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: #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
<video>
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<video src=...>
,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])
onDotNetStreamReference
that returns a Blob representing the .NET stream. - Ensuring the Blob can be used with standard web APIs (e.g.,
<video>
,<audio>
,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
<video @ref="videoPlayer" controls autoplay></video>
<button @onclick="PlayVideo">Play Streamed Video</button>
@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<string>("createVideoBlobUrl", streamRef);
// Set the video source
await JS.InvokeVoidAsync("setVideoSrc", videoPlayer, videoUrl);
}
}
JavaScript interop
window.createVideoBlobUrl = async function (streamRef) {
const blob = await streamRef.blob("video/mp4");
return URL.createObjectURL(blob);
};
window.setVideoSrc = function (videoElement, src) {
videoElement.src = src;
};