[英]ASP.Net Core Validation Problem State - Binding validation not returning problem details
Same question posted here: https://github.com/aspnet/Mvc/issues/8564 同样的问题发布在这里: https : //github.com/aspnet/Mvc/issues/8564
I have an issue where when execution hits the controller and my code explicitly returns the ValidationProblemDetails response. 我有一个问题,当执行命中控制器时,我的代码显式返回ValidationProblemDetails响应。
However, when binding validation prevents execution getting to the controller, I get the following JSON response (standard model state validation object). 但是,当绑定验证阻止执行到达控制器时,我得到以下JSON响应(标准模型状态验证对象)。
{
"Email": [
"Invalid email address"
]
}
Why doesn't it return the validation problem details in the response? 为什么不在响应中返回验证问题详细信息?
I'm using the Microsoft.AspNetCore.App
2.1.4 package. 我正在使用Microsoft.AspNetCore.App
2.1.4包。
Request Model 请求模型
public class RegistrationRequest
{
[Description("Given Name")]
[MaxLength(100)]
[Required(ErrorMessage = "Given Name is required")]
public string GivenName { get; set; }
[MaxLength(100)]
[Required(ErrorMessage = "Surname is required")]
public string Surname { get; set; }
[MaxLength(255)]
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public string Email { get; set; }
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; }
[Description("Confirm Password")]
[Compare(nameof(Password), ErrorMessage = "Passwords do not match")]
public string ConfirmPassword { get; set; }
}
Startup 启动
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var problemDetails = new ValidationProblemDetails(context.ModelState)
{
Instance = context.HttpContext.Request.Path,
Status = (int)HttpStatusCode.BadRequest,
Detail = "Please refer to the errors property for additional details"
};
return new BadRequestObjectResult(problemDetails)
{
ContentTypes = "applicaton/json"
};
};
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
...
}
}
Controller 调节器
[ApiController]
[Authorize]
[Route("users")]
public sealed class UserController : Controller
{
public UserController(
UserManager userManager,
IMapper mappingProvider)
{
Manager = userManager;
Mapper = mappingProvider;
}
private UserManager Manager { get; }
private IMapper Mapper { get; }
[HttpPost]
[AllowAnonymous]
[Consumes("application/json")]
[Produces("application/json")]
[ProducesResponseType(200)]
[ProducesResponseType(400, Type = typeof(ValidationProblemDetails))]
public async Task<IActionResult> Post([FromBody]ApiModels.RegistrationRequest request)
{
if (request == null) throw new ArgumentNullException(nameof(request));
var user = Mapper.Map<DataModels.User>(request);
var result = await Manager.Create(user, request.Password); // return OperationResult
return result.ToActionResult();
}
}
Extension methods to convert OperationResult to IActionResult 将OperationResult转换为IActionResult的扩展方法
public static class OperationResultExtensions
{
public static ValidationProblemDetails ToProblemDetails(this OperationResult result)
{
if (result == null) throw new ArgumentNullException(nameof(result));
var problemDetails = new ValidationProblemDetails()
{
Status = (int)HttpStatusCode.BadRequest
};
if (problemDetails.Errors != null)
{
result.Errors
.ToList()
.ForEach(i => problemDetails.Errors.Add(i.Key, i.Value.ToArray()));
}
return problemDetails;
}
public static IActionResult ToActionResult(this OperationResult result)
{
switch (result.Status)
{
case HttpStatusCode.OK:
return new OkResult();
case HttpStatusCode.NotFound:
return new NotFoundResult();
case HttpStatusCode.BadRequest:
var problems = result.ToProblemDetails();
return new BadRequestObjectResult(problems);
default:
return new StatusCodeResult((int)result.Status);
}
}
}
You have Configure<ApiBehaviorOptions>
before AddMvc
: The call to AddMvc
registers a class that implements IConfigureOptions<ApiBehaviorOptions>
, which ends up overwriting the instance you've configured using services.Configure<ApiBehaviorOptions>
and effectively resets the factory function . 你必须Configure<ApiBehaviorOptions>
前 AddMvc
:将呼叫AddMvc
注册一个类实现IConfigureOptions<ApiBehaviorOptions>
这最终覆盖您已经使用配置实例services.Configure<ApiBehaviorOptions>
和有效复位工厂函数 。
All you need to do in order to get this working is switch the order in ConfigureServices
: 要使其正常工作,您需要做的就是在ConfigureServices
切换顺序:
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
...
};
});
I've also noticed that although it's not exactly bold , the docs suggests that this ordering is important too: 我也注意到虽然它不完全是粗体 ,但是文档表明这种排序也很重要:
Add the following code in Startup.ConfigureServices after services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 在services.AddMvc()之后的Startup.ConfigureServices中添加以下代码.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<ApiBehaviorOptions>(options => ... );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.