C# 从 OWIN 中间件更改响应对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17509768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:41:09  来源:igfitidea点击:

Changing the response object from OWIN Middleware

c#asp.net-web-apiowinkatana

提问by Badri

My OWIN middleware is like this. (Framework is ASP.NET Web API).

我的OWIN中间件是这样的。(框架是 ASP.NET Web API)。

public class MyMiddleware : OwinMiddleware
{
    public MyMiddleware(OwinMiddleware next) : base(next) { }

    public override async Task Invoke(OwinRequest request, OwinResponse response)
    {
        var header = request.GetHeader("X-Whatever-Header");

        await Next.Invoke(request, response);

        response.SetHeader("X-MyResponse-Header", "Some Value");
        response.StatusCode = 403;

    }
}

Questions:

问题:

  1. Is it the recommended practice to derive from OwinMiddleware? I see that in Katana source, some of the middleware classes derive from OwinMiddlewareand some do not.

  2. I can see the request headers okay. Setting response header or status code after Next.Invokein my middleware has no effect on the response returned to the client. But if I set the response header or status before the Next.Invokecall, the response with headers and the status that I set is returned to the client. What is the right way of setting these?

  1. 它是从 推导出的推荐做法OwinMiddleware吗?我看到在 Katana 源代码中,一些中间件类派生自,OwinMiddleware而另一些则不派生。

  2. 我可以看到请求标头没问题。Next.Invoke在我的中间件之后设置响应头或状态码对返回给客户端的响应没有影响。但是如果我在Next.Invoke调用之前设置了响应头或状态,则带有头和我设置的状态的响应将返回给客户端。设置这些的正确方法是什么?

采纳答案by Youssef Moussaoui

  1. Yes, deriving from OwinMiddleware is recommended. The reason some middleware classes don't derive from OwinMiddleware is that either they haven't switched over yet because the class was introduced recently. Or to avoid having the assembly take a dependency on the Microsoft.Owin assembly for some reason.

  2. The probable reason setting stuff on the response after calling Invoke on Next doesn't work is that the response HTTP header gets sent as soon as anyone starts writing to the response body stream. So any changes to status code or HTTP headers after a middleware component starts writing to the response body won't have any effect.

  1. 是的,建议从 OwinMiddleware 派生。一些中间件类没有从 OwinMiddleware 派生的原因是它们还没有切换,因为该类是最近引入的。或者为了避免由于某种原因使程序集依赖于 Microsoft.Owin 程序集。

  2. 在调用 Invoke on Next 后在响应上设置内容不起作用的可能原因是,只要有人开始写入响应正文流,就会发送响应 HTTP 标头。因此,在中间件组件开始写入响应正文后,对状态代码或 HTTP 标头的任何更改都不会产生任何影响。

What you can try doing is to use the OnSendingHeaders callback that OWIN provides. Here's how you can use it:

您可以尝试做的是使用 OWIN 提供的 OnSendingHeaders 回调。使用方法如下:

public override async Task Invoke(IOwinContext context)
{
   var response = context.Response;
   var request =  context.Request;

   response.OnSendingHeaders(state =>
   {
       var resp = (OwinResponse)state;
       resp.Headers.Add("X-MyResponse-Header", "Some Value");
       resp.StatusCode = 403;
       resp.ReasonPhrase = "Forbidden";
    }, response);

  var header = request.Headers["X-Whatever-Header"];

  await Next.Invoke(context);
}

Credit to biscuit314 for updating my answer.

感谢 biscuit314 更新我的答案。

回答by biscuit314

I tried to edit Youssef's excellent answer to correct a minor bug and update the example with how the OwinMiddleware now works.

我试图编辑 Youssef 的优秀答案以纠正一个小错误,并使用 OwinMiddleware 现在的工作方式更新示例。

The edit was rejected (well, approved by one, rejected by one for being too minor, and rejected by two for being too major).

编辑被拒绝了(好吧,一个人批准,一个人因为太小而被拒绝,两个人因为太重要而被拒绝)。

Here is that version of Youssef's code:

这是 Youssef 代码的那个版本:

public override async Task Invoke(IOwinContext context)
{
  var response = context.Response;
  var request =  context.Request;

  response.OnSendingHeaders(state =>
    {
        var resp = (OwinResponse)state;
        resp.Headers.Add("X-MyResponse-Header", "Some Value");
        resp.StatusCode = 403;
        resp.ReasonPhrase = "Forbidden"; // if you're going to change the status code
                                         // you probably should also change the reason phrase
    }, response);

  var header = request.Headers["X-Whatever-Header"];

  await Next.Invoke(context);
}

回答by Deependra Kushwah

I used this code to get the time taken by every request.

我使用此代码来获取每个请求所花费的时间。

appBuilder.Use(async (context, next) =>
        {
            var watch = new Stopwatch();
            watch.Start();
            await next();
            watch.Stop();
            context.Response.Headers.Set("ResponseTime", watch.Elapsed.Seconds.ToString());
        });