Asp.Net Core 轻松学-一行代码搞定文件上传 JSONHelper
Asp.Net Core 轻松学-一行代码搞定文件上传
前言
在 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 等服务商的接口
示例代码下载
https://files.cnblogs.com/files/viter/Ron.UploadFile.zip
JSONHelper
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Text;
using System.Web.Script.Serialization;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
<br><br>[Serializable] public static class JSONHelper { /// <summary> /// 对象转JSON /// </summary> /// <param name="obj">对象</param> /// <returns>JSON格式的字符串</returns> public static string ObjectToJSON( object obj) { JavaScriptSerializer jss = new JavaScriptSerializer(); try { return jss.Serialize(obj); } catch { } return null ; } /// <summary> /// /// JSON文本转对象,泛型方法 /// </summary> /// <typeparam name="T">类型</typeparam> /// <param name="jsonText">JSON文本</param> /// <returns>指定类型的对象</returns> public static T JSONToObject<T>( string jsonText) { JavaScriptSerializer jss = new JavaScriptSerializer(); try { return jss.Deserialize<T>(jsonText); } catch {} return default (T); } public static string ObjectToJsonDateTime( object obj) { JavaScriptSerializer jss = new JavaScriptSerializer(); jss.RegisterConverters( new JavaScriptConverter[] { new DateTimeConverter() }); try { return jss.Serialize(obj); } catch { } return null ; } }<br><br><br> |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Script.Serialization; public class DateTimeConverter : JavaScriptConverter { public override object Deserialize(IDictionary< string , object > dictionary, Type type, JavaScriptSerializer serializer) { return new JavaScriptSerializer().ConvertToType(dictionary, type); } public override IDictionary< string , object > Serialize( object obj, JavaScriptSerializer serializer) { if (!(obj is DateTime)) { return null ; } return new CustomString(((DateTime)obj).ToString( "yyyy-MM-dd HH:mm:ss" )); } public override IEnumerable<Type> SupportedTypes { get { return new [] { typeof (DateTime) }; } } private class CustomString : Uri, IDictionary< string , object > { public CustomString( string str) : base (str, UriKind.Relative) { } void IDictionary< string , object >.Add( string key, object value) { throw new NotImplementedException(); } bool IDictionary< string , object >.ContainsKey( string key) { throw new NotImplementedException(); } ICollection< string > IDictionary< string , object >.Keys { get { throw new NotImplementedException(); } } bool IDictionary< string , object >.Remove( string key) { throw new NotImplementedException(); } bool IDictionary< string , object >.TryGetValue( string key, out object value) { throw new NotImplementedException(); } ICollection< object > IDictionary< string , object >.Values { get { throw new NotImplementedException(); } } object IDictionary< string , object >. this [ string key] { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } void ICollection<KeyValuePair< string , object >>.Add(KeyValuePair< string , object > item) { throw new NotImplementedException(); } void ICollection<KeyValuePair< string , object >>.Clear() { throw new NotImplementedException(); } bool ICollection<KeyValuePair< string , object >>.Contains(KeyValuePair< string , object > item) { throw new NotImplementedException(); } void ICollection<KeyValuePair< string , object >>.CopyTo(KeyValuePair< string , object >[] array, int arrayIndex) { throw new NotImplementedException(); } int ICollection<KeyValuePair< string , object >>.Count { get { throw new NotImplementedException(); } } bool ICollection<KeyValuePair< string , object >>.IsReadOnly { get { throw new NotImplementedException(); } } bool ICollection<KeyValuePair< string , object >>.Remove(KeyValuePair< string , object > item) { throw new NotImplementedException(); } IEnumerator<KeyValuePair< string , object >> IEnumerable<KeyValuePair< string , object >>.GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } } } |
Asp.Net Core 轻松学-一行代码搞定文件上传 JSONHelper的更多相关文章
- Asp.Net Core 轻松学-一行代码搞定文件上传
前言 在 Web 应用程序开发过程中,总是无法避免涉及到文件上传,这次我们来聊一聊怎么去实现一个简单方便可复用文件上传功能:通过创建自定义绑定模型来实现文件上传. 1. 实现自定义绑定模型 1 ...
- 【自动化专题】selenium如何轻松搞定文件上传
使用selenium做自动化时,我们经常会遇到的一个让人头疼的问题就是文件上传. 问题的难点在于selenium无法识别并操作Windows窗口,若我们可以绕过弹出框直接把文件信息上传给选择按钮,难点 ...
- Asp.Net Core 轻松学系列-1阅读指引目录
https://www.cnblogs.com/viter/p/10474091.html 目录 前言 1. 从安装到配置 2. 业务实现 3. 日志 4. 测试 5. 缓存使用 6.网络和通讯 7. ...
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
- Asp.Net Core 轻松学-使用MariaDB/MySql/PostgreSQL和支持多个上下文对象
前言 在上一篇文章中(Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库)[https://www.cnblogs.com/viter/p/10243577.html],介 ...
- Asp.Net Core 轻松学-多线程之Task(补充)
前言 在上一章 Asp.Net Core 轻松学-多线程之Task快速上手 文章中,介绍了使用Task的各种常用场景,但是感觉有部分内容还没有完善,在这里补充一下. 1. 任务的等待 在使用 ...
- Asp.Net Core 轻松学-利用文件监视进行快速测试开发
前言 在进行 Asp.Net Core 应用程序开发过程中,通常的做法是先把业务代码开发完成,然后建立单元测试,最后进入本地系统集成测试:在这个过程中,程序员的大部分时间几乎都花费在开发.运行 ...
- 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...
- C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌
1. IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...
随机推荐
- Visual Studio Code 构建C/C++开发环境
转自: https://blog.csdn.net/lidong_12664196/article/details/68928136#visual-sutdio-code%E4%BB%A5%E5%8F ...
- 使用svgdeveloper 和 svg-edit 绘制svg地图
目录: 1. 描述 2. 准备工作 3. 去除地图模板上的水印(可跳过) 4. 方法一.SVGDeveloper 5. 方法二.SVG-Edit 1. 描述编辑 有的时候我们需要自定义地图,本文提 ...
- javascript制作公式编辑器,函数编辑器和图形绘制
自己是电子信息方向的,因此总是需要处理大量的电路实验.电路数据和电路仿真处理,每次处理数据时候还需要同样的数据很多遍, 又需要关于电路的频率响应和时域响应情况,所以一直有做一个这样公式编辑器的打算了. ...
- IOS之Block讲解
Block,称为代码块,它是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持,从ios4.0开始就很好的支持Block. Block很像匿名方法 ...
- Android -- Fragment注意事项
ViewPager+Fragment 让Fragment成为ViewPager的一页时,FragmentManager会一直保存管理创建好了的Fragment,即使当前不是显示的这一页,Fragmen ...
- 如何在模板中引用参数类中的一个特定member
C++模板有很多特性需要我们去挖掘,很多新的设计模式也都与模板使用相关,我们知道模板的一个基本特性就是可以根据传入的类型产生新的类型.围绕这个特性,可以衍生出很多的其它特性,比如自动为不同的类生成st ...
- linux cp覆盖每次都有提示
1.cp命令,目标已经存在,每次都提示是否覆盖,怎么办? 2.cp --help 可以看到选项-i的时候,才会提示,但是这里并没有-i,为什么每次都有提示? 3.原因是:这里执行的cp是一个别名,通过 ...
- Mysql 环境配置查询
Mysql 环境查询 1, 查看全部的引擎 a) Show engines 或者是进入到information_schama里面去查看ENGINES表 2, 查看当前用户 a) Select user ...
- 【转载】Remote System Explorer Operation总是运行后台服务,卡死eclipse解决办法
原来是eclipse后台进程在远程操作,就是右下角显示的“Remote System Explorer Operation”.折腾了半天,在Stack Overflow找到答案(源地址).把解决方案翻 ...
- javascript---对象和函数的引用、浅拷贝、深拷贝、递归
1.javascript 对象和函数的引用 <!doctype html> <html lang="en"> <head> <meta c ...