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

如何实现可根据HTTP头条件隐藏属性的自定义Json Converter

.NET自定义JSON序列化:根据HTTP头动态排除属性

要实现你需求的「根据HTTP头动态排除指定属性」功能,单纯用JsonConverter没法直接跳过属性序列化,更合适的方案是结合自定义特性和契约解析器(ContractResolver),同时通过IHttpContextAccessor获取当前请求的头信息。下面是完整的实现步骤:

1. 定义自定义排除特性

先写一个特性,用来标记哪些属性需要根据HTTP头来决定是否排除,支持指定头名称和匹配值(可选):

[AttributeUsage(AttributeTargets.Property)]
public class ExcludeWhenHeaderPresentAttribute : Attribute
{
    public string HeaderName { get; }
    public string HeaderValue { get; }

    // 两种用法:
    // 1. 只传头名:只要请求中存在该头,就排除属性
    // 2. 传头名+值:只有头存在且值匹配时,才排除属性
    public ExcludeWhenHeaderPresentAttribute(string headerName, string headerValue = null)
    {
        HeaderName = headerName;
        HeaderValue = headerValue;
    }
}

2. 实现自定义契约解析器

这个解析器会遍历DTO的属性,检查是否带有上面的特性,再根据当前请求的HTTP头决定是否跳过该属性的序列化:

public class HeaderBasedContractResolver : DefaultContractResolver
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HeaderBasedContractResolver(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        // 检查当前属性是否有排除特性
        var excludeAttr = member.GetCustomAttribute<ExcludeWhenHeaderPresentAttribute>();
        if (excludeAttr != null && _httpContextAccessor.HttpContext != null)
        {
            var request = _httpContextAccessor.HttpContext.Request;
            // 检查请求中是否存在指定的头
            if (request.Headers.TryGetValue(excludeAttr.HeaderName, out var headerValues))
            {
                bool shouldExclude = string.IsNullOrEmpty(excludeAttr.HeaderValue) 
                    // 没指定头值:只要头存在就排除
                    || headerValues.Contains(excludeAttr.HeaderValue, StringComparison.OrdinalIgnoreCase);
                    // 指定了头值:需要匹配才排除

                if (shouldExclude)
                {
                    // 标记该属性不参与序列化
                    property.ShouldSerialize = _ => false;
                }
            }
        }

        return property;
    }
}

3. 注册服务(.NET 6+)

在Program.cs里注册IHttpContextAccessor和自定义的契约解析器,让JSON序列化时使用它:

var builder = WebApplication.CreateBuilder(args);

// 注册HttpContext访问器,用来获取当前请求信息
builder.Services.AddHttpContextAccessor();

// 把自定义解析器注册为单例
builder.Services.AddSingleton<HeaderBasedContractResolver>();

// 配置JSON序列化选项
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        var serviceProvider = builder.Services.BuildServiceProvider();
        // 注入自定义解析器
        options.JsonSerializerOptions.ContractResolver = serviceProvider.GetRequiredService<HeaderBasedContractResolver>();
        // 可选:处理循环引用等其他配置
        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    });

var app = builder.Build();

// 中间件配置(路由、授权等)...

app.Run();

4. 在DTO中标记需要排除的属性

给Age属性加上自定义特性,指定触发排除的HTTP头:

public class MyDto
{
    public string Name { get; set; }

    // 示例:只要请求头包含"Exclude-Age",就排除该属性
    [ExcludeWhenHeaderPresent("Exclude-Age")]
    // 如果需要匹配特定值,比如头值为"true"时才排除:
    // [ExcludeWhenHeaderPresent("Exclude-Age", "true")]
    public int Age { get; set; }

    public string ContactNumber { get; set; }
}

5. 测试效果

当你发送请求时带上指定的HTTP头,响应里就会自动排除Age字段:

比如用curl请求:

curl -H "Exclude-Age: true" https://your-api-url/api/your-endpoint

响应结果:

{
  "Name": "张三",
  "ContactNumber": "1234567"
}

补充说明

为什么不用你最初想的JsonConverter?因为JsonConverter的职责是处理单个属性的值转换逻辑(比如把int转成字符串),而不是决定是否包含整个属性。用契约解析器(ContractResolver)更契合「动态排除属性」的场景,也更灵活——可以给多个属性加特性,统一处理。

内容的提问来源于stack exchange,提问作者Ash

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 20:46:08