如何实现可根据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
相关产品推荐
相关产品推荐

