34

My OWIN middleware is like this. (Framework is 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 OwinMiddleware and some do not.

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

abatishchev
  • 98,240
  • 88
  • 296
  • 433

3 Answers3

36
  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.

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

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.

Youssef Moussaoui
  • 12,187
  • 2
  • 41
  • 37
  • Thanks Youssef. For point #2, is there an example code in Katana source or somewhere else that I can look at, from the best practice pt of view? I believe, what I'm asking for is a fairly common need and is every one supposed to do this stream switching just to set a response header, if we use OWIN middleware? Any pointers will be appreciated. – Badrinarayanan Lakshmiraghavan Jul 07 '13 at 16:25
  • I'm able to resolve the problem by following your suggestion but isn't there an easy way out? I mean this is too much of work to just set a response header on the way out, especially if one is used to Web API's message handler. – Badrinarayanan Lakshmiraghavan Jul 07 '13 at 18:47
  • 3
    Updated the answer with a simpler method. Please let me know if it works. – Youssef Moussaoui Jul 08 '13 at 18:57
  • Yes, this is much better. This is exactly what I'm looking for. Thank you. – Badrinarayanan Lakshmiraghavan Jul 09 '13 at 03:37
  • OnSendingHeaders is gone? or am i missing some references ? – Poul K. Sørensen Sep 12 '13 at 10:30
  • @pksorensen - OnSendingHeaders is on the response object, not the request. I've submitted an edit. – biscuit314 Mar 02 '14 at 17:13
  • 9
    "Yes, deriving from OwinMiddleware is recommended." No, no it is not. https://github.com/owin/owin/issues/20 https://github.com/owin/owin/issues/19 –  Mar 18 '14 at 21:56
  • @YoussefMoussaoui how about when I need to `write` something different (generally a completely different response) based on what the `next` did to the response? – Mo Valipour May 22 '15 at 17:28
  • 1
    @Valipour, the OnSendingHeaders callback only runs once data starts being sent on the wire, so you should be able to inspect the response at that point – Youssef Moussaoui Jun 02 '15 at 02:14
  • thanks, I am actually doing that and can confirm works perfectly. **HOWEVER** you must do the *rewrite* code synchronously, otherwise will end-up in memory-conflicting issues. My code can be seen here: http://mvalipour.github.io/back-end/2015/05/30/identityserver3-json-response-mode/ – Mo Valipour Jun 02 '15 at 08:52
  • Arrived at this after spending a day to no-avail trying to figure out why my middleware was not setting cookies I was telling it to. Thanks for this! – Aashish Koirala Mar 31 '17 at 14:09
  • 1
    Has this functionality changed recently? I don't see any change to my response headers when using it like this. – gooram Jun 18 '21 at 01:41
11

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

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:

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);
}
biscuit314
  • 2,384
  • 2
  • 21
  • 29
1

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());
        });