Blazorは本当に素晴らしいもので、開発効率を大幅に向上させてくれます。多くのページインタラクション機能を、ほんのわずかなコードで実現できますし、しかもJavaScript不要です。Blazorを使ったファイルアップロードがどれほど簡単か、想像もつかなかったでしょう?
結論から言うと、Blazorで進捗表示付きのファイルアップロードを実装するのは本当に簡単です!効果は画像をご覧ください:

この小さな機能を実現するのに、わずか50行足らずのコードで済みました。それでは、ケーススタディを紹介します。
まず、Tewr.Blazor.FileReaderパッケージを導入します。このパッケージはファイルアップロードのストリーム読み取りを提供するため、サーバーサイドでアップロードされたファイルを読み込みながら書き込む操作が可能になります。
依存関係の注入を設定します(注:これはBlazor Serverモードです。WASM方式については文末のリポジトリドキュメントを参照してください):
services.AddFileReaderService();
次にページレイアウトを行います。とてもシンプルで、進捗表示と画像表示に使用する2つの変数を宣言します:
<input type="file" /><button>ファイルをアップロード</button>
<div>
@if (!string.IsNullOrEmpty(_src)) {
<img src="@_src" width="600px" />
} else {
<p>@progress</p>
}
</div>
そしてコンポーネントにIFileReaderServiceサービスを注入します:
@using Tewr.Blazor.FileReader @inject IFileReaderService fileReaderService;
ファイル入力ボックスをC#コードとやり取りできるようにするため、ElementReferenceで参照します:
<input @ref="inputTypeFileElement" type="file" /><button>ファイルをアップロード</button>
<div>
@if (!string.IsNullOrEmpty(_src)) {
<img src="@_src" width="600px" />
} else {
<p>@progress</p>
}
</div>
@code { private ElementReference inputTypeFileElement; private string _src;
private string progress; }
ボタンにイベントをバインドし、ボタンがトリガーされるとfileReaderServiceを介してファイルストリームを読み取ります。その後は通常のバイナリデータのコピー操作で、ファイルの転送進捗を取得し、計算してページに表示できます:
<button @onclick="ReadFile">ファイルをアップロード</button>
public async Task ReadFile()
{
_src = "";
foreach (var file in await fileReaderService.CreateReference(inputTypeFileElement).EnumerateFilesAsync())
{
await using var fileStream = await file.OpenReadAsync();
var buffer = new byte[2048];
var finalBuffer = new byte[fileStream.Length];
int count;
int totalCount = 0;
while ((count = await fileStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
Buffer.BlockCopy(buffer, 0, finalBuffer, totalCount, count);
totalCount += count;
progress = "ファイルアップロード中 " + (int)(totalCount * 100.0 / fileStream.Length) + "%";
StateHasChanged();
}
_src = $"data:image/jpg;base64,{Convert.ToBase64String(finalBuffer)}";
progress = "";
StateHasChanged();
}
}
完全なコードは以下の通りです:
@page "/counter" @using Tewr.Blazor.FileReader @inject IFileReaderService
fileReaderService;
<input @ref="inputTypeFileElement" type="file" />
<button @onclick="ReadFile">ファイルをアップロード</button>
<div>
@if (!string.IsNullOrEmpty(_src)) {
<img src="@_src" width="600px" />
} else {
<p>@progress</p>
}
</div>
@code { private ElementReference inputTypeFileElement; private string _src;
private string progress; public async Task ReadFile() { _src = ""; foreach (var
file in await
fileReaderService.CreateReference(inputTypeFileElement).EnumerateFilesAsync()) {
await using var fileStream = await file.OpenReadAsync(); var buffer = new
byte[2048]; var finalBuffer = new byte[fileStream.Length]; int count; int
totalCount = 0; while ((count = await fileStream.ReadAsync(buffer, 0,
buffer.Length)) != 0) { Buffer.BlockCopy(buffer, 0, finalBuffer, totalCount,
count); totalCount += count; progress = "ファイルアップロード中 " + (int)(totalCount * 100.0
/ fileStream.Length) + "%"; StateHasChanged(); } _src =
$"data:image/jpg;base64,{Convert.ToBase64String(finalBuffer)}"; progress = "";
StateHasChanged(); } } }
管理者の追記:
記事の先頭のデモ画像は1MB未満の画像を使用しています。Tewr.Blazor.FileReaderパッケージはファイルアップロードのストリーム読み取りを提供するため、大きなファイルのアップロードも可能です。以下は34.2MBのZIP圧縮ファイルをアップロードした例です(Blazor Serverモード):

デモは簡素で、gifではわかりにくいかもしれませんが、このパッケージが優れていることを示すためのものです。大きなファイルをアップロードするには、上記の1回の読み取りサイズを大きめに変更します。例:512KB:
var buffer = new byte[1024*512];
以下のMicrosoftのBlazorファイルアップロードドキュメントを見ると、1回のパケットサイズを20KBより大きくすると、ページが一瞬フリーズし、その後自動的にリフレッシュされてアップロード操作がリセットされる可能性があります。しかし、このパッケージを使用するとその問題は発生しません。このパッケージは非常に優れています。
以上で記事を終わります。
参考