2
public class MyMiddleware
{
    RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {

        //await context.Response.WriteAsync("Hello!");
        await _next(context);
        context.Response.Headers.Add("X-ElapsedTime", new[] { "bla" });
    }
}

As soon as I add something like a header. I cannot receive any more the response from my Web API controller.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
     app.UseMyMiddleware();
     app.UseMvc();
 }

Do I need to read first the answer the following middleware "UseMvc" produced?

I just have a very simple Controller method:

    // GET: api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        //Task t = new Task(() => Thread.Sleep(2000));
        //t.Start();

        return new string[] { "value1", "value2" };
    }

I think I found a solution, but it is not actually a full answer:

 public class MyMiddleware
{
    RequestDelegate _next;
    HttpContext _context;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task Invoke(HttpContext context)
    {
        _context = context;
        context.Response.OnStarting(OnStartingCallback, state: this);
        await _next(context);
    }
    public Task OnStartingCallback(object state)
    {
        _context.Response.Headers.Set("x-bla", "bla");
        return Task.FromResult(0);
    }
}

I found a reference to: https://github.com/aspnet/Session/blob/master/src/Microsoft.AspNet.Session/SessionMiddleware.cs and tried to build my code according to it.

Anyway this code feels not very safe. Is it really thread safe.

1 Answer 1

1

Basically what's happening is that you can't set any headers after anything has been written to the response body.

It is because the headers are being sent before the body and as soon as any body content is set.

To get around it in a proper way would be to buffer the response and don't send anything until all middlewares have been executed so they have a chance to modify the headers. This behavior should be a responsibility of the web server. Unfortunately, I didn't find any useful information how to configure buffering on ASP.NET 5 (IIS or Kestrel).

Your solution seems to be ok, but it's not thread safe. Middlewares are singletons and holding context in a class field may introduce race conditions when multiple concurrent request may hit your server. You can make it thread safe by passing the context as a state object.

context.Response.OnStarting(OnStartingCallback, state: context);

and then retrieve it in callback by casting object state to HttpContext.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you sounds like the HTTP headers already sent issue from earlier PHP development. Does "state: this" even make sense? In this particular situation the state object would then just point always to the same class instance. Or is it call by value. Always unsure if it is call by value or call by reference in C#.
It will always point to the same instance of MyMiddleware class. But because middlewares are instantiated only once it will be the same instance for all the requests. That's why you shouldn't use 'this' keyword there and pass the context instead.
I modified my code according to your suggestion (state: context). How can I add further variables to this context? I am starting a stopwatch to measure request time (gist.github.com/MatthiasJost/83269e5d199bcc48b882)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.