Using ASP.NET Core's middleware to modify response body
Hey, where's my content?
Note: the issue referenced in this post has been fixed and will get released with ASP.NET Core 1.1.0.
While creating a small piece of middleware to modify the response body's content, I had trouble getting anything to appear in my browser. I would get a 200
response-code, but no content (i.e. Content-Length: 0
). Here is an example that creates a similar setup:
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.Use(async (context, next) =>
{
var newContent = string.Empty;
using (var newBody = new MemoryStream())
{
// We set the response body to our stream so we can read after the chain of middlewares have been called.
context.Response.Body = newBody;
await next();
// Reset the body so nothing from the latter middlewares goes to the output.
context.Response.Body = new MemoryStream();
newBody.Seek(0, SeekOrigin.Begin);
// newContent will be `Hello`.
newContent = new StreamReader(newBody).ReadToEnd();
newContent += ", World!";
// Send our modified content to the response body.
await context.Response.WriteAsync(newContent);
}
});
app.Map("", configuration =>
{
configuration.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello");
});
});
}
}
curl -i http://localhost:54122/
HTTP/1.1 200 OK
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcd2lsbGlhbS1ib2dhLWl2XERvY3VtZW50c1xwcm9qZWN0c1wxMGstYXBhcnRcc3JjXDEwa0FwYXJ0?=
X-Powered-By: ASP.NET
Date: Thu, 25 Aug 2016 22:42:51 GMT
Content-Length: 0
Turns out this is a known issue and has an easy workaround which involves storing the original response stream and setting back to it after the middlewares are called:
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.Use(async (context, next) =>
{
var newContent = string.Empty;
// Store the "pre-modified" response stream.
var existingBody = context.Response.Body;
using (var newBody = new MemoryStream())
{
// Previous code removed for brevity.
await next();
// Set the stream back to the original.
context.Response.Body = existingBody;
newBody.Seek(0, SeekOrigin.Begin);
// Previous code removed for brevity.
}
});
// Previous code removed for brevity.
}
}
curl -i http://localhost:54122/
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcd2lsbGlhbS1ib2dhLWl2XERvY3VtZW50c1xwcm9qZWN0c1wxMGstYXBhcnRcc3JjXDEwa0FwYXJ0?=
X-Powered-By: ASP.NET
Date: Thu, 25 Aug 2016 22:49:59 GMT
Hello, World!