繁体   English   中英

ApiController 并不总是在 BadRequest 中返回数据

[英]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 响应中提供机器可读的错误详细信息。

这包括typetitlestatustraceId值。

如果您没有应用[ApiController]那么ControllerBase.BadRequest()将返回一个带有HTTP 400状态代码的空响应。

接受valuemodel响应对象的ControllerBase.BadRequest所有重载都将序列化并返回,而不是使用ApiController默认响应。

您只需要返回ValidationProblem()结果而不是返回BadRequest()结果。 这将为您提供已填充当前 ModelState 错误的 ProblemDetails 对象响应。

对于ProblemDetails ,取决于ObjectResult是否继承自IClientErrorActionResult

您可以按照以下步骤解决方法:

  1. MyBadRequestObjectResult

     public class MyBadRequestObjectResult : BadRequestObjectResult, IClientErrorActionResult { public MyBadRequestObjectResult() : base((object)null) { } public MyBadRequestObjectResult(object error) : base(error) { } }
  2. 自定义问题详细信息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; } }
  3. 注册问题详细信息ProblemDetailsErrorFactory

     public void ConfigureServices(IServiceCollection services) { services.TryAddSingleton<IClientErrorFactory, ProblemDetailsErrorFactory>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
  4. 控制器动作

    [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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM