-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Open
Labels
api-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-http-abstractions
Milestone
Description
Background and Motivation
A very common pattern in ASP.NET Core middleware (and other middleware like components) is to set a temporary response body, execute some user code, then revert to the previous response body when unwinding. The steps go like this:
- Store a reference to the existing body
- Replace the body with the new stream
- Execute user code
- Grab the contents of the body stream and copy it to the previous stream
- Restore the previous body in a finally so exceptional cases are handled
- Don't forget to dispose any streams created
app.Use(async (context, next) =>
{
var previous = context.Response.Body;
try
{
using var stream = new FileBufferingWriteStream();
context.Response.Body = stream;
await next();
await stream.CopyToAsync(previous);
}
finally
{
context.Response.Body = previous;
}
});
This code today is very manual and we could instead make it a bit more pleasant with some new APIs.
Proposed API
Please provide the specific public API signature diff that you are proposing. For example:
namespace Microsoft.AspNetCore.Http
{
public class HttpResponse
{
+ public ResponseBodyScope UseBody(Stream stream);
}
+ public struct ResponseBodyScope : IDisposable, IAsyncDisposable
+ {
+ public Stream PreviousBody { get; }
+ public Stream CurrentBody { get; }
+ public void Dispose();
+ public ValueTask DisposeAsync();
+ }
}
Usage Examples
app.Use(async (context, next) =>
{
using var scope = context.Response.UseBody(new FileBufferingWriteStream());
await next();
await scope.CurrentBody.CopyToAsync(scope.PreviousBody);
});
Alternative Designs
An alternative might be an explicit push/pop style API but that wouldn't automagically handle the pop in the failure case.
We may also want to consider a mode that auto-flushes to the previous response body but then failure cases also get weird (did you want to flush the response on failure?)
doggy8088, lofcz, rbgarcia, YohanSciubukgian and WeihanLi
Metadata
Metadata
Assignees
Labels
api-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-http-abstractions