REST API如何复用同一数据类实现POST/PATCH避免代码重复
单类复用避免代码重复的实现方案
这是.NET Web API开发中DTO设计的典型场景:内置数据注解校验和模型类绑定,无法直接根据请求方法动态开关,以下是几种生产环境验证过的低冗余实现方式:
方案1:继承抽离公共字段,仅差异化配置校验规则
这是改动最小、最容易落地的方案,公共字段只需要在基类写一次,不会出现重复定义字段的冗余:
/// <summary> /// 操作DTO基类,统一维护所有公共字段,不标注校验特性 /// </summary> public abstract class PersonOperationBase { public string Name { get; set; } public string LastName { get; set; } } /// <summary> /// POST创建场景专用,仅补充必填校验特性,无需重复定义字段 /// </summary> public class CreatePersonRequest : PersonOperationBase { [Required] public new string Name { get => base.Name; set => base.Name = value; } [Required] public new string LastName { get => base.LastName; set => base.LastName = value; } } /// <summary> /// PATCH更新场景专用,直接继承基类即可,无额外代码 /// </summary> public class UpdatePersonRequest : PersonOperationBase { }
后续新增、修改字段只需要改基类,不需要同步维护两个类的字段定义,从根源上避免字段不同步、重复写代码的问题。
方案2:单DTO+分场景校验,真正实现类复用
如果完全不想额外建子类,可以把校验逻辑从数据注解层剥离,根据请求场景动态执行不同校验规则,全程只需要一个DTO类:
- 首先开启项目的可空引用类型配置,把DTO字段定义为可空,避开内置Required特性的强制校验:
public class PersonRequest { public string? Name { get; set; } public string? LastName { get; set; } }
- 用FluentValidation按场景写校验规则,不需要在模型类上加任何特性:
// POST创建场景校验:要求所有字段非空 public class CreatePersonValidator : AbstractValidator<PersonRequest> { public CreatePersonValidator() { RuleFor(x => x.Name).NotEmpty().WithMessage("姓名不能为空"); RuleFor(x => x.LastName).NotEmpty().WithMessage("姓氏不能为空"); } } // PATCH更新场景校验:仅当字段传入时校验格式,不强制非空 public class UpdatePersonValidator : AbstractValidator<PersonRequest> { public UpdatePersonValidator() { RuleFor(x => x.Name).NotEmpty().When(x => x.Name != null); RuleFor(x => x.LastName).NotEmpty().When(x => x.LastName != null); } }
接口上根据请求类型指定对应的校验器即可,全程只有一个PersonRequest类维护字段,完全没有代码重复。
如果不想引入第三方校验库,也可以自定义全局校验过滤器:自定义一个[RequiredOnCreate]特性标记需要在POST场景必填的字段,过滤器里判断当前请求方法如果是POST,就执行非空校验;如果是PATCH就跳过非空校验,只校验传入字段的合法性。
额外建议
如果是标准的PATCH部分更新场景,更推荐直接用ASP.NET Core内置的JsonPatchDocument<PersonRequest>类型作为接口参数,本身就是为部分更新设计的,天然支持只传入需要修改的字段,配合上面的分场景校验逻辑,代码冗余可以降到最低。
内容的提问来源于stack exchange,提问作者user18154574
相关产品推荐
相关产品推荐

