dotnet / dotnet/aspnetcore

Design proposal: #47685 Add blob() method to JS side of Blazor DotNetStreamReference

Open
#61,826 14 comments 0 reactions 0 assignees View on GitHub
area-blazor design-proposal good first issue help wanted
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 5h
Merged PRs (30d)
276

Description

## Summary

Add a ```blob([mimeType: string])``` method to ```DotNetStreamReference``` in Blazor, allowing developers to obtain a Blob from a .NET stream in JavaScript, without fully loading the stream into memory. We chose this specific issue, because it is a "good-first-issue" and we are participating in a germany wide competition, where the subject is to work on issues in open source projects.
Link to issue: https://github.com/dotnet/aspnetcore/issues/47685

## Motivation and goals

Blazor developers can currently pass .NET streams to JavaScript using ```DotNetStreamReference```, which exposes two main methods:
- ```stream()``` (returns a ReadableStream)
- ```arrayBuffer()``` (loads the full stream into memory)

The problem:
- There is no direct way to obtain a Blob, which is required for many web APIs (like `````` elements, file downloads or drag-and-drop functionality).
- ```arrayBuffer()``` is not suitable for large files (like videos) because it fully buffers the stream in memory before use.
- Using ```stream()``` gives a ReadableStream, but many APIs (like ``````, ```URL.createObjectURL()```) require a Blob, not a stream, and converting a ReadableStream into a Blob in JS is non-trivial and inefficient.

Adding a ```blob()``` method would:
- Allow efficient handling of large files (like video or audio) without consuming excessive memory.
- Simplify developer workflows by aligning with common web APIs that expect a Blob.
- Close a usability gap in the current Blazor-JS interop system.

## In scope

- A new method ```blob([mimeType: string])``` on ```DotNetStreamReference``` that returns a Blob representing the .NET stream.
- Ensuring the Blob can be used with standard web APIs (e.g., ``````, ``````, ```URL.createObjectURL()```).
- Keeping performance and memory usage efficient for large streams.

## Out of scope

- Changes to the existing stream() or arrayBuffer() methods.
- Polyfills for browsers that lack Blob support (modern browsers are assumed).
- Enhancements to streaming APIs beyond providing the Blob.

## Risks / unknowns
- **Browser behavior**: While Blobs are widely supported, the implementation detail of
streaming data into a Blob without full buffering might depend on browser internals.
Some browsers may still buffer the entire Blob in memory before making it available.

- **Memory use**: Even if we avoid buffering in .NET or JS, the underlying browser may still
end up consuming memory when the Blob is accessed, especially for very large files.

- **Implementation complexity**: Creating a Blob from a .NET stream across JS interop
might require platform-level work to ensure true streaming behavior rather than just
buffering and converting.

## Examples

### Blazor usage example
```blazor

Play Streamed Video

@code {
private ElementReference videoPlayer;

private async Task PlayVideo()
{
using var fileStream = File.OpenRead("bigvideo.mp4");
var streamRef = new DotNetStreamReference(fileStream);

// JS call to create a blob URL from the .NET stream
var videoUrl = await JS.InvokeAsync("createVideoBlobUrl", streamRef);

// Set the video source
await JS.InvokeVoidAsync("setVideoSrc", videoPlayer, videoUrl);
}
}
```
### JavaScript interop
```JavaScript
window.createVideoBlobUrl = async function (streamRef) {
const blob = await streamRef.blob("video/mp4");
return URL.createObjectURL(blob);
};

window.setVideoSrc = function (videoElement, src) {
videoElement.src = src;
};
```

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.