Events
Power BI DataViz World Championships
Feb 14, 4 PM - Mar 31, 4 PM
With 4 chances to enter, you could win a conference package and make it to the LIVE Grand Finale in Las Vegas
Learn moreThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see the .NET and .NET Core Support Policy. For the current release, see the .NET 9 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 9 version of this article.
This article explains how to download files in Blazor apps.
This article covers approaches for the following scenarios, where a file shouldn't be opened by a browser but downloaded and saved on the client:
When downloading files from a different origin than the app, Cross-Origin Resource Sharing (CORS) considerations apply. For more information, see the Cross-Origin Resource Sharing (CORS) section.
Use caution when providing users with the ability to download files from a server. Cyberattackers may execute Denial of Service (DoS) attacks, API exploitation attacks, or attempt to compromise networks and servers in other ways.
Security steps that reduce the likelihood of a successful attack are:
This section applies to files that are typically up to 250 MB in size.
The recommended approach for downloading relatively small files (< 250 MB) is to stream file content to a raw binary data buffer on the client with JavaScript (JS) interop. This approach is effective for components that adopt an interactive render mode but not components that adopt static server-side rendering (static SSR).
The recommended approach for downloading relatively small files (< 250 MB) is to stream file content to a raw binary data buffer on the client with JavaScript (JS) interop.
Warning
The approach in this section reads the file's content into a JS ArrayBuffer
. This approach loads the entire file into the client's memory, which can impair performance. To download relatively large files (>= 250 MB), we recommend following the guidance in the Download from a URL section.
The following downloadFileFromStream
JS function:
ArrayBuffer
.Blob
to wrap the ArrayBuffer
.HTMLAnchorElement
(<a>
element).fileName
) and URL (url
) for the download.click
event on the anchor element.url
) by calling URL.revokeObjectURL
. This is an important step to ensure memory isn't leaked on the client.<script>
window.downloadFileFromStream = async (fileName, contentStreamReference) => {
const arrayBuffer = await contentStreamReference.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? '';
anchorElement.click();
anchorElement.remove();
URL.revokeObjectURL(url);
}
</script>
Note
For general guidance on JS location and our recommendations for production apps, see JavaScript location in ASP.NET Core Blazor apps.
The following component:
GetFileStream
to retrieve a Stream for the file that's downloaded to clients. Alternative approaches include retrieving a file from storage or generating a file dynamically in C# code. For this demonstration, the app creates a 50 KB file of random data from a new byte array (new byte[]
). The bytes are wrapped with a MemoryStream to serve as the example's dynamically-generated binary file.DownloadFileFromStream
method:
GetFileStream
.quote.txt
.downloadFileFromStream
JS function to accept the data on the client.FileDownload1.razor
:
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS
<PageTitle>File Download 1</PageTitle>
<h1>File Download Example 1</h1>
<button @onclick="DownloadFileFromStream">
Download File From Stream
</button>
@code {
private Stream GetFileStream()
{
var randomBinaryData = new byte[50 * 1024];
var fileStream = new MemoryStream(randomBinaryData);
return fileStream;
}
private async Task DownloadFileFromStream()
{
var fileStream = GetFileStream();
var fileName = "log.bin";
using var streamRef = new DotNetStreamReference(stream: fileStream);
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS
<PageTitle>File Download 1</PageTitle>
<h1>File Download Example 1</h1>
<button @onclick="DownloadFileFromStream">
Download File From Stream
</button>
@code {
private Stream GetFileStream()
{
var randomBinaryData = new byte[50 * 1024];
var fileStream = new MemoryStream(randomBinaryData);
return fileStream;
}
private async Task DownloadFileFromStream()
{
var fileStream = GetFileStream();
var fileName = "log.bin";
using var streamRef = new DotNetStreamReference(stream: fileStream);
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS
<h1>File Download Example</h1>
<button @onclick="DownloadFileFromStream">
Download File From Stream
</button>
@code {
private Stream GetFileStream()
{
var randomBinaryData = new byte[50 * 1024];
var fileStream = new MemoryStream(randomBinaryData);
return fileStream;
}
private async Task DownloadFileFromStream()
{
var fileStream = GetFileStream();
var fileName = "log.bin";
using var streamRef = new DotNetStreamReference(stream: fileStream);
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}
@page "/file-download-1"
@using System.IO
@inject IJSRuntime JS
<h1>File Download Example</h1>
<button @onclick="DownloadFileFromStream">
Download File From Stream
</button>
@code {
private Stream GetFileStream()
{
var randomBinaryData = new byte[50 * 1024];
var fileStream = new MemoryStream(randomBinaryData);
return fileStream;
}
private async Task DownloadFileFromStream()
{
var fileStream = GetFileStream();
var fileName = "log.bin";
using var streamRef = new DotNetStreamReference(stream: fileStream);
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}
For a component in a server-side app that must return a Stream for a physical file, the component can call File.OpenRead, as the following example demonstrates:
private Stream GetFileStream() => File.OpenRead(@"{PATH}");
In the preceding example, the {PATH}
placeholder is the path to the file. The @
prefix indicates that the string is a verbatim string literal, which permits the use of backslashes (\
) in a Windows OS path and embedded double-quotes (""
) for a single quote in the path. Alternatively, avoid the string literal (@
) and use either of the following approaches:
\\
) and quotes (\"
)./
) in the path, which are supported across platforms in ASP.NET Core apps, and escaped quotes (\"
).This section applies to files that are relatively large, typically 250 MB or larger.
The recommended approach for downloading relatively large files (>= 250 MB) with interactively-rendered components or files of any size for statically-rendered components is to use JS to trigger an anchor element with the file's name and URL.
The recommended approach for downloading relatively large files (>= 250 MB) is to use JS to trigger an anchor element with the file's name and URL.
The example in this section uses a download file named quote.txt
, which is placed in a folder named files
in the app's web root (wwwroot
folder). The use of the files
folder is only for demonstration purposes. You can organize downloadable files in any folder layout within the web root (wwwroot
folder) that you prefer, including serving the files directly from the wwwroot
folder.
wwwroot/files/quote.txt
:
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"
- General Ravon (Guy Siner, http://guysiner.com/)
Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
Copyright 1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"
- General Ravon (Guy Siner, http://guysiner.com/)
Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
Copyright 1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"
- General Ravon (Guy Siner, http://guysiner.com/)
Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
Copyright 1975 BBC (https://www.bbc.co.uk/)
When victory is ours, we'll wipe every trace of the Thals and their city from the face of this land. We will avenge the deaths of all Kaleds who've fallen in the cause of right and justice and build a peace which will be a monument to their sacrifice. Our battle cry will be "Total extermination of the Thals!"
- General Ravon (Guy Siner, http://guysiner.com/)
Dr. Who: Genesis of the Daleks (https://www.bbc.co.uk/programmes/p00vd5g2)
Copyright 1975 BBC (https://www.bbc.co.uk/)
The following triggerFileDownload
JS function:
HTMLAnchorElement
(<a>
element).fileName
) and URL (url
) for the download.click
event on the anchor element.<script>
window.triggerFileDownload = (fileName, url) => {
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? '';
anchorElement.click();
anchorElement.remove();
}
</script>
Note
For general guidance on JS location and our recommendations for production apps, see JavaScript location in ASP.NET Core Blazor apps.
The following example component downloads the file from the same origin that the app uses. If the file download is attempted from a different origin, configure Cross-Origin Resource Sharing (CORS). For more information, see the Cross-Origin Resource Sharing (CORS) section.
FileDownload2.razor
:
@page "/file-download-2"
@inject IJSRuntime JS
<PageTitle>File Download 2</PageTitle>
<h1>File Download Example 2</h1>
<button @onclick="DownloadFileFromURL">
Download File From URL
</button>
@code {
private async Task DownloadFileFromURL()
{
var fileName = "quote.txt";
var fileURL = "/files/quote.txt";
await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
}
}
For interactive components, the button in the preceding example calls the DownloadFileFromURL
handler to invoke the JavaScript (JS) function triggerFileDownload
.
If the component adopts static server-side rendering (static SSR), add an event handler for the button (addEventListener
(MDN documentation)) to call triggerFileDownload
following the guidance in ASP.NET Core Blazor JavaScript with static server-side rendering (static SSR).
@page "/file-download-2"
@inject IJSRuntime JS
<PageTitle>File Download 2</PageTitle>
<h1>File Download Example 2</h1>
<button @onclick="DownloadFileFromURL">
Download File From URL
</button>
@code {
private async Task DownloadFileFromURL()
{
var fileName = "quote.txt";
var fileURL = "/files/quote.txt";
await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
}
}
For interactive components, the button in the preceding example calls the DownloadFileFromURL
handler to invoke the JavaScript (JS) function triggerFileDownload
.
If the component adopts static server-side rendering (static SSR), add an event handler for the button (addEventListener
(MDN documentation)) to call triggerFileDownload
following the guidance in ASP.NET Core Blazor JavaScript with static server-side rendering (static SSR).
@page "/file-download-2"
@inject IJSRuntime JS
<h1>File Download Example 2</h1>
<button @onclick="DownloadFileFromURL">
Download File From URL
</button>
@code {
private async Task DownloadFileFromURL()
{
var fileName = "quote.txt";
var fileURL = "https://localhost:5001/files/quote.txt";
await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
}
}
Change the port in the preceding example to match the localhost development port of your environment.
@page "/file-download-2"
@inject IJSRuntime JS
<h1>File Download Example 2</h1>
<button @onclick="DownloadFileFromURL">
Download File From URL
</button>
@code {
private async Task DownloadFileFromURL()
{
var fileName = "quote.txt";
var fileURL = "https://localhost:5001/files/quote.txt";
await JS.InvokeVoidAsync("triggerFileDownload", fileName, fileURL);
}
}
Change the port in the preceding example to match the localhost development port of your environment.
Without taking further steps to enable Cross-Origin Resource Sharing (CORS) for files that don't have the same origin as the app, downloading files won't pass CORS checks made by the browser.
For more information on CORS with ASP.NET Core apps and other Microsoft products and services that host files for download, see the following resources:
<a>
: The Anchor element: Security and privacy (MDN documentation)dotnet/blazor-samples
) (how to download)ASP.NET Core feedback
ASP.NET Core is an open source project. Select a link to provide feedback:
Events
Power BI DataViz World Championships
Feb 14, 4 PM - Mar 31, 4 PM
With 4 chances to enter, you could win a conference package and make it to the LIVE Grand Finale in Las Vegas
Learn moreTraining
Module
Download and upload files in an ASP.NET Core app with Microsoft Graph - Training
Learn how to list, download, and upload a user's files in an ASP.NET Core application by using Microsoft Graph.
Certification
Microsoft Certified: Azure Developer Associate - Certifications
Build end-to-end solutions in Microsoft Azure to create Azure Functions, implement and manage web apps, develop solutions utilizing Azure storage, and more.
Documentation
ASP.NET Core Blazor file uploads
Learn how to upload files in Blazor with the InputFile component.
Display images and documents in ASP.NET Core Blazor
Learn how to display images and documents in ASP.NET Core Blazor apps.
Call JavaScript functions from .NET methods in ASP.NET Core Blazor
Learn how to invoke JavaScript functions from .NET methods in Blazor apps.