dotnet/aspnetcore

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

Open

#61,826 建立於 2025年5月7日

在 GitHub 查看
 (11 留言) (0 反應) (0 負責人)C# (37,933 star) (10,653 fork)batch import
area-blazordesign-proposalgood first issuehelp wanted

描述

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 <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]) on DotNetStreamReference 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;
};

貢獻者指南