如何删除 ASP.NET Core 2.0 中错误消息的 ModelState 前缀?

How can I remove the ModelState prefix on error messages in ASP.NET Core 2.0?

我正在开发 ASP.NET Core 2.0 API,我的客户将使用它。我 运行 遇到的问题之一是,当我使用 ModelState 对请求负载进行输入验证时,消费者看到的结果错误消息在响应 JSON。我们的 API 文档列出了 属性 名称,但没有列出对象 class,因此当消费者编写将 JSON 响应反序列化到其本地的代码时,前缀会产生问题对象模型。

我可以在 Startup.cs ConfigureServices 方法中为 Service.AddMvc 设置任何选项或类似的东西,以禁用此前缀吗?

我在 API、.NET Core 2.0.4 和 VS2016 v15.5.7 中使用 Microsoft.AspNetCore.All(2.0.7) 依赖项。

我正在使用 System.ComponentModel.DataAnnotations 库中的数据注释并装饰我创建的 DTO class 属性,如下所示;

    [Required]
    [MaxLength(14)]
    public string AccountNumber
    {
        get => _accountNumber;
        set => _accountNumber = !string.IsNullOrWhiteSpace(value) ? value.Trim() : string.Empty;
    }

当消费者没有在请求有效负载中提供帐号时,returns 的错误如下所示;

{
    "[AccountDto].AccountNumber": [
        "The AccountNumber field is required."
    ]
}

我想做的是消除[AccountDto]。前缀以便错误 JSON 看起来像这样;

{
    "AccountNumber": [
        "The AccountNumber field is required."
    ]
}

我找到了这个 SO post 但它似乎引用了旧的 ASP.NET.

目前,我正在让我的客户对 json 响应进行字符串替换,但我真的希望有更好的解决方案。

有什么想法吗?

2018 年 5 月 16 日更新

前缀的问题似乎与我在 *ForCreationDtos 中使用 Validate 方法有关。

例如,

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {

        if (CompanyId == 0)
        {
            yield return new ValidationResult("A Company ID is required.", new[] { "CompanyId" });
        }

    }

但是,我找到了一种解决方法,方法是使用全局 ModelState 处理程序并修改它以解析出前缀。

public class ValidateModelAttribute : ActionFilterAttribute
{

    /// <summary>
    /// Validates model state upon action execution
    /// </summary>
    /// <param name="context">ActionExecutingContext object</param>
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.ModelState.IsValid) return;
        var errorList = context.ModelState.Where(ms => ms.Value.Errors.Any()).ToDictionary(
            kvp => kvp.Key.Replace("[0].", ""),
            kvp => kvp.Value.Errors.Select(e => string.IsNullOrEmpty(e.ErrorMessage) ? e.Exception.Message : e.ErrorMessage).ToArray()
        );
        var globalErrorDto = new GlobalErrorDto { Errors = errorList };
        context.Result = new BadRequestObjectResult(globalErrorDto);
    }
}

这有点粗略,假设为“[0]”。作为前缀,但这是我在 DTO class 中实现 Validate 方法时得到的前缀。这似乎解决了我的具体问题。

我正在使用 Microsoft.AspNetCore.All v2.0.8、Microsoft.NETCore.App v2.0.7 和 Visual Studio Community 2017 v15.7.1,一切都如您所愿。

屏幕截图 #1:无帐号 - 400

屏幕截图 #2:帐号太长 - 400

屏幕截图 #3:有效帐号 - 201

我无法重现您的问题。我什至想也许我只是在 Web 项目中创建了模型,所以我什至创建了一个单独的 class 项目来包含 DTO。结果仍然如您所愿!

DTO

using System.ComponentModel.DataAnnotations;

namespace DL.SO.ModelState.Dto.Users
{
    public class AccountModel
    {
        [Required]
        [MaxLength(14)]
        [Display(Name = "account number")]
        public string AccountNumber { get; set; }
    }
}

控制器

using DL.SO.ModelState.Dto.Users;
using Microsoft.AspNetCore.Mvc;

namespace DL.SO.ModelState.Controllers
{
    [Route("api/[controller]")]
    public class UsersController : ControllerBase
    {
        [HttpGet("{id}")]
        public IActionResult GetById(string id)
        {
            // Just testing 
            return Ok(id);
        }

        [HttpPost]
        public IActionResult Post(AccountModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // Just testing so I pass in null
            return CreatedAtAction(nameof(GetById), 
                 new { id = model.AccountNumber }, null);
        }
    }
}

启动

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace DL.SO.ModelState
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}