前言

在網頁的開發中,上傳檔案是一個非常常見的需求,本章節會介紹在開發 Blazor 時,該怎麼來實現檔案上傳的功能,Server 和 WebAssembly 雖然細節上有些差異但大致上是相通的

檔案流程

  • Blazor Server 與後端伺服器的溝通是透過 SignalR 溝通,檔案是透過 SignalR 傳輸到 .NET 上
  • Blazor WebAssembly 檔案資料會直接串流到 .NET 程式碼上

上傳檔案 (Blazor WebAssembly)

建立一個新的元件,名稱為 FileUpload

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@using System.Net.Http.Headers
@inject HttpClient Http

@page "/FileUpload"

<h3>檔案上傳</h3>

<InputFile OnChange="@OnInputFileChange" />

@code {
    private bool shouldRender;
    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles())
        {

            var fileContent = new StreamContent(file.OpenReadStream(1024 * 1000));
            fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
            content.Add(fileContent,"\"files\"",file.Name);
        }

        await Http.PostAsync("api/File", content);
        shouldRender = true;
    }
}

其中的 1024 * 100 是我要調整上傳檔案的大小的限制,預設為 500 KB 為了方便講解,沒有對檔案做必要的安全性處理,正式使用時請依照安全性原則處理檔案上傳 相關的資料可以查看官方文件 安全性考量

這邊建立了一個 type = fileinput,並且在檔案變動時,發出Request將檔案串流到至伺服器端

完成 razor 元件的部分後,我們來處理 API Controller 的內容,建立一個 API 控制器名稱為 FileController,並撰寫內容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    [Route("api/[controller]")]
    [ApiController]
    public class FileController : ControllerBase
    {
        private readonly IWebHostEnvironment _env;

        public FileController(IWebHostEnvironment env)
        {
            _env = env;
        }

        [HttpPost]
        public async Task<IActionResult> PostFile([FromForm] IEnumerable<IFormFile> files)
        {
            var filesProcessed = 0;

            foreach (var file in files)
            {
                var path = Path.Combine(_env.ContentRootPath,
                    _env.EnvironmentName, "image",
                    file.FileName);
                await using FileStream fs = new(path, FileMode.Create);
                await file.CopyToAsync(fs);
                filesProcessed++;
            }
            return Ok();

        }
    }

上傳檔案 (Blazor Server)

在 Blazor Server 上的檔案上傳大同小異,只是要在 Program.cs 註冊HttpClient

1
builder.Services.AddHttpClient();

並且對剛剛 WebAssembly 的 Componet 做修改

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@inject IHttpClientFactory ClientFactory
@using System.Net.Http.Headers

@page "/FileUpload"

<h3>檔案上傳</h3>

<InputFile OnChange="@OnInputFileChange" />
@code {
    private bool shouldRender;
    protected override bool ShouldRender() => shouldRender;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        using var content = new MultipartFormDataContent();

        foreach (var file in e.GetMultipleFiles())
        {
            var fileContent = new StreamContent(file.OpenReadStream(1024 * 1000));
            fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
            content.Add(fileContent, "\"files\"", file.Name);
        }
        var client = ClientFactory.CreateClient();
        await client.PostAsync("https://localhost:7197/api/File", content);
        shouldRender = true;
    }
}

有發現不一樣的地方嗎? @inject HttpClient Http 變成 @inject IHttpClientFactory ClientFactory

而API的部分是相同的所以可以直接參照上方的 API Controller

小結

這邊透過簡單的方式去示範檔案上傳的做法,在真實環境中務必注意安全性,以免對資料造成損失,下一章會介紹兩種 Blazor 專案要怎麼呼叫 WebAPI