系列目錄javascript
按部就班學.Net Core Web Api開發系列目錄css
本系列涉及到的源碼下載地址:https://github.com/seabluescn/Blog_WebApihtml
1、概述前端
本篇介紹經過.NET core WebApi實現文件上傳。java
2、Controller端代碼jquery
直接上代碼:git
[Route("api/files")] [Produces("application/json")] public class FileController : Controller { private readonly IHostingEnvironment _hostingEnvironment; public FileController(IHostingEnvironment hostingEnvironment) { _hostingEnvironment = hostingEnvironment; } [HttpPost("iform")] public ResultObject UploadIForm(List<IFormFile> files) { List<String> filenames = new List<string>(); foreach (var file in files) { var fileName = file.FileName; Console.WriteLine(fileName); fileName = $"/UploadFile/{fileName}"; filenames.Add(fileName); fileName = _hostingEnvironment.WebRootPath + fileName; using (FileStream fs = System.IO.File.Create(fileName)) { file.CopyTo(fs); fs.Flush(); } } return new ResultObject { state = "Success", resultObject = filenames }; }
爲了同時返回上傳的文件名和操做狀態,咱們定義了一個ResultObject的類來返回信息。github
public class ResultObject { public String state { get; set; } public Object resultObject { get; set; } }
返回上傳的文件名稱列表的目的是由於後臺可能會給文件從新命名,以免衝突,新的文件名稱須要讓前臺知道。ajax
後臺的files是經過傳入的參數得到的,還有其餘兩種方法能夠獲取到文件,效果同樣:json
[HttpPost] public ResultObject UploadAjax() { var files = Request.Form.Files; ... }
或:
public ResultObject UploadForm(IFormCollection form) { var files = form.Files; ... }
除了獲取到files的方式不一樣,其餘操做徹底一致。
3、前端代碼
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="lib/jquery/dist/jquery.min.js"></script> <script src="lib/jquery-form/dist/jquery.form.min.js"></script> <script type="text/javascript"> function AjaxFormDataUploadfile() { var fileUpload = $("#files").get(0); var files = fileUpload.files; var data = new FormData();
for (var i = 0; i < files.length; i++) { data.append("files", files[i]); } $.ajax({ type: "POST", url: "/api/files/iform", contentType: false, processData: false, data: data, success: function (message) { alert("success"); }, error: function () { alert("上傳文件出現錯誤!"); } }); } </script> </head> <body> <form id="myform" method="post" action="/api/files/iform" enctype="multipart/form-data"> <input type="file" id="files" name="files" multiple /> <br /><br /> <input id="formupload" type="button" value="Form Data Upload" onclick="AjaxFormDataUploadfile();" /><br /><br /> </form> </body> </html>
兩個注意點:
一、form要提供enctype="multipart/form-data" 屬性
二、若是要上傳多個文件,文件表單須要提供multiple屬性
這裏咱們經過FormData對象的append操做來構建提交的數據,根據我上一篇博客提到的,這裏提交數據還有其餘兩個辦法:
function formuploadfile() { $("#myform").ajaxSubmit(); }
或者:
function Ajaxuploadfile() { var formdata = new FormData(document.getElementById("myform")); $.ajax({ type: "POST", url: "/api/files/iform", contentType: false, processData: false, data: formdata, success: function (result) { alert("success"); $.each(result.resultObject, function (i, filename) { alert(filename); }); }, error: function () { alert("上傳文件出現錯誤!"); } }); }
具體選擇哪一種方式,要看前端的需求,我的認爲 var formdata = new FormData(document.getElementById("myform")); 比較方便。
4、上傳大文件
上傳大文件和上傳小文件代碼是同樣的,關鍵是上傳大文件時間太長,須要前端提供進度報告,否則用戶體驗太差。
解決的方案是利用ajax的HXR對象。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="lib/jquery/dist/jquery.min.js"></script> <script src="lib/jquery-form/dist/jquery.form.min.js"></script> <script type="text/javascript"> function AjaxuploadfileWithprogress() { var formdata = new FormData(document.getElementById("myform")); $.ajax({ type: "POST", url: "/api/files/iform", contentType: false, processData: false, data: formdata, success: function (result) { alert("success"); $.each(result.resultObject, function (i, filename) { alert(filename); }); }, error: function () { alert("上傳文件出現錯誤!"); }, xhr: function () { var xhr = $.ajaxSettings.xhr(); if (onprogress && xhr.upload) { xhr.upload.addEventListener("progress", onprogress, false); return xhr; } } }); } function onprogress(evt) { var loaded = evt.loaded; //已經上傳大小 var tot = evt.total; //附件總大小 var per = Math.floor(100 * loaded / tot); //百分比 $("#son").html(per + "%"); $("#son").css("width", per + "%"); } </script> <style type="text/css"> #parent { width: 550px; height: 10px; border: 2px solid #09F; } #son { width: 0; height: 100%; background-color: #09F; text-align: center; line-height: 10px; font-size: 20px; font-weight: bold; } </style> </head> <body> <form id="myform" method="post" action="/api/files/iform" enctype="multipart/form-data"> <div> <div> <br /> <p>表單多個上傳文件:</p><br /> <input type="file" id="files" name="files" multiple /> <br /><br /> <input id="formuploadprogress" type="button" value="Ajax Upload Progress" onclick="AjaxuploadfileWithprogress();" /><br /><br /> <div id="parent"> <div id="son"></div> </div> </div> </div> </form> </body> </html>
此時,能夠看到上傳進度條了,能夠選擇一個大文件測試一下。或者把瀏覽器的傳輸速度調低也能夠進行調試。
5、爲Swagger提供文件上傳調試功能支持
目前swagger是不支持List<IFormFile>類型的,爲了方便調試,咱們爲swagger提供該類型的支撐。
新增類:
public class SwaggerFileUploadListFilter : IOperationFilter { public void Apply(Operation operation, OperationFilterContext context) { if (!context.ApiDescription.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase) && !context.ApiDescription.HttpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase)) { return; } var fileParameters = context.ApiDescription.ActionDescriptor.Parameters.Where(n => n.ParameterType == typeof(List<IFormFile>)).ToList(); if (fileParameters.Count < 0) { return; } operation.Consumes.Add("multipart/form-data");
foreach (var fileParameter in fileParameters) { var parameter = operation.Parameters.Single(n => n.Name == fileParameter.Name); operation.Parameters.Remove(parameter); NonBodyParameter p = new NonBodyParameter { Name = parameter.Name, In = "formData", Description = parameter.Description, Required = parameter.Required, Type = "file" }; operation.Parameters.Add(p); } } }
在Startup類的ConfigureServices方法裏註冊該過濾器:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddCors(); services.AddSwaggerGen(option => { option.SwaggerDoc("v1", new Info { Version = "v1", Title = "SaleService接口文檔", Description = "RESTful API for SaleService.", TermsOfService = "None", Contact = new Contact { Name = "seabluescn", Email = "seabluescn@163.com", Url = "" } }); option.OperationFilter<SwaggerFileUploadListFilter>(); //Set the comments path for the swagger json and ui. var basePath = PlatformServices.Default.Application.ApplicationBasePath; var xmlPath = Path.Combine(basePath, "SaleService.xml"); option.IncludeXmlComments(xmlPath); }); }
此時能夠經過swagger選擇文件了
但有個缺點是隻能上傳一個文件,如何實現能夠選擇多個文件還不會搞。