自定义ASP.NET ControllerBase序列化行为 仅序列化接口声明属性
问题原因
ASP.NET Core 默认的 System.Text.Json 序列化器会基于对象的运行时实际类型探查可序列化属性,不会受 Action 声明的返回值接口类型约束,所以 DBProject 类型的所有公开属性都会被序列化输出,而非仅保留 IProject 接口定义的字段。
以下方案均满足「无需提前做对象拷贝转换、无需给实体属性加序列化忽略特性」的要求:
方案1:.NET 7+ 全局配置序列化类型过滤(推荐)
通过修改默认 JSON 序列化的类型信息解析器,全局指定所有 IProject 类型的序列化仅保留接口定义的属性,无需修改业务代码。
在 Program.cs 中添加如下配置:
builder.Services.AddControllers() .AddJsonOptions(opt => { opt.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { // 仅处理IProject类型的序列化规则 if (typeInfo.Type != typeof(IProject)) return; // 保留IProject接口声明的所有属性 var allowedProperties = typeof(IProject) .GetProperties() .Select(p => p.Name) .ToHashSet(); // 移除所有接口未定义的属性 typeInfo.Properties.RemoveAll(p => !allowedProperties.Contains(p.Name)); } } }; });
配置完成后所有返回 IProject/IEnumerable<IProject> 的接口都会自动按接口定义输出字段,同时兼容 MockProject 和 DBProject 两种实现。
方案2:兼容所有.NET版本 自定义JsonConverter
如果你的项目是 .NET 6 及更早版本,可以通过自定义 IProject 专属的 JSON 转换器实现需求:
- 首先实现转换器类:
public class IProjectJsonConverter : JsonConverter<IProject> { public override IProject? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 不需要反序列化可直接抛出异常 throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, IProject value, JsonSerializerOptions options) { writer.WriteStartObject(); // 仅序列化IProject定义的属性,后续新增接口字段在此处补充即可 writer.WriteString(nameof(IProject.Title), value.Title); writer.WriteEndObject(); } }
- 在 Program.cs 中注册转换器:
builder.Services.AddControllers() .AddJsonOptions(opt => { opt.JsonSerializerOptions.Converters.Add(new IProjectJsonConverter()); });
单Action临时适配方案
如果你只需要当前 GetProjects 接口做字段过滤,不需要全局生效,可以直接在Action中指定序列化规则,无需修改全局配置:
[HttpGet] public ActionResult GetProjects() { IEnumerable<IProject> projects = ...;// 原有获取数据逻辑不变 return Json(projects, new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ti => { if (ti.Type == typeof(IProject)) { var allowedProps = typeof(IProject).GetProperties().Select(p => p.Name).ToHashSet(); ti.Properties.RemoveAll(p => !allowedProps.Contains(p.Name)); } } } } }); }
内容的提问来源于stack exchange,提问作者Denise Skidmore
相关产品推荐
相关产品推荐

