Middleware to set response ContentType
Asked Answered
T

2

19

In our ASP.NET Core based web application, we want the following: certain requested file types should get custom ContentType's in response. E.g. .map should map to application/json. In "full" ASP.NET 4.x and in combination with IIS it was possible to utilize web.config <staticContent>/<mimeMap> for this and I want to replace this behavior with a custom ASP.NET Core middleware.

So I tried the following (simplified for brevity):

public async Task Invoke(HttpContext context)
{
    await nextMiddleware.Invoke(context);

    if (context.Response.StatusCode == (int)HttpStatusCode.OK)
    {
        if (context.Request.Path.Value.EndsWith(".map"))
        {
            context.Response.ContentType = "application/json";
        }
    }
}

Unfortunately, trying to set context.Response.ContentType after invoking the rest of the middleware chain yields to the following exception:

System.InvalidOperationException: "Headers are read-only, response has already started."

How can I create a middleware that solves this requirement?

Tweet answered 20/6, 2016 at 9:8 Comment(0)
C
18

Try to use HttpContext.Response.OnStarting callback. This is the last event that is fired before the headers are sent.

public async Task Invoke(HttpContext context)
{
    context.Response.OnStarting((state) =>
    {
        if (context.Response.StatusCode == (int)HttpStatusCode.OK)
        {
           if (context.Request.Path.Value.EndsWith(".map"))
           {
             context.Response.ContentType = "application/json";
           }
        }          
        return Task.FromResult(0);
    }, null);

    await nextMiddleware.Invoke(context);
}
Communicate answered 20/6, 2016 at 10:20 Comment(1)
Just in case anyone is trying to use this to write to the response body, note the following regarding the use of OnStarting: "By design, OnStarting must never write to the response body. OnStarting is triggered by the first write to the response body or when the response ends without a body. It's too late to provide a body. If this ever worked it was an accident." From here: github.com/dotnet/aspnetcore/issues/8156#issuecomment-469348439Lothair
E
6

Using an overload of OnStarting method:

public async Task Invoke(HttpContext context)
{
    context.Response.OnStarting(() =>
    {
        if (context.Response.StatusCode == (int) HttpStatusCode.OK &&
            context.Request.Path.Value.EndsWith(".map"))
        {
            context.Response.ContentType = "application/json";
        }

        return Task.CompletedTask;
    });

    await nextMiddleware.Invoke(context);
}
Emetic answered 11/8, 2016 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.