关于c#:. NET Core Web API:返回带有内容类型应用程序/问题json的自定义HTTP状态代码

.NET Core Web API: return a custom HTTP status code with Content Type application/problem+json

ControllerBase包含诸如Conflict()之类的方法,这些方法返回从StatusCodeResult派生的ConflictResult对象(代表HTTP 409响应)。结果响应主体的内容类型为application/problem+json,如下所示:

1
2
3
4
5
6
{
   "type":"https://tools.ietf.org/html/rfc7231#section-6.5.8",
   "title":"Conflict",
   "status": 409,
   "traceId":"0HLO99QHFC9QI:00000001"
}

HTTP 410响应没有内置的方法/类,所以我做了一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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();
    }
}

但是,这给出了

1
2
3
4
{
   "type":"about:blank",
   "status": 410
}

type值不同,并且titletraceId字段丢失。

我还想为HTTP 500响应创建一个自定义类,该类包括带有错误消息的message字段。我尝试返回StatusCode(StatusCodes.Status500InternalServerError),这给了我与Gone()方法相同的最小application/problem+json响应。我也尝试过返回StatusCode(StatusCodes.Status500InternalServerError, message),这会给我我的错误消息,但是将响应的格式设置为text/plain


生成ProblemDetails响应的代码不知道410状态代码,因此在构建响应对象时没有关联的LinkTitle属性。要添加此意识,请在ConfigureServices中配置ApiBehaviorOptions,如下所示:

1
2
3
4
5
6
7
8
services.Configure<ApiBehaviorOptions>(options =>
{
    options.ClientErrorMapping[410] = new ClientErrorData
    {
        Title ="Gone",
        Link ="https://tools.ietf.org/html/rfc7231#section-6.5.9"
    };
});

ClientErrorMappingint(状态代码)到ClientErrorData的字典。请注意,我上面用于Link的值确实指向RFC的正确部分。


简单来说,您实际上必须返回一个ProblemDetails响应主体。我必须仔细检查代码以确保,但是我认为ASP.NET Core仅通过中间件来实现特定结果。他们说的是4xx范围内的任何内容,但我认为实际上只限于返回该范围内状态代码的内置结果类型,而不是带有4xx状态代码的任何结果。同样,这是一种推测,因为我没有确切地查看他们在做什么,尽管这并不是实际结果类的一部分。

出于您的目的,您可以通过几种不同的方式来处理此问题。您可以编写自己的中间件来捕获出站响应并进行重写。您可以使用自定义异常处理程序。您可以直接从ObjectResult继承,然后自己创建一个ProblemDetails实例并将其放入基础中。您甚至可以直接从操作中直接返回ProblemDetails(尽管,这显然是最不理想的方法)。