2

I'm kind of new to .NET Core so please forgive me if I sound naive.

(Reference: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.1 )

Warning

Don't call next.Invoke after the response has been sent to the client. Changes to HttpResponse after the response has started throw an exception. For example, setting headers and a status code throw an exception. Writing to the response body after calling next:

May cause a protocol violation. For example, writing more than the stated Content-Length. May corrupt the body format. For example, writing an HTML footer to a CSS file.

HasStarted is a useful hint to indicate if headers have been sent or the body has been written to.

As per Microsoft's documentation above, the following would be bad programming practice. However, let's say that I want the webpage to indicate to the webpage user of the application that a Middleware component has been executed(which means writing to Response)

       app.Use(async (context, next) =>
        {
            await context.Response.WriteAsync("<div> Hello World from the middleware 1 </div>");
            await next.Invoke();
        });


        app.Use(async (context, next) =>
        {
            await context.Response.WriteAsync("<div> Hello World from the middleware 2 </div>");
            await next.Invoke();
        });

Since Microsoft's technical documentation above states Never to Invoke "next.Invoke after the response has been sent to the client" then could someone please tell me how to implement code that does the same, but remains a good practice?

crazyTech
  • 1,379
  • 3
  • 32
  • 67

1 Answers1

3

The point is that there should only be a single middleware that is responsible for generating the response. If multiple middlewares are that interlocked in each other, then it’s a sign that it should be a single middleware instead.

For example, the MVC middleware itself is a bit like this: With MVC filters there are multiple actors that could produce the result. To overcome this, MVC has its own pipeline which will not directly write to the response but rather collect an intermediary result which is only written to the response at the end. This is what the IActionResult abstraction does: While filters run, they can modify the action result, and only at the end of the MVC pipeline (and as such the end of the MVC middleware), the result is executed.

If you only need to transfer information between middlewares, then using the response is a bad idea anyway since later middleware cannot read that information. So it’s better to store the information elsewhere. The HttpContext is a good place for this. HttpContext.Items is a simple storage for keeping information for the duration of the request which you can use. For more elaborate information, you could also use a “feature” which can be registered with HttpContext.Features. Features are for example used with endpoint routing to allow other middlewares to access routing information for the current request (e.g. to allow the authorization middleware to authorize the user for a specific endpoint). For more details on Items and Features, check out this question.

poke
  • 369,085
  • 72
  • 557
  • 602