演示如何在 ASP.NET Core 中实现文件上传。

准备测试页面

使用 VS Code 打开 Module4\Tutorial_Lab_5 文件夹下的 MyWebApp 项目。

运行项目,可以看到如下页面:
4.5.5 Lab5 文件上传 - 图1

关于静态文件

图片、CSS、脚本(.js 文件)和 HTML 页面(.html 文件)都是静态(static)内容。静态内容不参与编译过程。当用户通过网页加载静态内容时,内容将直接返回至用户。

ASP.NET Core 程序中默认启用了静态文件中间件。通过 Startup.cs 文件 Configure 方法里面的 app.UseStaticFiles(); 进行了配置。

现在介绍一下 wwwroot 文件夹。该文件夹表示 Web 程序的根目录(或 ~)。可以看到我们的 Default.png 就在 wwwroot 下的 images 文件夹里面,所以我们可以通过 Images/Default.png 在 HTML 源码中引用它。

实现文件上传

我们的任务是添加适当的视图和操作,使用户能够上传不同国家的国旗。

Controller

在 HomeController.cs 里面添加如下引用:

  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using Microsoft.AspNetCore.Hosting;
  5. using Microsoft.AspNetCore.Http;

再在 HomeController 里面添加 Action 代码:

  1. private IHostingEnvironment _environment;
  2. public HomeController(IHostingEnvironment env)
  3. {
  4. _environment = env;
  5. }
  6. [HttpGet]
  7. public IActionResult UpdateNationalFlag(string code)
  8. {
  9. var country = DataSource.Countries
  10. .SingleOrDefault(c => c.Code.Equals(code, StringComparison.CurrentCultureIgnoreCase));
  11. return View(country);
  12. }
  13. [HttpPost]
  14. public IActionResult UpdateNationalFlag(string code, IFormFile nationalFlagFile)
  15. {
  16. if (nationalFlagFile == null || nationalFlagFile.Length == 0)
  17. return RedirectToAction(nameof(Index));
  18. var targetFileName = $"{code}{Path.GetExtension(nationalFlagFile.FileName)}";
  19. var relativeFilePath = Path.Combine("images", targetFileName);
  20. var absolutFilePath = Path.Combine(_environment.WebRootPath, relativeFilePath);
  21. var country = DataSource.Countries
  22. .SingleOrDefault(c => c.Code.Equals(code, StringComparison.CurrentCultureIgnoreCase));
  23. country.NationalFlagPath = relativeFilePath;
  24. using (var stream = new FileStream(absolutFilePath, FileMode.Create))
  25. {
  26. nationalFlagFile.CopyTo(stream);
  27. }
  28. return RedirectToAction(nameof(Index));
  29. }

env 参数的值由依赖注入设置。我们需要 _environment 字段的原因是因为我们需要 _environment.WebRootPath 的值来拼接上传文件的存储路径。

注:此处做了功能分隔,分离了 NationalFlag 的编辑和更新。[HttpGet] 将用户导向上传页面,[HttpPost] 执行上传更新操作。

View

在 Views/Home 文件夹下创建 UpdateNationalFlag.cshtml:

  1. @model MyWebApp.Models.Country
  2. <html>
  3. <h1>Update Nation Flag</h1>
  4. <form action="UpdateNationalFlag" method="POST" enctype="multipart/form-data">
  5. <input type="hidden" name="code" value="@Model.Code"/>
  6. <b>Code:</b><span>@Model.Code</span><br/>
  7. <b>Name:</b><span>@Model.Name</span><br/>
  8. <b>Continent:</b><span>@Model.Continent</span><br/>
  9. <b>Choose Local File:</b>
  10. <input type="file" name="nationalFlagFile"/><br/>
  11. <input type="submit" value="Update"/>
  12. </form>
  13. </html>

代码中需要注意的点:

  • 使用

    标签上传文件

  • action 属性名必须与 [HttpPost] 标注的操作名相同

  • 提交 method 必须设置为 POST

  • enctype 属性必须设置为 multipart/form-data

  • unique 的国家 ID 必须一并返回给服务器。示例用的是 hidden 的 input,这也是最常用的方式

  • 文件上传 input 的 name 属性必须与 Action 中的参数名一致

至此,我们可以通过手动输入 http://localhost:5000/home/UpdateNationalFlag?code=usa 进行国旗上传。当然为了便于使用,我们也可以更新 Index 页面,给 table 添加一行:

  1. 表头一行(header)添加 <th>Update</th>

  2. 表体(body)添加 <td>@Html.ActionLink("Update", "UpdateNationalFlag", new {code=c.Code})</td>

程序运行效果如下:
4.5.5 Lab5 文件上传 - 图2