Streaming an HTTP response in Blazor WebAssembly

 
 
  • Gérald Barré

Blazor WebAssembly relies on the browser to execute web requests. Every call you make using HttpClient is executed using the fetch API (documentation) provided by the browser.

Web Browsers support streaming the response of a fetch request using the readable streams. This allows reading the response chunk by chunk without waiting for the last byte of the response. You can also cancel the request as soon as you get the data you want.

The response streaming is not enabled by default. You must enable it explicitly per request by setting 2 options:

  • HttpRequestMessage.SetBrowserResponseStreamingEnabled(true) indicates to use a ReadableStream so the response is streamable
  • HttpCompletionOption.ResponseHeadersRead indicates the operation should complete as soon as a response is available and headers are read. The content is not read yet.

Here's the full example:

Razor
@page "/"
@inject HttpClient HttpClient

<h1>HTTP streaming</h1>

<button type="button" @onclick="Get">Get data</button>
<button type="button" @onclick="Stop">Cancel</button>

<p>Bytes read: @byteCount</p>

@code{
    int byteCount;
    CancellationTokenSource cts;

    async Task Get()
    {
        cts = new CancellationTokenSource();

        using var request = new HttpRequestMessage(HttpMethod.Get, "stream");
        request.SetBrowserResponseStreamingEnabled(true); // Enable response streaming

        // Be sure to use HttpCompletionOption.ResponseHeadersRead
        using var response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        using var stream = await response.Content.ReadAsStreamAsync();

        // Read the response chunk by chunk and count the number of bytes
        var bytes = new byte[10];
        while (!cts.Token.IsCancellationRequested)
        {
            var read = await stream.ReadAsync(bytes, cts.Token);
            if (read == 0) // End of stream
                return;

            byteCount += read;

            // Update the UI
            StateHasChanged();
            await Task.Delay(1);
        }
    }

    // Cancel the request
    void Stop() => cts?.Cancel();
}

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub