微软最新的.net 6文档中专门有一章节介绍文件上传相关的知识(参考文献1),同时配套有示例代码和项目,示例项目中包含的内容很多,有缓冲方式上传、流式上传、单个文件上传、多个文件上传、Razor页面上传、上传到数据库、上传到物理文件夹、带过滤器的上传等,内容太多,学起来也不方便。准备从微软示例项目中逐步剥代码,学到哪里就剥到哪里,本文先从最简单的Razor页面上传单个文件到物理文件夹开始学习。
运行下列名称创建webapp项目
dotnet new webapp -o UploadFileByRazorPage
code -r UploadFileByRazorPage
项目创建后,不需要改动Program.cs中的代码,只用在appsettings.json文件中增加一个物理文件保存地址的配置项即可。
"StoredFilesPath": "/home/XXX/文档/MyPrograms/FileBuffer"
关于缓冲和流式的区别,参考文献1中介绍的比较清楚,本文不在赘述。缓冲方式上传文件主要使用IFormFile接口处理或保存文件,本文中使用FileName属性获取上传文件的名称,使用CopyToAsync函数获取并保存文件内容。
直接将项目默认创建的Index.cshtml和Index.cshtml.cs参照微软示例修改为文件上传页面。定义FileUpload属性用于保存缓冲文件(该属性类型定义中包含IFormFile属性),同时将FileUpload属性绑定到页面表单中。初次之外最重要的函数就是OnPostUploadAsync,该函数接收表单的post请求,并将文件保存到本地文件夹中。微软示例中提供有专门的FileHelpers类用于文件检查及处理,本文精简其代码,并嵌入到OnPostUploadAsync函数中,函数实现代码如下所示:
public BufferedSingleFileUploadPhysical? FileUpload { get; set; }
public async Task<IActionResult> OnPostUploadAsync()
{
if (!ModelState.IsValid)
{
Result = "Please correct the form.";
return Page();
}
byte[] formFileContent=null;
try
{
using (var memoryStream = new MemoryStream())
{
await FileUpload.FormFile.CopyToAsync(memoryStream);
if (memoryStream.Length == 0)
{
ModelState.AddModelError(FileUpload.FormFile.FileName,"file is empty.");
}
formFileContent=memoryStream.ToArray();
}
}
catch (Exception ex)
{
ModelState.AddModelError(FileUpload.FormFile.FileName,
"file upload failed. " + $"Please contact the Help Desk for support. Error: {ex.HResult}");
}
if (!ModelState.IsValid)
{
Result = "Please correct the form.";
return Page();
}
var filePath = Path.Combine(
_targetFilePath, FileUpload.FormFile.FileName);
using (var fileStream = System.IO.File.Create(filePath))
{
await fileStream.WriteAsync(formFileContent);
}
Result = "File Upload Successfully.";
return Page();
}
接着是Index.cshtml页面,页面中的表单仅包含文件上传标签,需要特别说明的是表单的enctype要指定为"multipart/form-data"才行,其它没有什么特别的。
<form enctype="multipart/form-data" method="post">
<dl>
<dt>
<label asp-for="FileUpload.FormFile"></label>
</dt>
<dd>
<input asp-for="FileUpload.FormFile" type="file" />
<span asp-validation-for="FileUpload.FormFile"></span>
</dd>
</dl>
<input asp-page-handler="Upload" class="btn" type="submit" value="上传文件" />
</form>
最后的程序执行效果,从下面图形可以看到,可以将选定的文件上传到指定物理文件夹中。
参考文献
[1]https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/file-uploads?view=aspnetcore-6.0
[2]https://docs.microsoft.com/zh-CN/dotnet/api/microsoft.aspnetcore.http.iformfile?view=aspnetcore-6.0