How to download files with Blazor
Here is an easy way to download a file either using directly an HTTP URL or using a stream on C# side in your Blazor Web application.
Spoiler: In this article I will also make usage of the Browser JS Blob storage.
Static Asset
Let’s start with the simple use case where you want to download a file from your host as a static asset.
Using Anchor element
Nothing new here, you can just use the Anchor element <a> with the href set to your file in your razor page:
<a href="my-file.jpg" download>
Download Link to a file
</a>
From your C# code
Now we want to trigger the file download from the C# code. It’s getting a little more tricky here because we need to create a Java script function that will add an anchor element onto the html document and trigger a click event on it. Then we have to interop with the Java script to call that function with the URL parameter.
Fortunately, I wrote a project to help you with that. To use it, you just need to add the SoloX.BlazorJsBlob Nuget package in your project:
> dotnet add package SoloX.BlazorJsBlob --version 1.0.0
Once the pakage is added you need to register the BlazorJsBlob services:
First add using statement for SoloX.BlazorJsBlob and resister the services in your Startup.cs file (or in your Program.cs files):
services.AddJsBlob();
From that point, it is really easy, we need to inject the service IBlobService and call the SaveAsFileAsync method with the URL you want to download.
@* Inject the IBlobService *@
@inject IBlobService BlobService@* Add a button to trigger our ClickSaveFromUrlAsync method *@
<button @onclick="ClickSaveFromUrlAsync">Save Url file</button>@code {
// OnClick method
public async Task ClickSaveFromUrlAsync()
{
// Call SaveAsFileAsync method in order to download the file
// and to save it in the Download location.
await BlobService.SaveAsFileAsync("my-file.jpg");
}
}
Stream on C# side
Now we are going to download a file from a Stream created on the C# side of the Blazor application.
Using a data URL
The first option to save a file from a stream is to generate a data URL and to use the IBlobService with the SaveAsFileAsync method or to generate a Anchor element in your component.
data:[<mediatype>][;base64],<data>
Let’s see how to generate the data URL from the stream and to save it as a file:
// Create and/or load the source stream.
// Let's say this is a jpg file.
var stream = ...;// Create a memory buffer and copy the data in it.
var memBuffer = new MemoryStream();
await stream.CopyToAsync(memBuffer);// Base64 encode the data
var b64 = Convert.ToBase64String(memBuffer.ToArray());// Finally call the SaveAsFileAsync with the data URL.
var dataUrl = $"data:image/jpeg;base64," + b64;
await BlobService.SaveAsFileAsync(dataUrl, "my-file.jpg");
This solution works perfectly although it is not really fast because of the base64 encoding (even if it can be improved) and depending on the browser you will encounter some limitations regarding the file size.
Using a Browser Blob storage
A much better solution would be to use the Browser Blob storage to get access to much larger files. In addition, since .Net 6.0, Java Script interoperability has been improved in Blazor on bytes array transfer so it’s also much faster.
Thanks to the IBlobService this is all easily usable thought the IBlob object:
// Create and/or load the source stream.
// Let's say this is a jpg file.
var stream = ...;// Create a IBlob and copy data into it.
await using var blob = await BlobService
.CreateBlobAsync(stream, "image/jpeg");// Now we can just call SaveAsFileAsync to download the file
await BlobService.SaveAsFileAsync(blob, "tropical-waterfall.jpg");
Embed
The good thing about IBlob and its URL is that it is convenient to use. For instance It’s really easy to use in order to display a document in your page with a Embed tag for example.
<div>
<embed src="@blob.Uri" type="@blob.Type"
width="500" height="500"/>
</div>
Last words
I hope this article helps and as you can see the BlazorJsBlob project is really easy to use so don’t hesitate, give it a try!
Or if you are just curious you can find out how it’s implemented, it’s all in the BlazorJsBlob Github project.