Asp.Net Core 轻松学-一行代码搞定文件上传
程序员文章站
2023-11-15 23:42:58
在 Web 应用程序开发过程中,总是无法避免涉及到文件上传,这次我们来聊一聊怎么去实现一个简单方便可复用文件上传功能;通过创建自定义绑定模型来实现文件上传。 ......
前言
在 web 应用程序开发过程中,总是无法避免涉及到文件上传,这次我们来聊一聊怎么去实现一个简单方便可复用文件上传功能;通过创建自定义绑定模型来实现文件上传。
1. 实现自定义绑定模型
- 1.1 在 asp.net core mvc 中,内置了很多种绑定模型,让我们可以很方便的去使用,比如下面常用的几种绑定模型
frombodyattribute fromfromattribute fromqueryattribute fromheaderattribute fromservicesattribute fromrouteattribute
- 常见用法比如
[httppost] public async task<iactionresult> postinfo([frombody]userinfo user,[fromquery] string city) { ... }
- 查看以上绑定模型,唯独缺少一个 fromfileattribute ,下面就来实现一个自己的 fromfileattribute
public class fromfileattribute : attribute, ibindingsourcemetadata { public bindingsource bindingsource => bindingsource.formfile; }
- 非常简单,就三行代码,完全照抄系统内置的绑定模型,唯一不同的就是指定 bindingsource 为 bindingsource.formfile。
2. 实现一个上传文件实体类,专门用于接收客户端参数
- 2.1 创建 userfile
public class userfile { public string filename { get; set; } public long length { get; set; } public string extension { get; set; } public string filetype { get; set; } private readonly static string[] filters = { ".jpg", ".png", ".bmp" }; public bool isvalid => !string.isnullorempty(this.extension) && filters.contains(this.extension); private iformfile file; public iformfile file { get { return file; } set { if (value != null) { this.file = value; this.filetype = this.file.contenttype; this.length = this.file.length; this.extension = this.file.filename.substring(file.filename.lastindexof('.')); if (string.isnullorempty(this.filename)) this.filename = this.filename; } } } public async task<string> saveas(string destinationdir = null) { if (this.file == null) throw new argumentnullexception("没有需要保存的文件"); if (destinationdir != null) directory.createdirectory(destinationdir); var newname = datetime.now.ticks; var newfile = path.combine(destinationdir ?? "", $"{newname}{this.extension}"); using (filestream fs = new filestream(newfile, filemode.createnew)) { await this.file.copytoasync(fs); fs.flush(); } return newfile; } }
- userfile 是一个带保持文件行为的实体类,该类的公共属性用于从表单域中接收和属性名称相同的表单值,其中公共属性 file 用于接收文件,并在设置值的时候去做一些其它属性初始化的工作,比如文件长度和扩展名、文件类型
- 其中还实现了一个简单的文件过滤器,判断客户端上传的文件是否属于服务端允许上传的文件扩展名
- 最后 saveas(string destinationdir = null) 通过传入指定目录,将文件保存,并返回保存后的文件绝对路径
3. 上传文件
- 3.1 下面就定义一个简单的 api 接口,用于测试上传文件
[httppost] public async task<iactionresult> post([fromfile]userfile file) { if (file == null || !file.isvalid) return new jsonresult(new { code = 500, message = "不允许上传的文件类型" }); string newfile = string.empty; if (file != null) newfile = await file.saveas("/data/files/images"); return new jsonresult(new { code = 0, message = "成功", url = newfile }); }
3.2 首先是在 post([fromfile]userfile file) 中使用上面创建的 fromfileattribute 对模型 userfile 进行绑定,然后验证文件是否正确,接下来通过 file.saveas("/data/files/images"); 保存文件
3.3 上传代码非常简单,几乎到了无法精简的程度,最终发挥作用的就是 file.saveas 操作
4. 上传测试
- 4.1 现在通过控制台启动服务
- 4.2 使用 postman 模拟表单上传文件
- 4.3 上传成功,现在来查看目录下是否有文件
结语
- 在上传表单中,我们定义了附件的名称为 file 对应绑定模型的公共属性 file,这样模型就可以自动获得该文件
- 表单中还传递了另外一个字段 filename,对应绑定模型的公共属性 filename,实现自定义文件友好显示名称
- 通过自定义模型绑定,实现了快速上传文件功能,该功能只能用于上传小文件,对于大文件,还是需要实现分片上传,或者使用 cdn 等服务商的接口