手记

如何在 ASP.Net Core MVC 中实现文件上传

ASP.Net Core MVC 实现了将 上传文件 直接映射到 model 中,只要这个 model 实现了 IFormFile 接口即可,回想一下, model binding 的作用就是将 Request 映射到 Action 方法参数的过程,这样就简化了原来需要直接对 Request 的访问,同时也方便后续做单元测试,本篇中的 IFormFile 接口就简化了对 Request 中的 file 访问。

上传一个文件

在这一节中我们将会演示如何通过 IFromFile 接口来对接 client 上传一个或者多个文件,先看一下 IFromFile 接口的定义。


public interface IFormFile
{
    string ContentType { get; }
    string ContentDisposition { get; }
    IHeaderDictionary Headers { get; }
    long Length { get; }
    string Name { get; }
    string FileName { get; }
    Stream OpenReadStream();
    void CopyTo(Stream target);
    Task CopyToAsync(Stream target, CancellationToken cancellationToken = null);
}

然后我们创建一个 FileUploadController 类,构建一个 UploadFile 方法来接收 client 上传的文件。


    public class FileUploadController : Controller
    {
        [HttpPost("UploadFile")]
        public async Task UploadFile(IFormFile iFormFile)
        {
            if (iFormFile == null || iFormFile.Length == 0)
                return Content("No file selected for upload.");

            var filePath = Path.GetTempFileName();

            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await iFormFile.CopyToAsync(stream);
            }

            return RedirectToAction("Home");
        }
    }

从上面代码可以看到,UploadFile 方法中使用了 IFormFile 实例作用参数,如果 iFormFile 里无数据或者空引用就返回 No file selected for upload. 反之就保存文件并跳转到 Home 页。

如果有多文件上传需求,可以将 IFromFile 改成数组形式,如下代码所示:


        [HttpPost("UploadFiles")]
        public async Task UploadFiles(List iFormFiles)
        {
            var filePath = Path.GetTempFileName();

            foreach (var iFormFile in iFormFiles)
            {
                if (iFormFile.Length > 0)
                {
                    using (var stream = new FileStream(filePath, FileMode.Create))
                    {
                        await iFormFile.CopyToAsync(stream);
                    }
                }
            }
            return RedirectToAction("Home");
        }

上面代码用了 GetTempFileName() 来获取临时文件,这里有一个坑需要注意,如果这个路径下的临时文件超过 65535 的话将会抛出异常,解决办法就是:

  • 在处理完之后删除临时文件。

  • 将文件保存在你指定的地方。

下载 file

要想从 ASP.Net Core MVC 中下载文件,考虑如下代码:


        public async Task DownloadFile(string path, string filename)
        {
            if (filename == null || filename.Length == 0)
                return Content("No file selected for download.");

            var filePath = Path.Combine(path, filename);
            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(filePath, FileMode.Open))
            {
                await stream.CopyToAsync(memoryStream);
            }

            memoryStream.Position = 0;

            return File(memoryStream, "text/plain", Path.GetFileName(path));
        }

在 DownloadFile 方法中使用了 CopyToAsync 方法将文件 copy 到 MemoryStream 中,然后通过返回 FileStreamResult 将文件流返回给客户端。

创建一个 Razor View

接下来创建一个 Razor View 用来做文件上传的界面,在 View 界面中添加如下代码:


@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">

    
        Upload File
    
    
        Upload Files
    

</div>

接下来可以把程序跑起来,上传一个文件,截图如下:

通过本篇文章可以看出 ASP.Net Core MVC 中的 model binding 真的是太强大了,你可以上传一个或者多个size不定的文件,关于更多 ASP.Net Core 中上传下载的细节,我会放到后面的文章和大家细聊。

更多高质量干货:参见我的 GitHub: [csharptranslate] github.com/ctripxchuang/csharptranslate

0人推荐
随时随地看视频
慕课网APP