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 goes through the browser's fetch API (documentation).

Browsers support streaming the response of a fetch request using readable streams. This lets you read the response chunk by chunk without waiting for the full response to arrive. You can also cancel the request as soon as you have the data you need.

Response streaming is not enabled by default. You must enable it explicitly per request by setting two 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?