iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
0
Modern Web

今晚,我想來點Blazor系列 第 26

Day 26:Blazor WebAssembly 上傳檔案

  • 分享至 

  • twitterImage
  •  

Blazor表單這篇有提到,內建的Input元件只有下列幾個:

  • InputCheckbox
  • InputDate
  • InputNumber
  • InputSelect
  • InputText
  • InputTextArea

隨著.NET 5.0 RC1版本的到來,Blazor增加3個Input元件可以使用,包括:

  • InputFile
  • InputRadioInputRadio
  • InputRadioGroup

今天這篇我們就在Blazor WebAssembly專案,使用InputFile元件來進行上傳圖片功能。

Visual Studio 2019 Preview 3

因為InputFile是NET 5.0 RC1版本才有的元件,因此要使用的話需先安裝Visual Studio 2019 16.8 Preview 3以上版本來使用.NET 5.0 RC1。安裝完之後,就開始建立我們的Blazor WebAssembly專案。

建立專案

https://ithelp.ithome.com.tw/upload/images/20201010/20130058cPByTyLOae.jpg

  • 在建立專案時,記得將版本選到.NET 5.0,才有InputFile元件可用
  • 因為要將上傳的圖片傳到後端資料夾,這邊就一併建立後端的Server專案。

後端Api

因為Blazor WebAssembly是跑在瀏覽器,無法像Blazor Server一樣,可以直接存取wwwroot資料夾,因此需要透過api將圖片傳到Server端,因此先進行Api部分。

建立UploadedFile class,因為這個UploadedFile在Client和Server都會用到,所以建立在Shared專案內

public class UploadedFile
    {
        public string FileName { get; set; }
        public byte[] FileContent { get; set; }
    }

UploadController

[Route("api/[controller]")]
    [ApiController]
    public class UploadController : ControllerBase
    {
        private readonly IWebHostEnvironment env;

        public UploadController(IWebHostEnvironment env)
        {
            this.env = env;
        }

        [HttpPost]
        public void Post(UploadedFile uploadedFile)
        {
           try
            {
                var path = $"{env.WebRootPath}\\{uploadedFile.FileName}";               
                var fs = System.IO.File.Create(path);
                fs.Write(uploadedFile.FileContent, 0, uploadedFile.FileContent.Length);
                fs.Close();

                return Ok();
            }
            catch
            {
                return BadRequest("Save File Failed");
            }
        }
    }
  • UploadController的Post方法中,用File類別將傳來的圖檔存到wwwroot底下
  • 為了demo方便這邊沒有做任何檢查,實務上必須要加上檔案格式、大小等等必要的程式碼做檢查還有錯誤處理。

前端上傳畫面

<h1>Blazor Upload Image Demo</h1>

<div class="row">
    <div class="col-sm-6">
        <form @onsubmit="OnSubmit">
            <div class="custom-file my-3">
                <InputFile OnChange="FileChangeHandler" id="customFile" />
                <label class="custom-file-label" for="customFile">Choose file</label>
            </div>

            @if (ImgFile != null)
            {
                <img src="@imageDataUri" class="img-fluid mb-3" />
                <h5>@message</h5>
            }

            <button type="submit" class="btn btn-primary">上傳</button>
        </form>
    </div>    
</div>
  • 表單中的上傳檔案元件,使用InputFile元件,並註冊OnChange事件
  • <img>則是在上傳圖片後,使用Data Uri方式放入base64編碼的圖片檔,讓使用者可以預覽

@code程式碼

@code {       

    //上傳圖片訊息
    public string message { get; set; } = string.Empty;

    //Data:Uri Base 64 圖片
    public string imageDataUri { get; set; }

    public IBrowserFile ImgFile;

    private async Task FileChangeHandler(InputFileChangeEventArgs e)
    {
        if (e.FileCount > 0)        
            message = $"選擇了{e.FileCount}張圖片。(檔名:{e.File.Name})";   

        var format = "image/jpeg";
        ImgFile = e.File;

        var imageFile = await ImgFile.RequestImageFileAsync(format, 640, 480);

        using var fileStream = imageFile.OpenReadStream();
        using var memoryStream = new MemoryStream();
        await fileStream.CopyToAsync(memoryStream);

        imageDataUri = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}";       
    }

    private async Task OnSubmit()
    {
        if(ImgFile != null)
        {
            using Stream stream = ImgFile.OpenReadStream();
            using MemoryStream ms = new MemoryStream();
            await stream.CopyToAsync(ms);


            UploadedFile uploadedFile = new UploadedFile();
            uploadedFile.FileName = ImgFile.Name;
            uploadedFile.FileContent = ms.ToArray();

            var response = await httpClient.PostAsJsonAsync<UploadedFile>("/api/Upload", uploadedFile);
            
            if (response.IsSuccessStatusCode)            
                await js.InvokeVoidAsync("alert", "上傳成功");            
            else            
                await js.InvokeVoidAsync("alert", "上傳失敗,請再試一次");                          
                        
        }
    }
}

FileChangeHandler method:選擇完上傳圖檔後,顯示訊息並且將圖檔轉成DataUri base64編碼
OnSubmit method:用UploadedFile物件把檔名和轉成byte[]的content包起來傳到api,並用js alert顯示結果

上傳一張圖片
https://ithelp.ithome.com.tw/upload/images/20201010/2013005870eyr91pdc.jpg

可以看到Server/wwwroot底下有這張圖片囉https://ithelp.ithome.com.tw/upload/images/20201010/20130058E2vJa9Fm3S.jpg

專案原始碼:https://github.com/CircleLin/BlazorFileUpload


上一篇
Day 25:Blazor jwt登入範例(4) -- 驗證及授權
下一篇
Day 27:Blazor x Chart.js
系列文
今晚,我想來點Blazor30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言