ASP.NET Core Blazor でのファイルのダウンロード
注意
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
この記事では、Blazor アプリでファイルをダウンロードする方法について説明します。
ファイルのダウンロード
この記事では、ファイルをブラウザーで開くのではなく、クライアントにダウンロードして保存する必要がある次のシナリオに対するアプローチについて説明します。
- クライアント上の生のバイナリ データ バッファーにファイル コンテンツをストリーミングする: 通常、この方法は比較的小さいファイル (< 250 MB) に使用されます。
- ストリーミングなしで URL を使用してファイルをダウンロードする: 通常、この方法は比較的大きなファイル (> 250 MB) に使用されます。
アプリとは別のオリジンからファイルをダウンロードする場合、クロス オリジン リソース共有 (CORS) に関する考慮事項が該当します。 詳細については、「クロス オリジン リソース共有 (CORS)」セクションを参照してください。
セキュリティに関する考慮事項
サーバーからファイルをダウンロードする機能をユーザーに提供する場合は、十分に注意してください。 攻撃者は、サービス拒否 (DOS) 攻撃や API 悪用攻撃を実行したり、他の方法でネットワークやサーバーの侵害を試したりする可能性があります。
攻撃の成功の可能性を少なくするセキュリティ手順は、次のとおりです。
- サーバー上のファイル ダウンロード専用領域 (好ましいのは、システム ドライブ以外) からファイルをダウンロードします。 専用の場所を使用することで、ダウンロード可能なファイルに対してセキュリティ制限を適用しやすくなります。 ファイルのダウンロード領域のアクセス許可を無効にします。
- 悪意のあるユーザーは、クライアント側のセキュリティ チェックを簡単に回避できます。 常にサーバーでもクライアント側のセキュリティ チェックを実行してください。
- ユーザーやその他の信頼されていないソースからファイルを受信し、そのファイルに対してセキュリティ チェックを実行せずにそのファイルをすぐにダウンロードできるようにしないでください。 詳細については、「ASP.NET Core でファイルをアップロードする」をご覧ください。
ストリームからのダウンロード
"このセクションは、通常、サイズが最大 250 MB までのファイルに当てはまります。"
比較的小さいファイル (< 250 MB) のダウンロードに推奨される方法は、JavaScript (JS) 相互運用を使用して、クライアント上の生のバイナリ データ バッファーにファイルの内容をストリーミングすることです。 この方法は、対話型レンダリング モードを採用するが、静的サーバー側レンダリング (静的 SSR) を採用するコンポーネントではないコンポーネントに有効です。
比較的小さいファイル (< 250 MB) のダウンロードに推奨される方法は、JavaScript (JS) 相互運用を使用して、クライアント上の生のバイナリ データ バッファーにファイルの内容をストリーミングすることです。
警告
このセクションの方法では、ファイルの内容を JS ArrayBuffer
に読み取ります。 この方法では、ファイル全体がクライアントのメモリに読み込まれるため、パフォーマンスが低下するおそれがあります。 比較的大きなファイル (>= 250 MB) をダウンロードするには、「URL からダウンロードする」セクションのガイダンスに従うことをお勧めします。
次の downloadFileFromStream
JS 関数:
- 指定されたストリームを
ArrayBuffer
に読み取ります。 Blob
を作成して、ArrayBuffer
をラップします。- ファイルのダウンロード アドレスとして機能するオブジェクト URL を作成します。
HTMLAnchorElement
(<a>
要素) を作成します。- ダウンロード用のファイル名 (
fileName
) と URL (url
) を割り当てます。 - アンカー要素で
click
イベントを発生させることでダウンロードをトリガーします。 - アンカー要素を削除します。
URL.revokeObjectURL
を呼び出すことでオブジェクト URL (url
) を取り消します。 クライアント側でメモリがリークしないようにするため、この手順は非常に重要です。
<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
JS の場所に関する一般的なガイダンスと、実稼働アプリの推奨事項については、「ASP.NET Core Blazor アプリでの JavaScript の場所」を参照してください。
次の コンポーネントでは、次を実行します。
- ネイティブ バイト ストリーミング相互運用を使用して、ファイルをクライアントに効率的に転送します。
- クライアントにダウンロードされるファイルの Stream を取得するための
GetFileStream
というメソッドがあります。 別の方法として、ストレージからファイルを取得したり、C# コードでファイルを動的に生成したりする方法もあります。 このデモでは、アプリは新しいバイト配列 (new byte[]
) から 50 KB のランダム データのファイルを作成します。 このバイト配列は MemoryStream でラップされ、例の動的に生成されたバイナリ ファイルとして使用されます。 DownloadFileFromStream
メソッド:GetFileStream
から Stream を取得します。- ユーザーのマシンにファイルが保存されるときのファイル名を指定します。 次の例では、ファイルに
quote.txt
という名前を付けています。 - ファイル データをクライアントにストリーミングできるようにするため、Stream を DotNetStreamReference でラップします。
downloadFileFromStream
JS 関数を呼び出して、クライアント上でデータを受け入れます。
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);
}
}
物理ファイルの Stream を返す必要があるサーバー側アプリ内のコンポーネントの場合、コンポーネントは、次の例に示すように、File.OpenRead を呼び出すことができます。
private Stream GetFileStream() => File.OpenRead(@"{PATH}");
前の例では、{PATH}
プレースホルダーがファイルへのパスです。 @
プレフィックスは、文字列が "逐語的文字列リテラル" であることを示します。このリテラルでは、Windows OS パスのバックスラッシュ (\
) と、パスの単一引用符を表す埋め込みの二重引用符 (""
) を使用できます。 または、文字列リテラル (@
) を使用せず、次のいずれかの方法を使うこともできます。
- エスケープしたバックスラッシュ (
\\
) と引用符 (\"
) を使います。 - ASP.NET Core アプリのプラットフォーム全体でサポートされているパスのスラッシュ (
/
) と、エスケープされた引用符 (\"
) を使います。
URL からダウンロードする
"このセクションは、比較的大きいファイル (通常は 250 MB 以上) に当てはまります。"
静的にレンダリングされるコンポーネント用に対話的にレンダリングされたコンポーネントまたは任意のサイズのファイルを含む比較的大きなファイル (> = 250 MB) をダウンロードするには、JS を使用して、ファイルの名前と URL を持つアンカー要素をトリガーすることをお勧めします。
比較的大きなファイル (> = 250 MB) をダウンロードするには、JS を使用して、ファイルの名前と URL を持つアンカー要素をトリガーすることをお勧めします。
このセクションの例では、quote.txt
という名前のダウンロード ファイルを使用します。これは、アプリの Web ルート (wwwroot
フォルダー) の files
という名前のフォルダーに配置されます。 files
フォルダーは、デモンストレーションのためにのみ使います。 お好みの Web ルート (wwwroot
フォルダー) 内の任意のフォルダー レイアウトで、ダウンロード可能なファイルを整理できます。wwwroot
フォルダーから直接ファイルを提供することもできます。
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/)
次の triggerFileDownload
JS 関数:
HTMLAnchorElement
(<a>
要素) を作成します。- ダウンロード用のファイル名 (
fileName
) と URL (url
) を割り当てます。 - アンカー要素で
click
イベントを発生させることでダウンロードをトリガーします。 - アンカー要素を削除します。
<script>
window.triggerFileDownload = (fileName, url) => {
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? '';
anchorElement.click();
anchorElement.remove();
}
</script>
Note
JS の場所と実稼働アプリの推奨事項に関する一般的なガイダンスについては、ASP.NET Core Blazor アプリの JavaScript の位置に関する記事を参照してください。
次のコンポーネント例では、アプリが使用するのと同じオリジンからファイルをダウンロードします。 別のオリジンからファイルのダウンロードが試行される場合は、クロス オリジン リソース共有 (CORS) を構成します。 詳細については、「クロス オリジン リソース共有 (CORS)」セクションを参照してください。
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);
}
}
対話型コンポーネントでは、前述の例のボタンが DownloadFileFromURL
ハンドラーを呼び出して JavaScript (JS) 関数 triggerFileDownload
を呼び出します。
コンポーネントが静的サーバー側レンダリング (静的 SSR) を採用している場合は、静的サーバー側レンダリング (静的 SSR) を使用する ASP.NET Core Blazor JavaScript のガイダンスに従って triggerFileDownload
を呼び出すボタン (addEventListener
(MDN ドキュメント)) のイベント ハンドラーを追加します。
@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);
}
}
対話型コンポーネントでは、前述の例のボタンが DownloadFileFromURL
ハンドラーを呼び出して JavaScript (JS) 関数 triggerFileDownload
を呼び出します。
コンポーネントが静的サーバー側レンダリング (静的 SSR) を採用している場合は、静的サーバー側レンダリング (静的 SSR) を使用する ASP.NET Core Blazor JavaScript のガイダンスに従って triggerFileDownload
を呼び出すボタン (addEventListener
(MDN ドキュメント)) のイベント ハンドラーを追加します。
@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);
}
}
前述の例のポートを、自分の環境の localhost 開発ポートと一致するように変更します。
@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);
}
}
前述の例のポートを、自分の環境の localhost 開発ポートと一致するように変更します。
クロスオリジン リソース共有 (CORS)
アプリと同じオリジンを持たないファイルに対してクロス オリジン リソース共有 (CORS) を有効にする追加の手順を実行しないと、ファイルのダウンロードはブラウザーによって行われる CORS チェックに合格しません。
ダウンロード用のファイルをホストする ASP.NET Core アプリと他の Microsoft 製品とサービスを使用した CORS の詳細については、次のリソースを参照してください。
- ASP.NET Core でクロスオリジン要求 (CORS) を有効にする
- CORS を使用した Azure CDN の使用 (Azure ドキュメント)
- クロスオリジン リソース共有 (CORS) による Azure Storage のサポート (REST ドキュメント)
- コア Cloud Services - Web サイトとストレージ資産のために CORS を設定する (Learn のモジュール)
- IIS CORS モジュール構成リファレンス (IIS ドキュメント)
その他のリソース
- ASP.NET Core Blazor の静的ファイル
- ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)
- ASP.NET Core Blazor アプリ内の JavaScript の場所
- ASP.NET Core Blazor JavaScript と静的サーバー側レンダリング (静的 SSR)
<a>
: Anchor 要素: セキュリティと privacy (MDN ドキュメント)- ASP.NET Core Blazor ファイルのアップロード
- Blazor サンプル GitHub リポジトリ (
dotnet/blazor-samples
) (ダウンロード方法)
ASP.NET Core