ControllerBase
包含诸如Conflict()
之类的方法,这些方法返回从StatusCodeResult
派生的ConflictResult
对象(表示HTTP 409响应(。 生成的响应正文具有内容类型 application/problem+json
,如下所示:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"traceId": "0HLO99QHFC9QI:00000001"
}
HTTP 410 响应没有内置的方法/类,所以我做了一个:
[DefaultStatusCode(410)]
public class GoneResult : StatusCodeResult
{
public GoneResult() : base(410)
{}
}
...
public static class ControllerBaseExtensions
{
public static GoneResult Gone(this ControllerBase controllerBase) // this doesn't give all the problem+JSON attributes
{
return new GoneResult();
}
}
但是,这给了
{
"type": "about:blank",
"status": 410
}
即,type
值不同,缺少title
和traceId
字段。
我还想为 HTTP 500 响应创建一个自定义类,其中包含一个带有错误消息的message
字段。 我尝试返回 StatusCode(StatusCodes.Status500InternalServerError)
,这给了我与Gone()
方法相同的最小application/problem+json
响应;我也尝试返回StatusCode(StatusCodes.Status500InternalServerError, message)
,这给了我错误消息,但将响应格式化为 text/plain
。
生成ProblemDetails
响应的代码不知道410
状态代码,因此在生成响应对象时,它没有关联的Link
和Title
属性。要添加此感知,请在 ConfigureServices
中配置ApiBehaviorOptions
,如下所示:
services.Configure<ApiBehaviorOptions>(options =>
{
options.ClientErrorMapping[410] = new ClientErrorData
{
Title = "Gone",
Link = "https://tools.ietf.org/html/rfc7231#section-6.5.9"
};
});
ClientErrorMapping
是int
(状态代码(到 ClientErrorData
的字典。请注意,我用于上述Link
的值确实指向 RFC 的正确部分。
简单地说,你必须实际返回一个ProblemDetails
响应体。我必须深入研究代码才能确定,但我认为 ASP.NET Core 通过中间件执行此操作只是为了特定结果。他们说的是 4xx 范围内的任何内容,但我认为这实际上仅限于返回该范围内状态代码的内置结果类型,而不是任何带有 4xx 状态代码的结果。同样,这是猜想,因为我还没有确切地看到他们在做什么,尽管它不是作为实际结果类的一部分发生的。
出于您的目的,有几种不同的方法可以处理此问题。您可以编写自己的中间件来捕获出站响应并重写它们。可以使用自定义异常处理程序。您可以简单地从ObjectResult
继承,然后自己创建一个ProblemDetails
实例并将其放入基实例中。您甚至可以直接从操作中返回ProblemDetails
(尽管这显然是最不理想的方法(。