【问题标题】:C# REST API - how to extend the model state error with an error codeC# REST API - 如何使用错误代码扩展模型状态错误
【发布时间】:2021-09-28 09:59:03
【问题描述】:

我正在创建一个 ASP.net Core Web API (.net 5) 来为单页应用程序 (SPA) 提供数据。我正在使用 DataAnnotations (System.ComponentModel.DataAnnotations) 在我的 Controller 中以非常标准的方式执行模型状态验证。我想确保我的错误响应以非常一致的方式返回(并且可以在前端进行翻译!)。

MVC 控制器

示例控制器如下:

[ApiController, Route("[controller]")]
public class AgencyController : Controller
{
    private readonly IOptions<ApiBehaviorOptions> _apiBehaviorOptions;

    public AgencyController(IOptions<ApiBehaviorOptions> apiBehaviorOptions)
    {
        _apiBehaviorOptions = apiBehaviorOptions;
    }

    [HttpPost]
    [ProducesResponseType(typeof(void), (int) HttpStatusCode.OK)]
    [ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.BadRequest)]
    public IActionResult Create([FromBody] ExampleCreateModel createModel)
    {
        // If the email already exists, add the custom error.
        var emailExists = EmailAlreadyExists(createModel.Email);
        if (emailExists)
        {
            ModelState.AddModelError("Email", "Email already exists");
            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
        }

        // Return some relevant status...
        return Ok();
    }

    // Real verification implementation would go here....
    private bool EmailAlreadyExists(string email) => true;
}

上面的示例代码演示了一个采用 POCO 模型的控制器(如下所示),如果它通过属性验证,则执行额外的内联验证以确保电子邮件地址不存在(电子邮件的伪代码存在检查)。

样本模型

public class ExampleCreateModel
{
    [Required] 
    public string Name { get; set; } = "";

    [Required]
    [EmailAddress(ErrorMessage = "Invalid email format")]
    public string Email { get; set; } = "";
}

错误响应格式

上面显示的模型的验证失败会产生来自 MVC 应用程序的标准错误对象,格式如下(示例):
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-6b30709ed71b7347afd41e0ed58e1ccb-e3ede2ff7591a24d-00",
  "errors": {
    "Email": [
      "Email already exists"
    ]
  }
}

这种格式对于上面代码中的常规属性验证和自定义内联验证都是一致的

我的问题

使用内置错误的优点是一致性(并遵循标准模式)。但对我来说,不利的一面是我想返回错误代码以及文本作为错误对象的一部分,所以 UI 可以翻译它们,但它似乎并不容易支持,即“电子邮件已经存在”错误可能是 3001 错误,UI 可能会以各种语言显示 3001。

是否有任何标准方法可以使用现有的 DataAnnotation 属性来包含附加信息?这样 POCO 模型就会变成这样:

public class ExampleCreateModel
{
    [Required(ErrorCode = 3000)] 
    public string Name { get; set; } = "";

    [Required]
    [EmailAddress(ErrorMessage = "Invalid email format", ErrorCode = 3001)]
    public string Email { get; set; } = "";
}

导致类似这样的错误对象:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-6b30709ed71b7347afd41e0ed58e1ccb-e3ede2ff7591a24d-00",
  "errors": {
    "Email": [
      { "message": "Email already exists", "errorCode": 3002 }
    ]
  }
}

为了清晰起见,我在这里的目的是让 UI 有机会轻松转换错误代码,同时使用开箱即用的错误响应实现错误一致性。

提前感谢您的任何指点!

【问题讨论】:

  • 在errorMessage中添加errorCode怎么样?如[EmailAddress(ErrorMessage = "[3002]Invalid email format")]
  • 我正在考虑这样做@YiyiYou,但希望有一种更优雅的方法:-)
  • 也许您应该从属性类中继承并根据需要覆盖方法。我没有测试,但听起来很合理。

标签: c# asp.net asp.net-core .net-5 modelstate


【解决方案1】:

是否有任何标准方法可以使用现有的 DataAnnotation 属性来包含附加信息?

没有。

【讨论】:

    【解决方案2】:

    我认为最简单(但相当 hacky)的方法可能是将错误代码包含在消息字符串本身中,然后在客户端提取它:

    public class ExampleCreateModel
    {
        // ...
        [Required]
        [EmailAddress(ErrorMessage = "ErrorCode:3001 - Invalid email format")]
        public string Email { get; set; } = "";
    }
    

    您甚至可以更进一步,将一个序列化的 JSON 对象放入其中以使其更有条理(但要注意转义)。当然,您应该将创建此类“自定义”错误消息的逻辑集中到某种静态实用程序类中,以使其在整个应用程序中保持一致。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-12
      • 2016-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-18
      • 2016-11-18
      相关资源
      最近更新 更多