You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:35:34