在上篇文章深入探究ASP.NET Core读取Request.Body的正确方式中我们探讨了很多人在日常开发中经常遇到的也是最基础的问题,那就是关于Request.Body的读取方式问题,看是简单实则很容易用不好。笔者也是非常荣幸的得到了许多同学的点赞支持,心理也是非常的兴奋。在此期间在技术交流群中,有一位同学看到了我的文章之后提出了一个疑问,说关于ASP.NET Core文件上传IFormFile和Request.Body之间存在什么样的关系。由于笔者没对这方面有过相关的探究,也没敢做过多回答,怕误导了那位同学,因此私下自己研究了一番,故作此文,希望能帮助更多的同学解除心中的疑惑。
IFormFile的使用方式考虑到可能有的同学对ASP.NET Core文件上传操作可能不是特别的理解,接下来咱们通过几个简单的操作,让大家简单的熟悉一下。
简单使用演示首先是最简单的单个文件上传的方式
[HttpPost] public string UploadFile (IFormFile formFile) { return $"{formFile.FileName}--{formFile.Length}--{formFile.ContentDisposition}--{formFile.ContentType}"; }非常简单的操作,通过IFormFile实例直接获取文件信息,这里需要注意模型绑定的名称一定要和提交的表单值的name保持一致,这样才能正确的完成模型绑定。还有的时候我们是要通过一个接口完成一批文件上传,这个时候我们可以使用下面的方式
[HttpPost] public IEnumerable<string> UploadFiles(List<IFormFile> formFiles) { return formFiles.Select(i => $"{i.FileName}--{ i.Length}-{ i.ContentDisposition}--{ i.ContentType}"); }直接将模型绑定的参数声明为集合类型即可,同时也需要注意模型绑定的名称和上传文件form的name要保持一致。不过有的时候你可能连List这种集合类型也不想写,想通过一个类就能得到上传的文件集合,好在微软够贴心,给我们提供了另一个类,操作如下
[HttpPost] public IEnumerable<string> UploadFiles3(IFormFileCollection formFiles) { return formFiles.Select(i => $"{i.FileName}--{ i.Length}-{ i.ContentDisposition}--{ i.ContentType}"); }对微软的代码风格有了解的同学看到名字就知道,IFormFileCollection其实也是对IFormFile集合的封装。有时候你可能都不想使用IFormFile的相关模型绑定,可能是你怕记不住这个名字,那还有别的方式能操作上传文件吗?当然有,可以直接在Request表单中获取上传文件信息
[HttpPost] public IEnumerable<string> UploadFiles2() { IFormFileCollection formFiles = Request.Form.Files; return formFiles.Select(i => $"{i.FileName}--{ i.Length}-{ i.ContentDisposition}--{ i.ContentType}"); }其实它的本质也是获取到IFormFileCollection,不过这种方式更加的灵活。首先是不需要模型绑定名称不一致的问题,其次是只要有Request的地方就可以获取到上传的文件信息。
操作上传内容如果你想保存上传的文件,或者是直接读取上传的文件信息,IFormFile为我们提供两种可以操作上传文件内容信息的方式
一种是将上传文件的Stream信息Copy到一个新的Stream中
另一种是直接通过OpenReadStream的方式直接获取上传文件的Stream信息
两种操作方式大致如下
[HttpPost] public async Task<string> UploadFile (IFormFile formFile) { if (formFile.Length > 0) { //1.使用CopyToAsync的方式 using var stream = System.IO.File.Create("test.txt"); await formFile.CopyToAsync(stream); //2.使用OpenReadStream的方式直接得到上传文件的Stream StreamReader streamReader = new StreamReader(formFile.OpenReadStream()); string content = streamReader.ReadToEnd(); } return $"{formFile.FileName}--{formFile.Length}--{formFile.ContentDisposition}--{formFile.ContentType}"; } 更改内容大小限制ASP.NET Core会对上传文件的大小做出一定的限制,默认限制大小约是2MB(以字节为单位)左右,如果超出这个限制,会直接抛出异常。如何加下来我们看一下如何修改上传文件的大小限制通过ConfigureServices的方式直接配置FormOptions的MultipartBodyLengthLimit
public void ConfigureServices(IServiceCollection services) { services.Configure<FormOptions>(options => { // 设置上传大小限制256MB options.MultipartBodyLengthLimit = 268435456; }); }这里只是修改了对上传文件主题大小的限制,熟悉ASP.NET Core的同学可能知道,默认情况下Kestrel对Request的Body大小也有限制,这时候我们还需要对Kestrel的RequestBody大小进行修改,操作如下所示
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureKestrel((context, options) => { //设置Body大小限制256MB options.Limits.MaxRequestBodySize = 268435456; }); webBuilder.UseStartup<Startup>(); });很多时候这两处设置都需要配合着一起使用,才能达到效果,用的时候需要特别的留意一下。
源码探究