Search code examples
c#asp.net-coremiddleware

ASP.NET Core Middleware Breaks Physical File Controller Method


I use the following middleware to replace the response content:

app.Use(async (context, next) => {
    var body = context.Response.Body;

    using (var updatedBody = new MemoryStream()) {
        context.Response.Body = updatedBody;

        await next();

        context.Response.Body = body;

        updatedBody.Seek(0, SeekOrigin.Begin);

        var newContent = new StreamReader(updatedBody).ReadToEnd();

        // Replace content here ...

        await context.Response.WriteAsync(newContent);
    }
});

This works fine. However now say I have the following action method:

public IActionResult Image() {
    return PhysicalFile(@"C:\myimage.jpg", "image/jpeg");
}

When it tries to display this image it won't load, but if I remove the middleware then it does.

Please note that I am using ASP.NET Core 3.


Solution

  • Here's the solution I have come up with:

    app.Use(async (context, next) => {
        var body = context.Response.Body;
    
        using (var updatedBody = new MemoryStream()) {
            context.Response.Body = updatedBody;
    
            try {
                await next();
            } catch {
                throw;
            } finally {
                context.Response.Body = body;
            }
    
            if (context.Response.StatusCode == 200 && context.Response.ContentType != null && context.Response.ContentType.Contains("text/html", StringComparison.InvariantCultureIgnoreCase)) {
                updatedBody.Seek(0, SeekOrigin.Begin);
    
                using (var reader = new StreamReader(updatedBody)) {
                    var newContent = reader.ReadToEnd();
    
                    // Replace content here
    
                    await context.Response.WriteAsync(newContent);
                }
            } else {
                if (updatedBody.Length > 0)
                    await context.Response.Body.WriteAsync(updatedBody.ToArray());
            }
        }
    });
    

    This article helped thanks to @CodeCaster's suggestion. As an added bonus I have fixed an issue where it breaks the developer exception page by wrapping a try/catch around the call to the delegate.