C# REST API - 如何使用错误代码扩展模型状态错误 MVC 控制器示例模型错误响应格式我的问题

问题描述

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

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","errors": {
    "Email": [
      { "message": "Email already exists","errorCode": 3002 }
    ]
  }
}

再次声明 - 我的目标是让 UI 有机会轻松翻译错误代码,同时使用开箱即用的错误响应实现错误一致性。

提前感谢您的指点!

解决方法

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

没有

,

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

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

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