AspNet WebApi中如何基于请求上下文将JSON反序列化为派生类?
解决方案推荐
下面是几种替代静态服务提供者的简洁方案,均基于ASP.NET Core原生依赖注入机制实现:
方案一:使用JsonConverterFactory结合依赖注入
JsonConverter本身不支持构造注入,但可以通过JsonConverterFactory间接注入服务。工厂类可依赖IHttpContextAccessor,在内部创建具体转换器并传递上下文信息。
代码实现
// 转换器工厂 public class RoleBasedConverterFactory : JsonConverterFactory { private readonly IHttpContextAccessor _httpContextAccessor; public RoleBasedConverterFactory(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override bool CanConvert(Type typeToConvert) { // 指定该工厂处理的目标模型类型 return typeToConvert == typeof(YourRequestModel); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { // 创建具体转换器并注入HttpContextAccessor return new RoleBasedRequestConverter(_httpContextAccessor); } } // 具体的角色依赖转换器 public class RoleBasedRequestConverter : JsonConverter<YourRequestModel> { private readonly IHttpContextAccessor _httpContextAccessor; public RoleBasedRequestConverter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override YourRequestModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 获取当前用户角色 var httpContext = _httpContextAccessor.HttpContext; bool isAdmin = httpContext?.User.IsInRole("Admin") ?? false; // 基础反序列化 var request = JsonSerializer.Deserialize<YourRequestModel>(ref reader, options); // 根据角色调整模型字段 if (!isAdmin) { request.RestrictedField = null; // 其他角色相关的处理逻辑 } return request; } public override void Write(Utf8JsonWriter writer, YourRequestModel value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, options); } }
注册配置
在Program.cs中注册服务和转换器:
// 注册HttpContextAccessor(ASP.NET Core默认未注册) builder.Services.AddHttpContextAccessor(); // 注册转换器工厂 builder.Services.AddScoped<RoleBasedConverterFactory>(); // 配置MVC的Json选项 builder.Services.AddControllers() .AddJsonOptions(options => { var factory = builder.Services.BuildServiceProvider().GetRequiredService<RoleBasedConverterFactory>(); options.JsonSerializerOptions.Converters.Add(factory); });
方案二:使用ActionFilter预处理模型
如果不需要在反序列化阶段处理,可在模型绑定完成后,通过ActionFilter获取用户角色并调整模型数据,实现更简单直观。
代码实现
public class RoleBasedModelFilter : IAsyncActionFilter { private readonly IHttpContextAccessor _httpContextAccessor; public RoleBasedModelFilter(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 获取当前用户角色 bool isAdmin = _httpContextAccessor.HttpContext?.User.IsInRole("Admin") ?? false; // 遍历Action参数,找到目标模型并修改 foreach (var kvp in context.ActionArguments) { if (kvp.Value is YourRequestModel request) { if (!isAdmin) { request.RestrictedField = null; // 其他角色限制逻辑 } } } await next(); } }
注册配置
builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped<RoleBasedModelFilter>(); builder.Services.AddControllers(options => { // 全局注册过滤器,或在特定Controller/Action上用[ServiceFilter(typeof(RoleBasedModelFilter))]标记 options.Filters.Add<RoleBasedModelFilter>(); });
方案对比
- 方案一:更贴合JsonConverter的职责,在反序列化阶段直接处理数据,适合需要严格控制反序列化结果的场景。
- 方案二:实现更简单,侵入性更低,适合只需要在模型绑定后做字段调整的场景。
内容的提问来源于stack exchange,提问作者Jacob Roberts
相关产品推荐
相关产品推荐

