![](/img/trans.png)
[英]WebApi: Creating custom BadRequest status outside of ApiController
[英]ApiController does not always return data in BadRequest
我正在使用 ASP.NET Core 2.2 ApiController 并且我有以下内容:
[ApiController]
public class PostController : Controller {
[HttpGet("posts")]
public async Task<IActionResult> Get() {
return BadRequest();
}
}
在这种情况下,我得到以下响应:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"traceId": "0HLMFSL0C7SKB:00000001"
}
但是如果我返回一些数据如下:
[ApiController]
public class PostController : Controller {
[HttpGet("posts")]
public async Task<IActionResult> Get() {
List<String> errors = new List<String> { "Code is invalid" };
return BadRequest(new { errors = errors });
}
}
我得到以下信息:
{
"errors": ["Code is invalid"]
}
为什么ApiController在没有返回内容的情况下会添加type、title、status和traceId?
我希望回复总是类似的:
{
"errors": ["Code is invalid"],
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"traceId": "0HLMFSL0C7SKB:00000001"
}
默认的ControllerBase.BadRequest()
响应内容是因为您已将[ApiController]
属性应用于您的控制器。 这是在线记录的:
当兼容版本为 2.2 或更高版本时,MVC 将错误结果(状态码为 400 或更高的结果)转换为带有
ProblemDetails
的结果。ProblemDetails
类型基于 RFC 7807 规范,用于在 HTTP 响应中提供机器可读的错误详细信息。
这包括type
、 title
、 status
和traceId
值。
如果您没有应用[ApiController]
那么ControllerBase.BadRequest()
将返回一个带有HTTP 400
状态代码的空响应。
接受value
或model
响应对象的ControllerBase.BadRequest
所有重载都将序列化并返回,而不是使用ApiController
默认响应。
您只需要返回ValidationProblem()
结果而不是返回BadRequest()
结果。 这将为您提供已填充当前 ModelState 错误的 ProblemDetails 对象响应。
对于ProblemDetails
,取决于ObjectResult
是否继承自IClientErrorActionResult
。
您可以按照以下步骤解决方法:
MyBadRequestObjectResult
public class MyBadRequestObjectResult : BadRequestObjectResult, IClientErrorActionResult { public MyBadRequestObjectResult() : base((object)null) { } public MyBadRequestObjectResult(object error) : base(error) { } }
自定义问题详细信息ProblemDetailsErrorFactory
public class ProblemDetailsErrorFactory: IClientErrorFactory { private static readonly string TraceIdentifierKey = "traceId"; private static readonly string ErrorsKey = "errors"; private readonly ApiBehaviorOptions _options; public ProblemDetailsErrorFactory(IOptions<ApiBehaviorOptions> options) { _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); } public IActionResult GetClientError(ActionContext actionContext, IClientErrorActionResult clientError) { var problemDetails = new ProblemDetails { Status = clientError.StatusCode, Type = "about:blank", }; if (clientError.StatusCode is int statusCode && _options.ClientErrorMapping.TryGetValue(statusCode, out var errorData)) { problemDetails.Title = errorData.Title; problemDetails.Type = errorData.Link; SetErrors(actionContext, problemDetails); SetTraceId(actionContext, problemDetails); } return new ObjectResult(problemDetails) { StatusCode = problemDetails.Status, ContentTypes = { "application/problem+json", "application/problem+xml", }, }; } internal static void SetErrors(ActionContext actionContext, ProblemDetails problemDetails) { if (actionContext is ResultExecutingContext resultExecutingContext) { if (resultExecutingContext.Result is BadRequestObjectResult result) { problemDetails.Extensions[ErrorsKey] = result.Value; } } //var errors = actionContext.HttpContext. } internal static void SetTraceId(ActionContext actionContext, ProblemDetails problemDetails) { var traceId = Activity.Current?.Id ?? actionContext.HttpContext.TraceIdentifier; problemDetails.Extensions[TraceIdentifierKey] = traceId; } }
注册问题详细信息ProblemDetailsErrorFactory
public void ConfigureServices(IServiceCollection services) { services.TryAddSingleton<IClientErrorFactory, ProblemDetailsErrorFactory>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
控制器动作
[ApiController] public class PostController : Controller { [HttpGet("posts")] public IActionResult Get() { return new MyBadRequestObjectResult(); } [HttpGet("posts1")] public IActionResult Get1() { List<String> errors = new List<String> { "Code is invalid" }; return new MyBadRequestObjectResult(errors); } }
它为我工作
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
});
尝试使用 JsonConvert 序列化您的错误请求。
return BadRequest(JsonConvert.Serialize(new List {“代码无效”}));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.