ASP.NET MVC 將上傳檔案儲存在 SQL Server 資料庫 (Save Uploaded Fiels Into Database)

2023-02-13

說明 ASP.NET MVC 開發,如何將上傳的檔案儲存於 SQL Server 資料庫當中,以如何取回以檔案的方式提供下載使用 😎

logo

說明

建立 Model

Models/UploadFile.cs

public class UploadFile
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int FileId { get; set; }
    public string FileName { get; set; }
    public string Extension { get; set; }
    public byte[] FileContent { get; set; }
    public DateTime UploadDateTime { get; set; }
}

建立 DBContext

Models/AppDataLocalDbContext.cs

public class AppDataLocalDbContext : DbContext
{
    public AppDataLocalDbContext() : base("name=AppDataLocalDb")
    {

    }
    public DbSet<UploadFile> UploadFiles { get; set; }

}

在建構子上使用 name 指定資料庫的連線字串名稱,並且在 Web.config 進行相關設定:

<connectionStrings>
  <add name="AppDataLocalDb"
  connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\AppDataLocalDb.mdf;Initial Catalog=AppDataLocalDb;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" providerName="System.Data.SqlClient" />
</connectionStrings>

其中藉由 AttachDbFilename=|DataDirectory|\AppDataLocalDb.mdf,指定將 mdf 檔案儲存在 App_Data 的資料夾當中。

建立 Controller

Controller/FileController.cs

public class FileController : Controller
{
    private readonly AppDataLocalDbContext context = new AppDataLocalDbContext();

    public ActionResult Index()
    {
        return View(context.UploadFiles.ToList());
    }

    ...
}
<table class="table table-bordered">
    <tr>
        <th>File Name</th>
        <th>Extension</th>
        <th>Length</th>
        <th>DateTime</th>
    </tr>
    @foreach (var file in Model)
    {
        <tr>
            <td>@file.FileName</td>
            <td>@file.Extension</td>
            <td>@Html.ActionLink(
              file.FileContent.Length.ToString(),
              "DownloadFile", "File",
              new { fileId = file.FileId }, null)</td>
            <td>@file.UploadDateTime</td>
        </tr>
    }
</table>

Index Action 作為首頁,負責簡易的呈現目標上傳的檔案以及提供上傳檔案的介面。

[HttpPost]
public ActionResult UploadFile(HttpPostedFileBase uploadFile)
{
    byte[] fileBytes;
    using (var stream = uploadFile.InputStream)
    {
        fileBytes = new byte[stream.Length];
        stream.Read(fileBytes, 0, (int)stream.Length);
    }

    context.UploadFiles.Add(new UploadFile
    {
        FileName = Path.GetFileNameWithoutExtension(uploadFile.FileName),
        FileContent = fileBytes,
        Extension = Path.GetExtension(uploadFile.FileName),
        UploadDateTime = DateTime.Now
    });

    context.SaveChanges();

    return RedirectToAction("Index");
}
@using (Html.BeginForm("UploadFile", "File", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div class="col-4">
        <div class="mb-3">
            <label for="uploadFile" class="form-label">Default file input example</label>
            <input class="form-control" type="file" id="uploadFile" name="uploadFile">
        </div>
    </div>
    <button type="submit" class="btn btn-outline-secondary">Upload</button>
}

UploadFile Action 處理使用者上傳的檔案,要注意搭配 View 使用的 Form 以及使用的 enctype (multipart/form-data)。

而將檔案儲存在資料庫的處理核心也在此,就是藉由 byte[] 的資料型別,搭配 InputStream.Read 的方式將上傳的圖片串流轉為 Binary 陣列的方式儲存在資料庫當中。

public ActionResult DownloadFile(int fileId)
{
    var file = context.UploadFiles.FirstOrDefault(f => f.FileId == fileId);

    if (file == null)
    {
        return HttpNotFound();
    }

    return File(file.FileContent, "application/pdf", $"{file.FileName}{file.Extension}");
}

DownloadFile Action 提供檔案下載的處理方式,藉由 FileResult 可以簡單的處理下載。

需要注意的是以上的檔案上傳以及下載都沒有針對資安去做更多的實踐,相關資訊可以參考 ASP.NET MVC 5 實作更安全的檔案上傳功能 (ASP.NET MVC Safer File Upload Implements) 以及 ASP.NET MVC 5 實作更安全的檔案下載功能 (ASP.NET MVC Safer Downloads Implements)

組態設定

預設上 IIS Express 會限制最大的檔案大小,如果想要客製,可以藉由在 Web.config 進行調整,分別設定 maxAllowedContentLength 以及 maxRequestLength (以下範例程式碼是調整為 30MB)。

IIS 檔案上傳的大小限制 File Upload Limit (MaxRequestLength, MaxAllowedContentLength)

<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="31457280"/>
    </requestFiltering>
  </security>
</system.webServer>

<system.web>
    <httpRuntime targetFramework="4.8" maxRequestLength="307200"/>
</system.web>

相關連結

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

Visual Studio 入門教學