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)
    {
        ...
    }
    1. 查看以上绑定模型,唯独缺少一个 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<stringobject> dictionary, Type type, JavaScriptSerializer serializer)
        {
            return new JavaScriptSerializer().ConvertToType(dictionary, type);
        }
 
        public override IDictionary<stringobject> 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<stringobject>
        {
            public CustomString(string str) : base(str, UriKind.Relative)
            {
            }
 
            void IDictionary<stringobject>.Add(string key, object value)
            {
                throw new NotImplementedException();
            }
 
            bool IDictionary<stringobject>.ContainsKey(string key)
            {
                throw new NotImplementedException();
            }
 
            ICollection<string> IDictionary<stringobject>.Keys
            {
                get
                {
                    throw new NotImplementedException();
                }
 
            }
 
            bool IDictionary<stringobject>.Remove(string key)
            {
                throw new NotImplementedException();
            }
 
 
            bool IDictionary<stringobject>.TryGetValue(string key, out object value)
            {
                throw new NotImplementedException();
 
            }
 
            ICollection<object> IDictionary<stringobject>.Values
            {
 
                get
                {
                    throw new NotImplementedException();
                }
 
            }
 
            object IDictionary<stringobject>.this[string key]
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }
 
            void ICollection<KeyValuePair<stringobject>>.Add(KeyValuePair<stringobject> item)
            {
                throw new NotImplementedException();
            }
 
            void ICollection<KeyValuePair<stringobject>>.Clear()
            {
                throw new NotImplementedException();
            }
 
            bool ICollection<KeyValuePair<stringobject>>.Contains(KeyValuePair<stringobject> item)
            {
 
                throw new NotImplementedException();
 
            }
 
            void ICollection<KeyValuePair<stringobject>>.CopyTo(KeyValuePair<stringobject>[] array, int arrayIndex)
            {
                throw new NotImplementedException();
 
            }
 
            int ICollection<KeyValuePair<stringobject>>.Count
            {
                get
                {
                    throw new NotImplementedException();
                }
            }
 
            bool ICollection<KeyValuePair<stringobject>>.IsReadOnly
            {
                get
                {
                    throw new NotImplementedException();
                }
            }
 
            bool ICollection<KeyValuePair<stringobject>>.Remove(KeyValuePair<stringobject> item)
            {
                throw new NotImplementedException();
            }
 
            IEnumerator<KeyValuePair<stringobject>> IEnumerable<KeyValuePair<stringobject>>.GetEnumerator()
            {
                throw new NotImplementedException();
            }
 
            IEnumerator IEnumerable.GetEnumerator()
            {
                throw new NotImplementedException();
            }
        }
    }

  

Asp.Net Core 轻松学-一行代码搞定文件上传 JSONHelper的更多相关文章

  1. Asp.Net Core 轻松学-一行代码搞定文件上传

    前言     在 Web 应用程序开发过程中,总是无法避免涉及到文件上传,这次我们来聊一聊怎么去实现一个简单方便可复用文件上传功能:通过创建自定义绑定模型来实现文件上传. 1. 实现自定义绑定模型 1 ...

  2. 【自动化专题】selenium如何轻松搞定文件上传

    使用selenium做自动化时,我们经常会遇到的一个让人头疼的问题就是文件上传. 问题的难点在于selenium无法识别并操作Windows窗口,若我们可以绕过弹出框直接把文件信息上传给选择按钮,难点 ...

  3. Asp.Net Core 轻松学系列-1阅读指引目录

    https://www.cnblogs.com/viter/p/10474091.html 目录 前言 1. 从安装到配置 2. 业务实现 3. 日志 4. 测试 5. 缓存使用 6.网络和通讯 7. ...

  4. WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)

    WebAPI调用笔记   前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...

  5. Asp.Net Core 轻松学-使用MariaDB/MySql/PostgreSQL和支持多个上下文对象

    前言 在上一篇文章中(Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库)[https://www.cnblogs.com/viter/p/10243577.html],介 ...

  6. Asp.Net Core 轻松学-多线程之Task(补充)

    前言     在上一章 Asp.Net Core 轻松学-多线程之Task快速上手 文章中,介绍了使用Task的各种常用场景,但是感觉有部分内容还没有完善,在这里补充一下. 1. 任务的等待 在使用 ...

  7. Asp.Net Core 轻松学-利用文件监视进行快速测试开发

    前言     在进行 Asp.Net Core 应用程序开发过程中,通常的做法是先把业务代码开发完成,然后建立单元测试,最后进入本地系统集成测试:在这个过程中,程序员的大部分时间几乎都花费在开发.运行 ...

  8. 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange

    如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...

  9. C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌

    1.  IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...

随机推荐

  1. OpenCV学习(18) 细化算法(6)

    本章我们在学习一下基于索引表的细化算法. 假设要处理的图像为二值图,前景值为1,背景值为0. 索引表细化算法使用下面的8邻域表示法: 一个像素的8邻域,我们可以用8位二进制表示,比如下面的8邻域,表示 ...

  2. Byedance AI Camp-笔试题目

    最小m段和问题:给定n个整数组成的序列,现在要求将序列分割为m段,每段子序列中的数在原序列中连续排列.如何分割才能使这m段子序列的和的最大值达到最小? Input 第一行输入一个整数t,代表有t组测试 ...

  3. 我的SQL里哪个语句占用的CPU最多?

    可以使用下面的语句来得到 SELECT SUBSTRING(qt.TEXT, (qs.statement_start_offset/2)+1, ( (CASE qs.statement_end_off ...

  4. ASP.NET MVC中使用jQuery时的浏览器缓存问题

    介绍 尽管jQuery在浏览器ajax调用的时候对缓存提供了很好的支持,还是有必要了解一下如何高效地使用http协议. 首先要做的事情是在服务器端支持HTTP GET,定义不同的URL输出不同的数据( ...

  5. WebViewClient 简介 API 案例

    代码位置:https://github.com/baiqiantao/WebViewTest.git 设计思想理解 在WebView的设计中,不是什么事都要WebView类干的,有相当多的杂事是分给其 ...

  6. ILMerge-GUI的使用

    去这里下载: 这里下载ILMerge,http://www.microsoft.com/en-us/download/details.aspx?id=17630 这里下载ILMerge-GUI,htt ...

  7. .Net垃圾收集机制—了解算法与代龄

    垃圾收集器在本质上就是负责跟踪所有对象被引用到的地方,关注对象不再被引用的情况,回收相应的内存.在.NET平台中同样如此,有效的提高.NET垃圾回收性能,能够提高程序执行效率. 其实垃圾收集并不是伴随 ...

  8. VS2008中生成DLL项目

    创建项目 新建项目-> 选择Win32项目 输入项目名称,点击确定.在程序向导中选择下一步 选择DLL. 由于我想创建的是相对独立的DLL,所以不选择ATL和MFC. 点击完成.   Main文 ...

  9. hbase-0.94安装方法具体解释

    先决条件:     1)java环境,须要安装java1.6以上版本号     2)hadoop环境.因为HBase架构是基于其它文件存储系统的,因此在分布式模式下安装Hadoop是必须的,可是,假设 ...

  10. fatal: incorrect checksum in control file

    在网上搜到 7. 修改pg_controlfile的checksum源码, 不check. vi src/backend/access/transam/xlog.c 注释checksum部分     ...