はじめに
選択した画像ファイルをアプリ上で表示する機能をBlazorで実装したいと思い調べていたのですが、少し苦労したことがあったので共有します。
環境
Blazor Server (.NET 6)
Microsoft Visual Studio Professional 2022 (64-bit) 17.2.5
実装手順
実装する方法は以下のドキュメントにある通りです。
ここでは主にコードを抜粋します。
まずはPages/_Layout.cshtml
のbodyタグ内に以下を記述します。
<script> window.setImage = async (imageElementId, imageStream) => { const arrayBuffer = await imageStream.arrayBuffer(); const blob = new Blob([arrayBuffer]); const url = URL.createObjectURL(blob); document.getElementById(imageElementId).src = url; URL.revokeObjectURL(url); } </script>
img要素に対して画像を表示するように設定しています。
次にIndex.razor
は以下のようにします。
@page "/" @inject IJSRuntime JS <PageTitle>Index</PageTitle> <InputFile OnChange="ResizeAndDisplayImageUsingStreaming" /> <img id="showImageHere" /> @code { //ファイルを選択するたびに実行される private async Task ResizeAndDisplayImageUsingStreaming(InputFileChangeEventArgs e) { //選択したファイルの取得 var imageFile = e.File; //画像のサイズを変更 var resizedImage = await imageFile.RequestImageFileAsync("image/jpg", 250, 250); //画像のストリームを取得 var jsImageStream = resizedImage.OpenReadStream(); var dotnetImageStream = new DotNetStreamReference(jsImageStream); //JavaScriptの関数を呼び出し await JS.InvokeVoidAsync("setImage", "showImageHere", dotnetImageStream); } }
これで準備完了です。
あとはアプリを立ち上げ、ファイルの選択
ボタンを押して表示したい画像ファイルを選ぶと画像が表示され・・・ません。
このようにうまく読み込めていない状態になります。
エラーメッセージは?
ブラウザの開発者ツールを利用すると、以下のようなエラーが出ています。
Failed to load resource: net::ERR_FILE_NOT_FOUND
どうやら元となるファイルが見つからないようです。
解決方法
以下のページに解決方法がありました。
JavaSctiptの
URL.revokeObjectURL(url);
となっているところを
setTimeout(() => URL.revokeObjectURL(url), 0);
と変更すると画像が表示されます。
setTimeoutは1つ目の引数で指定した処理を、2つ目の引数で指定した時間(ミリ秒)遅らせて実行するメソッドです。
詳しくは以下のページをご覧ください。
developer.mozilla.org
これを使うとURLを破棄するタイミングが遅くなるということなんでしょうか?
一旦はこの方法で回避しようと思います。