在 ASP.NET Core MVC中批量上传多个文件
admin
2021-06-03本文作者:梁桐铭- 微软最有价值专家(Microsoft MVP)
本文出自《从零开始学 ASP.NET Core 与 EntityFramework Core》目录
视频课程效果更佳:跨平台开发实战掌握 ASP.NET Core 与 EntityFramework Core
在 ASP.NET Core MVC 完成上传多个文件
在上个章节中,我们已经学习了单个文件的上传,本章我们将学习如果完成多文件的上传内容。
我们依然使用 添加学生的表单视图,当我们点击请选择照片按钮的时候,我们将会通过他来完成多文件的上传。
被我们选中的照片则会被存储到 Web 服务器上的wwwroot/images
文件夹中
提交信息后,我们能够在数据库Students表中,存储 Student 类的数据,包含Name,Email,Major,PhotoPath信息。
下面是数据库 Students 表中的信息,是通过 ASP.NET Core 中的迁移功能来创建的。
Id | 名字 | 电子邮件 | 主修科目 | 图片路径 |
---|---|---|---|---|
1 | 52ABP管理员 | 2 | info@ddxc.org | info.png |
2 | 梁桐铭 | 3 | ltm@ddxc.org | ltm.png |
为了实现多个文件的上传功能,我们需要添加修改和添加以下几个类文件。
StudentCreateViewModel 文件
public class StudentCreateViewModel
{
[Required(ErrorMessage = "请输入名字"), MaxLength(50, ErrorMessage = "名字的长度不能超过50个字符")]
[Display(Name = "名字")]
public string Name { get; set; }
[Required]
[Display(Name = "主修科目")]
public MajorEnum? Major { get; set; }
[Display(Name = "电子邮件")]
[RegularExpression(@"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$",
ErrorMessage = "邮箱的格式不正确")]
[Required(ErrorMessage = "请输入邮箱地址")]
public string Email { get; set; }
[Display(Name = "图像")]
public List<IFormFile> Photos { get; set; }
}
我们要将StudentCreateViewModel文件中的IFormFile类型的 Photos 的字段修改为 List<IFormFile>
。
- IFormFile 位于
Microsoft.AspNetCore.Http
命名空间中。 - 上传至服务器的文件可通过 IFormFile 接口通过模型绑定的形式进行访问。
- Photos 属性通过模型绑定接收上传的文件
- 因为要支持多个文件上传,我们将 Photos 属性的数据类型设置为
List<IFormFile>
更新 Create 视图的代码
@model StudentCreateViewModel
@{ ViewBag.Title = "创建学生信息"; }
要支持文件上传,请设置表单元素为enctype="multipart/form-data"
- enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。
- application/x-www-form-urlencoded 在发送前编码所有字符(默认)
- multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
- text/plain 空格转换为 "+" 加号,但不对特殊字符编码。 以上都是 Hhtml 的基础。
<form
enctype="multipart/form-data"
asp-controller="home"
asp-action="create"
method="post"
class="mt-3"
>
<div class="form-group row">
<label asp-for="Name" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Name" class="form-control" placeholder="请输入名字"/>
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label asp-for="Email" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input
asp-for="Email"
class="form-control"
placeholder="请输入邮箱地址"
/>
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<label asp-for="Major" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<select
asp-for="Major"
class="custom-select mr-sm-2"
asp-items="Html.GetEnumSelectList<MajorEnum>()"
>
<option value=""> 请选择</option>
</select>
<span asp-validation-for="Major" class="text-danger"></span>
</div>
</div>
@* 我们使用了asp-for的taghelper设置input的属性为"Photos"。
"Photos"属性类型是`List<IFormFile>`, 所以在运行的时候ASP.NET
Core会将该标签生成上传控件(input type=file) 而要支持多个文件上传,需要
multiple 属性支持*@
<div class="form-group row">
<label asp-for="Photos" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<div class="custom-file">
<input
asp-for="Photos"
multiple
class="form-control custom-file-input"
/>
<label class="custom-file-label">请选择照片...</label>
</div>
</div>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">创建</button>
</div>
</div>
@*以下JavaScript代码是必须的,它的作用是 -
如果选择了单个文件,则显示该文件的名称。 -
如果多个选择文件,然后显示文件数量。 *@ @section Scripts {
<script>
$(document).ready(function() {
$(".custom-file-input").on("change", function() {
//console.log($(this));
var fileLabel = $(this).next(".custom-file-label");
var files = $(this)[0].files;
if (files.length > 1) {
fileLabel.html("您已经选择了:" + files.length + " 个文件");
} else if (files.length == 1) {
fileLabel.html(files[0].name);
}
});
});
</script>
}
</form>
我们使用了 asp-for 的 taghelper 设置 input 的属性为"Photos"。
"Photos"属性类型是List<IFormFile>
, 所以在运行的时候 ASP.NET
Core 会将该标签生成上传控件(input type=file) 而要支持多个文件上传,需要
multiple 属性支持,参考以下代码:
<input asp-for="Photos" multiple class="form-control custom-file-input" />
生成 HTML 后
<input
multiple
class="form-control custom-file-input"
type="file"
id="Photos"
name="Photos"
/>
因为原有的
Student
领域模型已经不满足我们的业务呈现了,所以当前页面视图模型改用StudentCreateViewModel
。在结束
form
标签之前的 JavaScript 代码我们也做了修改,它的作用是,- 如果选择了单个文件,则显示该文件的名称。
- 如果多个选择文件,然后显示文件数量。
修改 Create 操作方法
我们回到HomeController
文件中,因为要让 Create()方法支持多文件上传,所以我们要对这个方法进行修改。修改规则如下:
- 判断用户是否上传了图片,如果没有上传图片路径信息为空。
- 所以我们要判断
StudentCreateViewModel
中的Photo
属性是否为空
- 所以我们要判断
- 如果有上传图片,则要进行规则验证。
- 所有的图片都必须上传到
wwwroot
中的images
文件夹中。- 而要获取
wwwroot
文件夹的路径,我们需要通过 ASP.NET Core 中的依赖注入注册HostingEnvironment
服务
- 而要获取
- 为了确保文件名是唯一的,文件名的生成规则为 GUID 值加一个下划线。
完整的上传文件代码如下:
[HttpPost]
public IActionResult Create(StudentCreateViewModel model)
{
if (ModelState.IsValid)
{
string uniqueFileName = null;
//如果传入模型对象中的Photo属性不为null,并且Count>0,则表示用户选择至少一个要上传的文件。
if (model.Photos != null && model.Photos.Count > 0)
{
//循环每个选定的文件
foreach (IFormFile photo in model.Photos)
{
//必须将图像上传到wwwroot中的images文件夹
//而要获取wwwroot文件夹的路径,我们需要注入 ASP.NET Core提供的HostingEnvironment服务
//通过HostingEnvironment服务去获取wwwroot文件夹的路径
string uploadsFolder = Path.Combine(hostingEnvironment.WebRootPath, "images");
//为了确保文件名是唯一的,我们在文件名后附加一个新的GUID值和一个下划线
uniqueFileName = Guid.NewGuid().ToString() + "_" + photo.FileName;
string filePath = Path.Combine(uploadsFolder, uniqueFileName);
//使用IFormFile接口提供的CopyTo()方法将文件复制到wwwroot/images文件夹
photo.CopyTo(new FileStream(filePath, FileMode.Create));
}
}
Student newStudent = new Student
{
Name = model.Name,
Email = model.Email,
Major = model.Major,
// 将文件名保存在student对象的PhotoPath属性中 它将保存到数据库 Students的 表中
PhotoPath = uniqueFileName
};
_studentRepository.Add(newStudent);
return RedirectToAction("details", new { id = newStudent.Id });
}
return View();
}
此HomeController
文件中的其余代码不需要上传文件。涉及到图片显示的视图页面为学生详情页面和学生列表页面,所以去修改对应的代码地方即可。
文章说明
如果您觉得我的文章质量还不错,欢迎打赏,也可以订阅我的视频哦
未得到授权不得擅自转载本文内容,52abp.com 保留版权
感谢您对我的支持