ASP.NET MVC 5 實作多檔案 / 複數檔案上傳功能 (ASP.NET MVC Upload Multiple Files)

2022-04-09

筆記 ASP.NET MVC 如何實作多檔案與複數檔案的上傳功能,讓使用者可以批次上傳檔案,不再需要逐一上傳囉,使用者體驗 Up 😲

logo

說明

Model

FiledUploaded.cs

using System.IO

public class FiledUploaded
{
    public FiledUploaded(HttpPostedFileBase file, string serverPath)
    {
        HashedName = System.Web.Helpers.Crypto.SHA256(file.FileName);
        FileName = file.FileName;
        FileSize = file.ContentLength;
        ServerPath = Path.Combine(serverPath + file.FileName);
        Extension = Path.GetExtension(file.FileName);
    }

    public string FileName { get; set; }
    public string HashedName { get; set; }
    public string ServerPath { get; set; }
    public int FileSize { get; set; }
    public string Extension { get; set; }
}

Controller

示範是使用同名 Action Upload 並以 GET Method 以及 POST Method 區別顯示的內容,如果是 POST Method 就顯示上傳的檔案內容。

多檔案上傳在 Conroller 的靈魂所在為 POST Method 參數要使用 HttpPostedFileBase[] 以陣列方式來接收使用者上傳的多個檔案。

public ActionResult Upload()
{
    return View();
}

[HttpPost]
public ActionResult Upload(HttpPostedFileBase[] files)
{
    // Check If Upload Nothing
    if (files[0] == null)
    {
        return RedirectToAction("Upload");
    }

    var fileUploads = new List<FiledUploaded> {  };

    foreach (var file in files)
    {
        var fileUpload =
          new FiledUploaded(file, Server.MapPath("~/Uploads/"));

        file.SaveAs(fileUpload.ServerPath);
        fileUploads.Add(fileUpload);
    }

    return View(fileUploads);
}

View

在 View 當中,多檔案上傳的靈魂於在於 File Input 必須要有 multiple 屬性,如此一來 Browser 就會允許使用者選擇多個檔案進行上傳。

Upload.cshtml

@model IList<MVCTemplate.Controllers.FiledUploaded>

@{
    ViewBag.Title = "Upload Features";
}

@using (
    Html.BeginForm(
      "Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })
    )
{
    <div class="mb-1">
        <label for="formFile" class="form-label">上傳檔案</label>
        @Html.TextBox("files", "", 
          new { type = "file", multiple = "multiple", @class = "d-block" })
        <br />
    </div>
    <div class="mb-3 d-flex">
        <ion-icon name="cloud-upload-outline" style="font-size: 2rem"></ion-icon>
        <input type="submit"
          value="上傳"
          class="btn btn-primary ml-3"
          id="uploadBtn"
          disabled />
        <br />
    </div>
}

本次範例上傳元件與上傳結果是相同頁面,因此利用 HTTP Method 判斷是否為 POST 以顯示上傳檔案的名稱及相關資訊

@if (Context.Request.HttpMethod == "POST")
{
<div class="row mb-5">
    @foreach (var file in Model)
    {
    <div class="col-4 d-flex mb-3">
        <div class="card">
            <div style="overflow: hidden; height: 200px">
                <img class="card-img-top" src="~/uploads/@file.FileName">
            </div>
            <div class="card-body">
                <h5 class="card-title">@file.FileName</h5>
                <p class="card-text">
                    @(file.FileSize / 1024) KB
                </p>
                <a href="#" class="btn btn-outline-danger">Like</a>
            </div>
        </div>
    </div>
    }
</div>
}

預設上使用者沒有選擇任何檔案也可以看上傳,雖然在後端 Action 有進行檢查,但在前端能夠防呆會讓使用者體驗更好,所以在 Upload 的 Submit Button 啟用 Disabled 屬性,並且使用 jQuery 偵測選擇上傳的檔案數合理時,才主動移除 Disabled 屬性。

同時也檢查如果使用者又調整為不上傳任何檔案時,自動為 Submit Button 加入 Disabled 屬性。

@section scripts{
<script>
    $(document).ready(function () {
        $('#files').change(function(){ 

            if ($('#files')[0].files.length > 0) {
                $('#uploadBtn').removeAttr('disabled');
            }
            else {
                $('#uploadBtn').attr('disabled', true)
            }
        })
    })
</script>  
}

精進作為

本篇主要是探討如何實作多檔案上傳,對於 Web 安全性的細節實作還有強化的空間,有興趣的朋友可以參考單檔上傳時的 Safer Practices ASP.NET MVC 5 實作更安全的檔案上傳功能 (ASP.NET MVC Safer File Upload Implements) 並加以應用在多檔案上傳 😀

參考資料

Vithal Wadje 在 C# Cornoer 所分享的Uploading Multiple Files In ASP.NET MVC

相關連結

ASP.NET MVC 從無到有打造一個應用系統