您是否应该为参数创建一个 DTO,为正文创建一个 DTO,为查询创建一个,...?
Should you create one DTO for the params, one for the body, one for the queries, ...?
所以我们假设您有一个 API 端点需要
- 1 到 n 个参数
- 1 到 n 体值
- 1 到 n 个查询
您想创建一个 DTO 来获取和验证所有这些值。正如您可能知道的那样,不可能有一个 DTO class 来处理整个请求,所以这是行不通的:
public class Dto
{
[FromRoute]
public int Id { get; set; }
[FromBody]
public int Foo { get; set; }
}
解析器只会设置Foo
字段而忽略Id
字段。当调用 https://localhost:5001/foo/1 时,Id
字段将只有默认值 0,而不是 1。可以为 url 参数创建一个 DTO,一个用于正文,一个用于查询像这样
public class ParamsDto
{
public int FirstId { get; set; }
public int SecondId { get; set; }
}
// ... same for the body and queries ...
然后你可以像这样标记那些 dtos [FromRoute] ParamsDto paramsDto, [FromBody] BodyDto bodyDto, [FromQuery] QueryDto queryDto
。您可能有一个多层架构,并且您的 Web API 项目与一个需要 DTO 的层进行通信,该 DTO 是上面显示的所有 3 个 DTO 的组合。所以你必须将这 3 个对象合并到一个大的 DTO,例如使用 AutoMapper..
将请求 DTO 转换为命令对象(来自 Mediatr)
在文件夹结构、命名约定等方面是否有任何处理多个 DTO 的最佳实践......?因为你可能必须为参数 UpdateProductAmountFromOrderByIdsParamsDto
和正文 UpdateProductAmountFromOrderByIdsBodyDto
。我知道这不是最好的例子,因为这里并不真正需要 DTO,但我们假设您将对 ID 进行复杂的验证,并且正文包含多个值。您不希望在控制器文件中有那么多验证注释。就将这些单独的 DTO 合并为一个大的而言,这种方法对我来说真的很混乱,所以也许有更好的方法。
这是 asp.net 核心 3.0 的工作演示:
型号:
public class Dto
{
[FromRoute(Name = "")]
public Test Test { get; set; }
[FromBody]
public Sample Sample { get; set; }
public ApiVersion ApiVersion { get; set; }
}
public class Test
{
public string Col1 { get; set; }
public int Col2 { get; set; }
public bool Col3 { get; set; }
}
public class ApiVersion
{
public int VersionId { get; set; }
public string VersionName { get; set; }
}
public class Sample
{
public int Foo { get; set; }
public string Name { get; set; }
}
控制器:
[ApiController]
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/<controller>
[HttpGet("col1/{col1}/col2/{col2}/col3/{col3}")]
public async Task<IActionResult> Get([FromQuery]Dto dto)
{
return Ok(dto);
}
}
请求url:https://localhost:44393/api/values/col1/1/col2/2/col3/true?apiversion.versionId=1&apiversion.versionName=aaa
结果:
更新:
public class Dto
{
//[FromRoute(Name = "")]
//public Test Test { get; set; }
[FromRoute]
public string Col1 { get; set; }
[FromRoute]
public int Col2 { get; set; }
[FromRoute]
public bool Col3 { get; set; }
[FromBody]
public Sample Sample { get; set; }
public ApiVersion ApiVersion { get; set; }
}
所以我们假设您有一个 API 端点需要
- 1 到 n 个参数
- 1 到 n 体值
- 1 到 n 个查询
您想创建一个 DTO 来获取和验证所有这些值。正如您可能知道的那样,不可能有一个 DTO class 来处理整个请求,所以这是行不通的:
public class Dto
{
[FromRoute]
public int Id { get; set; }
[FromBody]
public int Foo { get; set; }
}
解析器只会设置Foo
字段而忽略Id
字段。当调用 https://localhost:5001/foo/1 时,Id
字段将只有默认值 0,而不是 1。可以为 url 参数创建一个 DTO,一个用于正文,一个用于查询像这样
public class ParamsDto
{
public int FirstId { get; set; }
public int SecondId { get; set; }
}
// ... same for the body and queries ...
然后你可以像这样标记那些 dtos [FromRoute] ParamsDto paramsDto, [FromBody] BodyDto bodyDto, [FromQuery] QueryDto queryDto
。您可能有一个多层架构,并且您的 Web API 项目与一个需要 DTO 的层进行通信,该 DTO 是上面显示的所有 3 个 DTO 的组合。所以你必须将这 3 个对象合并到一个大的 DTO,例如使用 AutoMapper..
在文件夹结构、命名约定等方面是否有任何处理多个 DTO 的最佳实践......?因为你可能必须为参数 UpdateProductAmountFromOrderByIdsParamsDto
和正文 UpdateProductAmountFromOrderByIdsBodyDto
。我知道这不是最好的例子,因为这里并不真正需要 DTO,但我们假设您将对 ID 进行复杂的验证,并且正文包含多个值。您不希望在控制器文件中有那么多验证注释。就将这些单独的 DTO 合并为一个大的而言,这种方法对我来说真的很混乱,所以也许有更好的方法。
这是 asp.net 核心 3.0 的工作演示:
型号:
public class Dto
{
[FromRoute(Name = "")]
public Test Test { get; set; }
[FromBody]
public Sample Sample { get; set; }
public ApiVersion ApiVersion { get; set; }
}
public class Test
{
public string Col1 { get; set; }
public int Col2 { get; set; }
public bool Col3 { get; set; }
}
public class ApiVersion
{
public int VersionId { get; set; }
public string VersionName { get; set; }
}
public class Sample
{
public int Foo { get; set; }
public string Name { get; set; }
}
控制器:
[ApiController]
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/<controller>
[HttpGet("col1/{col1}/col2/{col2}/col3/{col3}")]
public async Task<IActionResult> Get([FromQuery]Dto dto)
{
return Ok(dto);
}
}
请求url:https://localhost:44393/api/values/col1/1/col2/2/col3/true?apiversion.versionId=1&apiversion.versionName=aaa
结果:
更新:
public class Dto
{
//[FromRoute(Name = "")]
//public Test Test { get; set; }
[FromRoute]
public string Col1 { get; set; }
[FromRoute]
public int Col2 { get; set; }
[FromRoute]
public bool Col3 { get; set; }
[FromBody]
public Sample Sample { get; set; }
public ApiVersion ApiVersion { get; set; }
}