从OWIN Middleware更改响应对象

时间:2013-07-07 06:20:05

标签: c# asp.net-web-api owin katana

我的OWIN中间件是这样的。 (Framework是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;

    }
}

问题:

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

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

3 个答案:

答案 0 :(得分:27)

  1. 是的,推荐使用OwinMiddleware。一些中间件类不是从OwinMiddleware派生的原因是它们要么尚未切换,因为最近引入了类。或者为了避免程序集由于某种原因而依赖于Microsoft.Owin程序集。

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

  3. 你可以尝试做的是使用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);
    }
    

    感谢cookiesit314更新我的回答。

答案 1 :(得分:8)

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

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

以下是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);
}

答案 2 :(得分:0)

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

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