.NET Core API设计:DTO该选用record还是ValueObject?
.NET Core API中DTO:Record 与 ValueObject 的选择
核心判断标准
选 Record 的场景
- 纯数据传输需求:比如API的请求/响应DTO,这类对象只负责在不同层级(前端、API层、服务层)之间传递数据,不需要承载业务逻辑,像你示例里的
LoginRequest和AuthenticationResponse就属于这类。 - 想要默认的基于值的相等性:Record会自动根据所有属性的值判断对象是否相等,对比两个数据传输对象内容是否一致时很省心。
- 快速构建不可变数据对象:用 positional record 可以一行定义所有属性,自动生成构造函数、
ToString、Equals等方法,省去大量样板代码。
选 ValueObject 的场景
- 对象带有业务语义和行为:比如代表金额的
Money(包含数值+币种,还要实现加减、币种转换等方法)、代表地址的Address,这类对象是业务概念的封装,不是单纯的数据容器。 - 需要内置业务规则验证:比如
Email对象要在创建时就校验格式合法性,PhoneNumber要验证号码规则,这些逻辑应该内聚在对象内部,而不是在外部零散校验。 - 无标识的业务概念:ValueObject没有唯一ID,两个属性完全相同的对象在业务上视为同一个,比如两个地址完全一致的
Address,不需要区分它们的身份。
你的示例场景分析
你给出的LoginRequest和AuthenticationResponse是典型的API数据传输场景,用Record完全适配需求:
LoginRequest 定义
public record LoginRequest ( string Email, string Password );
AuthenticationResponse 定义
public record AuthenticationResponse ( Guid Id, string FirstName, string LastName, string Email, string Token );
控制器使用示例
[HttpPost("login")] public IActionResult Login(LoginRequest request) { var authResult = _authenticationService.Login(request.Email, request.Password); //返回数据类 var response = new AuthenticationResponse( authResult.Id, authResult.FirstName, authResult.LastName, authResult.Email, authResult.Token ); return Ok(response); }
这两个Record满足了不可变性(positional record的属性默认是init-only)、值相等性、代码简洁的要求,完全适配纯数据传输的场景。
总结
- 纯数据传输的DTO(请求/响应对象)优先用Record,省心省力还符合场景需求。
- 带有业务逻辑、语义的不可变对象,优先用ValueObject,它是业务领域概念的封装,更贴合DDD设计思想。
内容的提问来源于stack exchange,提问作者Jivopis
相关产品推荐
相关产品推荐

