初めまして、アキちゃんです。
備忘録をかねてブログを書くことにしました。
今回はBlazor Serverで簡易ファイル共有(後編:ファイルダウンロード)について書きます。
それでは早速・・・Blazor Serverで簡易ファイル共有(後編:ファイルダウンロード)!
Lesson.1 前回まで
前回まででファイルをアップロードするところまで作成しました。
今回はアップロードしたファイルをダウンロードするところまでしようと思います
Lesson.2 事前準備
Blazorでファイルをダウンロードする方法は少ないですがいくつかあります。
今回はMicrosoftが紹介している以下サイトの方法で行おうと思います。
Pages/_Layout.cshtmlに、以下の記述を追記します。
_Layout.cshtml(クリックで展開) _Layout.cshtml(クリックで圧縮)
@using Microsoft.AspNetCore.Components.Web
@namespace FileShare.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<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>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="FileShare.styles.css" rel="stylesheet" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
@RenderBody()
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
Lesson.3 ファイル一覧・ダウンロード
アップロードしたファイル一覧を取得し、任意のファイルをダウンロードするコントローラーを作りたいため、Controllerフォルダに 追加→コントローラー→MVCコントローラー - 空 を選択し、DownloadController.csを作成します。
できたDownloadController.csをざっくり以下のように修正します。
DownloadController.cs(クリックで展開) DownloadController.cs(クリックで圧縮)
using Microsoft.AspNetCore.Mvc;
using System.Text;
using System.Text.Json;
namespace FileShare.Controllers
{
public class DownloadController : Controller
{
private readonly IWebHostEnvironment environment;
public DownloadController(IWebHostEnvironment environment)
{
this.environment = environment;
}
[Route("api/getfiles")]
public IActionResult GetFiles()
{
try
{
var rslt = new List<string>();
var files = Directory.GetFiles(Path.Combine(environment.WebRootPath + @"\share"));
foreach (var i in files)
{
rslt.Add(Path.GetFileName(i));
}
return Content(JsonSerializer.Serialize(rslt.ToArray()), "application/json", Encoding.UTF8);
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
[Route("api/download/file")]
public async Task<IActionResult> DownloadDocument(IFormFile file)
{
try
{
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
byte[] buffer = memoryStream.ToArray();
var fileName = JsonSerializer.Deserialize<string>(Encoding.ASCII.GetString(buffer));
var filePath = Path.Combine(environment.WebRootPath + @"\share", fileName);
return File(System.IO.File.ReadAllBytes(filePath), "application/octet-stream", fileName);
};
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
}
}
アップロードしたファイル一覧を表示し、任意のファイルをダウンロードする画面を作りたいため、Pagesフォルダに追加→Razorコンポーネントを選択し、Download.razorを作成します。
できたDownload.razorをざっくり以下のように修正します。
Download.razor(クリックで展開) Download.razor(クリックで圧縮)
@page "/download"
@using System.Text.Json
@inject IJSRuntime JSRuntime
@inject IHttpClientFactory ClientFactory
@foreach (var i in files)
{
<button @onclick="(s => ButtonClick(i))">@i</button>
}
@code {
List<string> files = new List<string>();
protected override async Task OnParametersSetAsync()
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7281" + "/api/getfiles");
var client = ClientFactory.CreateClient();
var response = await client.SendAsync(request);
var getVal = await response.Content.ReadAsStringAsync();
files.AddRange(JsonSerializer.Deserialize<string[]>(getVal));
}
async void ButtonClick(string fileName)
{
var content = new MultipartFormDataContent();
content.Add(new StringContent(JsonSerializer.Serialize<string>(fileName)), "file", "file.json");
var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7281" + "/api/download/file");
var client = ClientFactory.CreateClient();
request.Content = content;
var response = await client.SendAsync(request);
var getVal = await response.Content.ReadAsStreamAsync();
using var streamRef = new DotNetStreamReference(getVal);
await JSRuntime.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
}
}
Download.razorにアクセスできるようにするために、Shared/NavMenu.razorを以下のように修正します。
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="upload">
<span class="oi oi-data-transfer-upload" aria-hidden="true"></span> Upload
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="download">
<span class="oi oi-data-transfer-download" aria-hidden="true"></span> Download
</NavLink>
</div>
</nav>
</div>
ここまできたら実行しUploadで任意のファイルをアップロードします。(今回は困った18.pngをアップロード)
ファイルアップロード後、Downloadに遷移するとUploadで選択したファイル名のボタンが存在しています。(困った24.pngは前回記事で上げたものです。)
任意のボタンを押下しダウンロードが完了したらアップロードしたファイルがダウンロードされているはずです。
Lesson.4 あとがき
以上!!