我正在使用 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"
}
无需返回
BadRequest()
结果,您只需返回 ValidationProblem()
结果即可。这将为您提供包含当前 ModelState 错误的 ProblemDetails 对象响应。
默认
ControllerBase.BadRequest()
响应内容是因为您已将[ApiController]
属性应用于您的控制器。这是在线记录:
当兼容版本为2.2或更高版本时,MVC将错误结果(状态码为400或更高的结果)转换为带有
的结果。ProblemDetails
类型基于 RFC 7807 规范,用于在 HTTP 响应中提供机器可读的错误详细信息。ProblemDetails
这包括
type
、title
、status
和 traceId
值。
如果您没有应用
[ApiController]
,那么ControllerBase.BadRequest()
将返回带有HTTP 400
状态代码的空响应。
所有接受
ControllerBase.BadRequest
或value
响应对象的model
重载将序列化并返回,而不是使用ApiController
默认响应。
对于
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;
});
不想用的人
ValidationProblem()
.
例子:
public IActionResult Post()
{
// ...
return Problem("msg", statusCode: (int)HttpStatusCode.BadRequest);
}
哪些输出
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "msg",
"traceId": "xxxxx"
}
尝试使用 JsonConvert 序列化您的错误请求。
return BadRequest(JsonConvert.Serialize(new List { “Code is invalid” }));