dotnet / dotnet/aspnetcore

Add Results.Stream overload that takes a Func<Stream, Task>

Open
#39,383 20 comments 4 reactions 1 assignee Claimed by @davidfowl View on GitHub
api-approved area-minimal feature-minimal-actions help wanted
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

## Background and Motivation

There are scenarios where APIs want to work directly on the response stream without buffering. Today the Stream overloads assume you have a stream that you have produced that is then copied to the underlying response stream, instead, we want to provide a result type that gives you access to the underlying response stream.

Example:

https://github.com/khalidabuhakmeh/dotnet-dramameter/blob/main/DramaMeter/Program.cs#L37-L43

Another is writing a blob storage results to the http response.

## Proposed API

```diff
namespace Microsoft.AspNetCore.Http
{
public static class Results
{
+ public IResult Stream(Func streamWriterCallback,
+ string? contentType = null,
+ string? fileDownloadName = null,
+ DateTimeOffset? lastModified = null,
+ EntityTagHeaderValue? entityTag = null,
+ bool enableRangeProcessing = false);
}
}
```

## Usage Examples

```C#
app.MapGet("/", async (HttpContext http, string? level) => {
level ??= "low";

if (!levels.TryGetValue(level.Trim(), out var result))
return Results.BadRequest("invalid level");

var image = background.CloneAs();
image.Mutate(ctx => {
ctx.Vignette(result.color); // match the background to the intensity
ctx.DrawImage(foreground, new Point(0, 0), 1f);
ctx.DrawImage(result.image, new Point(0, 0), opacity: 1f);
});

http.Response.Headers.CacheControl = $"public,max-age={FromHours(24).TotalSeconds}";
return Results.Stream(stream => image.SaveAsync(stream, PngFormat.Instance), "image/png");
});
```

## Risks

None

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.