DTO 构造函数参数验证和 WebApi 响应

DTO constructor argument validation and WebApi response

如果我开发一个 WebApi 操作方法

[Route]
public string Put([FromBody]MyClass value)

使用在构造函数中进行参数验证的 MyClass class 真的是个坏主意吗:

public MyClass(string value)
{
    if (!_pattern.IsMatch(value))
            throw new ArgumentException($"Value should match RegEx: {_pattern}", nameof(value));
}

因此,在错误的请求中,它会抛出来自 JsonMediaTypeFormatter.ReadFromStreamAsync 的异常,该异常发生在控制器或操作过滤器之外,因此我还没有找到用 ArgumentException 消息中的真实问题描述来响应客户端的方法。

即使这样的参数检查也没有放在 DTO 中,这是正确的吗?DTO 是 WebApi 中唯一允许的,并且对于真正的(域模型)MyClass 应该创建相应的简单合同 class 而根本没有任何检查?

使用来自 API 的结构化消息创建一个 ErrorDto。有一个 ExceptionFilter 来处理这个是常见的做法。

关于验证反馈,您可能想看看 this article by Martin Fowler about avoiding to use exceptions as an approach to validation

话虽如此,您可能会发现 this library interesting

顺便说一句,我发现如果 Dto 从构造函数(在控制器之外)中抛出 ArgumentException,您仍然可以使用

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ModelState.IsValid == false)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

[Route]
[ValidateModel]
public string Put([FromBody]MyClass value)

那将以

回应客户
{
  "Message": "The request is invalid.",
  "ModelState": {
    "value": [
      "Value should match RegEx: ...\r\nParameter name: value"
    ]
  }
}

但是当带有 DataAnnotations 的纯 DTO 指定所有问题时,它仍然只允许通知第一个发现的问题。