为啥我们不再需要在更高版本的 ASP.NET Core 中手动验证模型?

Posted

技术标签:

【中文标题】为啥我们不再需要在更高版本的 ASP.NET Core 中手动验证模型?【英文标题】:Why do we no longer need to manually validate models in higher versions of ASP.NET Core?为什么我们不再需要在更高版本的 ASP.NET Core 中手动验证模型? 【发布时间】:2020-03-31 06:40:41 【问题描述】:

我的所有模型在到达端点之前都会自动验证,如果某种形式的验证失败,则会返回相应的错误。

我记得在 ASP.NET Core 2.2 中,我们需要手动调用 ModelState.IsValid 以确保对象已通过验证检查,但在最新的 ASP.NET Core 3.0 中,情况似乎并非如此,而且我在任何地方都没有明确地包含/配置任何服务以使这种行为存在。

有人能对此事有所了解,或许可以链接他们提到此更改的相关来源吗?

编辑:是因为[ApiController] 属性吗?见:https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-3.1#automatic-http-400-responses

谢谢!

【问题讨论】:

您是使用 MVC 还是仅使用 Web API 构建 Web 应用程序? @citronas 我正在使用services.AddControllersapp.UseRoutingapp.UseEndpoints 控制器实现Controller,而不是BaseController(他们也使用属性[ApiController] 【参考方案1】:

使用[ApiController]属性时,不需要在每个方法中检查ModelState.IsValid,因为会自动返回400状态码以及验证失败的字段名称,参见https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.1

您甚至可以修改 400 状态代码的外观。这篇博客文章应该可以帮助您入门:https://coderethinked.com/customizing-automatic-http-400-error-response-in-asp-net-core-web-apis/

添加这个依赖:

services.AddMvc.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.ConfigureApiBehaviorOptions(options =>

    options.InvalidModelStateResponseFactory = context =>
    
        var problems = new CustomBadRequest(context);
        return new BadRequestObjectResult(problems);
    ;
);

您的自定义错误请求类可能如下所示。如果您想包含有关错误的其他信息,例如错误严重性、警告等,请创建一个 YourErrorClass 类。

public class CustomBadRequest

    [JsonProperty("httpstatuscode")]
    public string HttpStatusCode  get; set; 

    [JsonProperty("errors")]
    public List<YourErrorClass> Errors  get; set;  = new List<YourErrorClass>();

    public CustomBadRequest(ActionContext context)
    
        this.HttpStatusCode = "400";
        this.Errors = new List<YourErrorClass>();
        this.ConstructErrorMessages(context);
    

    private void ConstructErrorMessages(ActionContext context)
    
        foreach (var keyModelStatePair in context.ModelState)
        
            var key = keyModelStatePair.Key;
            var errors = keyModelStatePair.Value.Errors;
            if (errors != null && errors.Count > 0)
            
                foreach (var error in errors)
                
                    Errors.Add(new YourErrorClass()
                    
                        ErrorMessage = error.ErrorMessage
                        // add additional information, if you like
                    );
                
            
        

【讨论】:

我添加了一些代码来自定义返回的错误类 这太有用了,谢谢!除了不检查模型是否有效之外,您也不需要检查对象是否为空,对吧?因为它自动要求其属性具有某种形式的价值? 也不应该是error而不是errors[0]吗?你从来没有使用过error,你只是在迭代元素? 是的,感谢您的关注。我在回答中简化了解决方案并犯了一个错误,现在我更正了;) 谢谢!!奇迹般有效!只是一个额外的问题..有没有办法显示错误。ErrorMessage 翻译成特定的语言?谢谢!【参考方案2】:

是的,这是因为 ApiController 属性。

但是,即使在 Core 2.2 中也会发生这种情况,但是有一个选项可以将兼容性设置为 2.0,但是从 3.0 起不再有效,这可能解释了您看到的行为。

要在 3.0 及更高版本中关闭它,您需要在执行 services.AddControllers()services.AddMvc() 时在选项中设置它,如下代码所示:

services.AddControllers().ConfigureApiBehaviorOptions(options =>

     options.SuppressModelStateInvalidFilter = true;

另请注意,核心 2.1 和更高版本之间存在差异,如 this MSDN article 中所述,如下例所示:

Core 2.1 示例响应:


   "": [
      "A non-empty request body is required."
   ]

Core 2.2 及更高版本示例响应:


  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|7fb5e16a-4c8f23bbfc974667.",
  "errors": 
    "": [
      "A non-empty request body is required."
    ]
  

要恢复 2.1 的行为,您可以将兼容性设置回 2.1,但这在 3.0 及更高版本后不再有效,而是在执行 services.AddControllers()services.AddMvc() 时需要在选项配置中添加以下代码在以下代码中:

services.AddControllers().ConfigureApiBehaviorOptions(options =>

    options.InvalidModelStateResponseFactory = context => 
         new BadRequestObjectResult(new SerializableError(context.ModelState));
);

【讨论】:

以上是关于为啥我们不再需要在更高版本的 ASP.NET Core 中手动验证模型?的主要内容,如果未能解决你的问题,请参考以下文章

我的导航栏显示了太多项目和溢出。如何在更高的屏幕宽度下折叠它? [复制]

Linq 查询在 ASP.NET-Core 3.0 及更高版本中对数字等字符串进行排序

React-Native .apk 文件在更高版本的 android 设备中失败

React Native 版本 .apk 在更高版本的 android 设备中崩溃,地理定位权限被拒绝错误

为啥我们需要避免在 ASP.NET MVC 视图中直接使用 IQueryable?

React Native Maps - 自定义标记图像未在更高的 Android 版本中呈现