ASP.Net Core中如何覆盖415响应

3
在ASP.net Core 2.1中,我想返回一个带有状态码415的Json响应,而不是默认返回415。
为了实现这一目标,我使用了资源过滤器:
public class MediaTypeResouceFilter : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
        if (context.HttpContext.Response.StatusCode == 415)
        {
            context.Result = new ContentResult() { StatusCode = 415, Content = JsonConvert.SerializeObject(myResponse), ContentType = "application/json" };
        }
    }
}

在调试过程中,我看到context.Result被成功覆盖了,但Postman只获取到415错误,没有Json响应。
如果我采取以下措施:
context.Result = new ContentResult() { StatusCode = 415, Content = JsonConvert.SerializeObject(myResponse), ContentType = "application/json" };

在 OnResourceExecuting 中而不是 OnResourceExecuted 中,它按照我希望的方式工作,但问题在于在执行资源之前我无法检查状态码。有任何想法为什么会发生这种情况吗?
3个回答

4

你可以试试这个吗?

public class MediaTypeResouceFilter : Attribute, IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            if (context.HttpContext.Response.StatusCode == 415)
            {
                var jsonString = JsonConvert.SerializeObject(new { data = "this is custom message" });
                byte[] data = Encoding.UTF8.GetBytes(jsonString);
                context.HttpContext.Response.Body.WriteAsync(data, 0, data.Length);
            }
        }
    }

您可能会收到415状态码,返回的数据如下:{"data":"这是自定义消息"}

实际上,OnResourceExecuted事件触发太晚了,但您可以修改响应体以显示您的自定义消息。


1
有时候可能会绕过这个问题,但是当你已经设置了一个响应时要小心。比如说,在一个内容为 11111111111111111111111AAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDD 的操作中发送一个 415 响应。由于内容长度不匹配,你会收到一个错误。 - itminus
1
是的,我明白。在某些情况下,这可能是危险的。如果我们真的想要回复像这样的自定义消息,请小心添加更多业务逻辑。 - Khai Nguyen
虽然我认为没有一种优雅的方式可以通过“增加更多业务”来实现,但我支持您快速简短的解决方法。 - itminus

2

我认为使用中间件组件是一个不错的选择。这是中间件的Invoke方法:

public async Task Invoke(HttpContext context) {
    Exception exception = null;
    try {
        await _next(context);
    }
    catch (Exception e) {
        exception = e;
        //try handling exception stuff...
    }

    //try handling 415 code stuff...
    if(context.Response.StatusCode==415){
        var yourJsonObj = new { Blah = "blah..." };
        string result = JsonConvert.SerializeObject(yourJsonObj);
        //context.Response.StatusCode = 200; //You can change the StatusCode here
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(result);
    }
}

1

查看 Microsoft 的工作流程:

filter execution workflow

IResourceFilter::OnResourceExecuted(ResourceExecutedContext context) 方法在结果执行后运行。由于结果执行已经完成,您无法对结果进行任何更改。


我在这里留下评论,因为我不知道是否有一种好的方法可以在过滤器中根据状态代码替换正文。在IActionResult执行之前没有API来窥视StatusCode。但是如果有人想要这样做,一个更好的地方是在结果执行之前替换结果。我们可以设置一个标志(例如HttpContext.Items ["flag"])来告诉过滤器,在这种方式中,我们不需要写两次正文。 - itminus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接