Reputation: 10683
I want to write Custom Middleware in my ASP.NET Core 1.0 project which will replace original framework's Http Response Stream to my own, so I will be able to perform read / seek / write operations on it (first 2 are not possible on the original stream) in the further code i.e. in Actions or Filters.
I've started with the following code:
public class ReplaceStreamMiddleware
{
protected RequestDelegate NextMiddleware;
public ReplaceStreamMiddleware(RequestDelegate next)
{
NextMiddleware = next;
}
public async Task Invoke(HttpContext httpContext)
{
using (var responseStream = new MemoryStream())
{
var fullResponse = httpContext.Response.Body;
httpContext.Response.Body = responseStream;
await NextMiddleware.Invoke(httpContext);
responseStream.Seek(0, SeekOrigin.Begin);
await responseStream.CopyToAsync(fullResponse);
}
}
}
The problem with the following code is that sometimes the fullResponse
stream is already closed at the time of invoking await responseStream.CopyToAsync(fullResponse);
so it throws an exception Cannot access a closed Stream.
This weird behaviour is easy to observe when I load the page in the browser and then refresh, before it loads completely.
I would like to know:
Upvotes: 3
Views: 3300
Reputation: 28425
The exception doesn't come from your CopyToAsync
. It's from one of your code's callers:
You're not restoring the original response stream in HttpContext
. Therefore, whoever calls your middleware will get back a closed MemoryStream
.
Here's some working code:
app.Use(async (httpContext, next) =>
{
using (var memoryResponse = new MemoryStream())
{
var originalResponse = httpContext.Response.Body;
try
{
httpContext.Response.Body = memoryResponse;
await next.Invoke();
memoryResponse.Seek(0, SeekOrigin.Begin);
await memoryResponse.CopyToAsync(originalResponse);
}
finally
{
// This is what you're missing
httpContext.Response.Body = originalResponse;
}
}
});
app.Run(async (context) =>
{
context.Response.ContentType = "text/other";
await context.Response.WriteAsync("Hello World!");
});
Upvotes: 8