循序漸進學.Net Core Web Api開發系列【5】:文件上傳


系列目錄

循序漸進學.Net Core Web Api開發系列目錄

 本系列涉及到的源碼下載地址:https://github.com/seabluescn/Blog_WebApi

 

一、概述

本篇介紹通過.NET core WebApi實現文件上傳。

 

二、Controller端代碼

直接上代碼:

    [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的類來返回信息。

    public class ResultObject
    {
        public String state { get; set; }
        public Object resultObject { get; set; }
    }

返回上傳的文件名稱列表的目的是因為后台可能會給文件重新命名,以避免沖突,新的文件名稱需要讓前台知道。

后台的files是通過傳入的參數獲得的,還有其他兩種方法可以獲取到文件,效果一樣:

       [HttpPost]
        public ResultObject UploadAjax()
        { 
            var files = Request.Form.Files;
            ...
         }

或:

       public ResultObject UploadForm(IFormCollection form)
        {    
            var files = form.Files;
            ...
       }

除了獲取到files的方式不同,其他操作完全一致。

 

三、前端代碼

<!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>

兩個注意點:

1、form要提供enctype="multipart/form-data" 屬性

2、如果要上傳多個文件,文件表單需要提供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")); 比較方便。

 

四、上傳大文件

上傳大文件和上傳小文件代碼是一樣的,關鍵是上傳大文件時間太長,需要前端提供進度報告,不然用戶體驗太差。

解決的方案是利用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>

 此時,可以看到上傳進度條了,可以選擇一個大文件測試一下。或者把瀏覽器的傳輸速度調低也可以進行調試。

 

五、為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選擇文件了

但有個缺點是只能上傳一個文件,如何實現可以選擇多個文件還不會搞。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM