Closed LiangZugeng closed 5 years ago
I did some research and found a solution (explicitly specify the response type for 400 status code on every action), however this solution requires the response type added to every action, is there a global configuration to fix this?
Solution:
[AllowAnonymous]
[HttpPost]
[Route("Login")]
[ProducesResponseType(200)]
// this is the fix, add "typeof(ValidationProblemDetails)"
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(401)]
public async Task<ActionResult<LoginResultDTO>> Login([FromBody] LoginModel loginVM)
@pranavkm @dougbu is this a known issue or expected behavior? Is there a way to change these conventions globally?
MVC assumes ProblemDetails
as the default response type for error status codes unless specified. For API controllers, returning any 4xx status code, including a 400, will return a ProblemDetails
instance which is a more general purpose type of ValidationProblemDetails
. Consider:
[ApiController]
[Route("[controller]/[action]")]
public class WeatherController
{
public ActionResult<WeatherResult> UpdateWeather([Required, StringLength(6, 6)] string zipCode /* This should produce a ValidationProblemDetails if validation fails */ )
{
if (!IsNotLocatedInNorthDakota(zipCode))
{
return BadRequest(); // This produces a vanilla ProblemDetails
}
}
}
Is there a way to change these conventions globally?
I'd recommend looking at conventions: https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/conventions?view=aspnetcore-2.2
@pranavkm I tried the default conventions of ASP.NET Core 2.2, they also produced ProblemDetails type, did you mean that I should write our own custom conventions for ValidationProblemDetails?
[HttpPost]
[ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.c))]
public async Task<ActionResult<AuditOfficeDTO>> Create([FromBody] AuditOfficeCreationModel aoCreationVM)
did you mean that I should write our own custom conventions for ValidationProblemDetails?
Yup. https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/conventions?view=aspnetcore-2.2#create-web-api-conventions has some guidance for this.
Maybe we should update the nswag wiki with some guidance regarding this?
@pranavkm already done writing the custom conventions. Thanks for the help.
The following is the API convention class in case you need some sample code for the nswag wiki.
namespace WebAPI.Infrastructure
{
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
/// <summary>
/// Custom API Conventions
/// </summary>
public static class CustomAPIConventions
{
/// <summary>
/// Find Action Convention
/// </summary>
/// <param name="parameters">The parameters of Find action</param>
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
#pragma warning disable CA1801 // Remove unused parameter
public static void Find(params object[] parameters)
#pragma warning restore CA1801 // Remove unused parameter
{
}
/// <summary>
/// GetById Action Convention
/// </summary>
/// <param name="id">Object Id</param>
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
[ProducesDefaultResponseType]
[ProducesResponseType(200)]
#pragma warning disable CA1801 // Remove unused parameter
public static void GetById([ApiConventionNameMatch(ApiConventionNameMatchBehavior.Suffix)] Guid id)
#pragma warning restore CA1801 // Remove unused parameter
{
}
/// <summary>
/// Create Action Convention
/// </summary>
/// <param name="model">The creation view model Create action</param>
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
#pragma warning disable CA1801 // Remove unused parameter
public static void Create([ApiConventionNameMatch(ApiConventionNameMatchBehavior.Any)][ApiConventionTypeMatch(ApiConventionTypeMatchBehavior.Any)] object model)
#pragma warning restore CA1801 // Remove unused parameter
{
}
/// <summary>
/// Update Action Convention
/// </summary>
/// <param name="id">Object Id</param>
/// <param name="patchDoc">JsonPatchDocument object containing all update and patch information</param>
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
[ProducesDefaultResponseType]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
#pragma warning disable CA1801 // Remove unused parameter
public static void Update([ApiConventionNameMatch(ApiConventionNameMatchBehavior.Suffix)][ApiConventionTypeMatch(ApiConventionTypeMatchBehavior.Any)] Guid id, [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Any)][ApiConventionTypeMatch(ApiConventionTypeMatchBehavior.Any)] object patchDoc)
#pragma warning restore CA1801 // Remove unused parameter
{
}
}
}
According to the Microsoft official doc, if the compatible version is set to 2.2 in Startup.cs and ApiController attribute is set on controllers, the default response type for HTTP 400 responses is ValidationProblemDetails.
However in my WebAPI project, NSwag produced ProblemDetails response type for 400 responses instead of producing ValidationProblemDetails.
I would like to be able to use ValidationProblemDetails, any idea what caused the issue and how it can be fixed? Thanks.
.NET Core SDK: v2.2.300 Windows 10 Professional: v1809 (Build 17763.615)
WebAPI.csproj
swagger.json
ConfigureServices and Configure methods in Startup.cs
Login Actions in Security controller