asp.net core webappでローカルファイルをアップロードするには、一般的なHTMLと同様、formタグにenctype=”multipart/form-data”を付け、<input type=”file”>を使用して、ファイル本体をアップロードする。
<form enctype="multipart/form-data" method="post">
・・・
アップロードファイル:<input type="file" name="fupFile"/>
<button class="btn btn-primary" type="submit">アップロード</button>
</form>
受取側は、IFormFileクラスを指定して、引数として受取ることが可能。
public async Task OnPost([FromForm]IFormFile fupFile) {
・・・
Stream stm = fupFile.OpenReadStream();
// ファイルに対する処理
・・・
}
まだ試していないが、Blazorの場合は少々異なり、<InputFile>タグとそのイベントハンドラで処理ができるようだ。
・・・
<InputFile OnChange="@OnInputFileChange"/>
・・・
@code {
・・・
protected void OnInputFileChange(InputFileChangeEventArgs e) {
Stream stm = e.File.OpenReadStream();
// ファイル処理
}
}
ちなみに、webapp中のハンドラで動的に作成したファイルのダウンロードだが、ASP.NETで使っていた方法では、ミドルウェアのせいで実行時エラー(Responseヘッダは上書き禁止)が出て、動作しなかった。
色々試してみて、結局MVC(FileContentResultを返す)を一部使用することによってダウンロードできるようになったが、他に方法はないものだろうか・・・
@{
Dictionary<string,string> prm = new Dictionary<string,string>() {
{"Query" : Model.Query}
};
}
・・・
<button class="btn btn-primary" asp-controller="[コントローラ]" asp-action="Download" asp-asp-all-route-data="prm">ダウンロード</button>
public async Task<FileContentResult> Download(string Query) {
・・・
MemoryStream stm = new MemoryStream();
// MemoryStreamにファイルを作成する処理
・・・
byte[] buff = stm.ToArray();
return new FileContentResult(
buff,
"application/octet-stream"
) {
FileDownloadName = filename
};
}
Blazorで<InputFile>を試してみた。
さすがに、WASM版では動作しないみたい。(エラーは出ないけど・・・)Server版ではちゃんと動作しました。
追記
WASM版でも動作しました。動作しなかったのは別の原因だったよう・・・
ちなみに、<InputFile>では、multipleを指定することにより、複数ファイルのアップロードが可能。
その場合は、イベントハンドラ内で、GetMultipleFilesメソッドを使用することにより、複数ファイルの処理が可能。
※multipleを指定しても、UIは同じなので分かりづらい・・・
<InputFile>コンポーネントの実装をみたら、JavaScript使ってますね。
まぁ、POSTBACKしないのだから当たり前か・・・
webappでのファイルダウンロードですが、正解かどうかは分かりませんが、下記のようなコードで動作することを確認しました。
public async Task<IActionResult> OnPost(・・・) {
// これはExcelの例です
ExcelPackage pkg = new ExcelPackage();
// Excelセルへ値設定
・・・
// ヘッダ設定
string filename = $”XXX-{DateTime.Now.ToString(“yyyyMMddHHmmss”)}.xlsx”;
Response.Headers.Add(“Content-Disposition”,$”attachment; filename={filename}”);
Response.ContentType = “application/octet-stream”;
// コンテンツ出力
pkg.SaveAs(Response.BodyWriter.AsStream(true));
await Response.CompleteAsync();
return new EmptyResult();
}
ファイルダウンロードの件ですが、単純にFileResultを返せば良いだけのようです。
try {
・・・
var stm = new MemoryStream();
pkg.SaveAs(stm);
stm.Flush();
stm.Seek(0L,SeekOrigin.Begin); // ポジションを先頭に移動←これやら無いとエラーになった・・・
var res = new FileStreamResult(stm,”application/octet-stream”);
res.FileDownloadName = filename;
return res;
} catch (Exception e) {
// エラーがあったら通常ページを返す
Message = e.Message;
return Page();
}