能否为POST和PUT API请求配置自定义JsonSerializer处理接口类型参数
方案1:拆分请求DTO(零额外配置,最推荐)
直接为POST和PUT接口定义不同的请求类型,各自指定RequestData的具体实现类型,不需要改序列化配置,改动最小,无并发风险:
// 公共基类可保留原有逻辑 public class FooRequestBase : IRequest<Foo> { } // POST专用请求类 public class PostFooRequest : FooRequestBase { public FooRequestData RequestData { get; set; } } // PUT专用请求类 public class PutFooRequest : FooRequestBase { public FooOtherRequestData RequestData { get; set; } } // 控制器仅需修改参数类型即可 [ApiController] [Route("api/[controller]")] public class FooController { [HttpPost] public FooResponse Post(PostFooRequest request) { return FooService.Post(request); } [HttpPut] public FooResponse Put(PutFooRequest request) { return FooService.Put(request); } }
如果必须保留IRequestData接口属性定义,也可以给属性加[JsonConverter]特性指定对应实现类,不需要全局配置:
public class PostFooRequest : IRequest<Foo> { [JsonConverter(typeof(InterfaceToConcreteConverter<IRequestData, FooRequestData>))] public IRequestData RequestData { get; set; } } public class PutFooRequest : IRequest<Foo> { [JsonConverter(typeof(InterfaceToConcreteConverter<IRequestData, FooOtherRequestData>))] public IRequestData RequestData { get; set; } }
通用Converter实现(适配默认System.Text.Json序列化器):
public class InterfaceToConcreteConverter<TInterface, TConcrete> : JsonConverter<TInterface> where TConcrete : TInterface, new() { public override TInterface? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return JsonSerializer.Deserialize<TConcrete>(ref reader, options); } public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
方案2:不拆分DTO,用自定义模型绑定实现
如果不想改动现有DTO结构、保留统一的FooRequest参数,可以通过自定义模型绑定器针对不同接口指定反序列化规则,避免修改全局配置的并发风险:
- 先定义标记特性,指定对应接口要绑定的
IRequestData实现类
[AttributeUsage(AttributeTargets.Method)] public class RequestDataImplAttribute : Attribute { public Type ConcreteType { get; } public RequestDataImplAttribute(Type concreteType) => ConcreteType = concreteType; }
- 实现
FooRequest专属模型绑定器,根据接口标记动态选择实现类反序列化 - 在Program.cs中注册模型绑定器,给对应控制器方法加标记即可
[ApiController] [Route("api/[controller]")] public class FooController { [HttpPost] [RequestDataImpl(typeof(FooRequestData))] public FooResponse Post(FooRequest request) { return FooService.Post(request); } [HttpPut] [RequestDataImpl(typeof(FooOtherRequestData))] public FooResponse Put(FooRequest request) { return FooService.Put(request); } }
如果使用Newtonsoft.Json作为序列化器,逻辑和上述方案一致,仅需将Converter改为继承Newtonsoft.Json.JsonConverter即可。
内容的提问来源于stack exchange,提问作者KateMak
相关产品推荐
相关产品推荐

