我正在开发一个将由我的客户使用的ASP.NET Core 2.0 API。我遇到的一个问题是,当我使用ModelState对请求有效负载进行输入验证时,消费者看到的结果错误消息在响应JSON中有一个[objectPrefix] .PropertyName。我们的API文档列出了属性名称而不是对象类,因此当使用者编写将JSON响应反序列化到其本地对象模型的代码时,前缀会产生问题。
我可以在Service.AddMvc的Startup.cs ConfigureServices方法中设置任何选项,或类似的东西,这将禁用此前缀吗?
如果重要的话,我在我的API,.NET Core 2.0.4和VS2016 v15.5.7中使用了Microsoft.AspNetCore.All(2.0.7)依赖项。
我正在使用System.ComponentModel.DataAnnotations lib中的Data Annotations并装饰我的创建DTO类属性,如下所示;
[Required]
[MaxLength(14)]
public string AccountNumber
{
get => _accountNumber;
set => _accountNumber = !string.IsNullOrWhiteSpace(value) ? value.Trim() : string.Empty;
}
当消费者未在请求有效负载中提供帐号时,返回的错误如下所示;
{
"[AccountDto].AccountNumber": [
"The AccountNumber field is required."
]
}
我想要做的是消除[AccountDto]。前缀,以便错误JSON然后看起来像这样;
{
"AccountNumber": [
"The AccountNumber field is required."
]
}
我发现了这个SO帖子,但它似乎引用了较旧的ASP.NET。
目前,我让我的客户端对json响应进行字符串替换,但我真的希望有更好的解决方案。
有什么想法吗?
更新5/16/18
似乎前缀的问题与我在* 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类中实现Validate方法时得到的那个。这似乎解决了我的具体问题。
答案 0 :(得分:1)
我正在使用Microsoft.AspNetCore.All
v2.0.8,Microsoft.NETCore.App
v2.0.7和Visual Studio
社区2017 v15.7.1,所有内容都符合您的要求。
我无法重现您的问题。我甚至认为我可能只是在Web项目中创建了模型,所以我甚至创建了一个单独的类项目来包含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();
}
}
}