第57章 Swagger通过IFormFile或IFormCollection参数实例实现文件上传

  • Post author:
  • Post category:其他



1


以数据流形式渲染显示头像图片


1.1  Core.



MimeTypes



namespace


Core



{




///


<summary>



///





Mime


类型





类】



///


<remarks>



///


摘要:



///


媒体类型(通常称为


Multipurpose Internet Mail Extensions





MIME


类型)是一种标准,用来表示文档、文件或字节流的性质和格式。



///


它在


IETF RFC 6838


中进行了定义和标准化。



///


警告


/


说明:



///     1


、浏览器通常使用


MIME


类型(而不是文件扩展名)来确定如何处理


URL


,因此


Web


服务器在响应头中添加正确的


MIME


类型非常重要。



///


如果配置不正确,浏览器可能会曲解文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。




///     2









MIME




类型主要是为浏览器通常以静态文件的形式渲染显示指定类型的持久化文件提供数据支撑,





///




如果先把指定类型的持久化文件转换为数据流再在浏览器渲染显示时,则不用,但是在持久化文件转换为数据流操作时必须为其提供相应的




MIME




类型作为数据支撑。




///


</remarks>



///


</summary>



public


static


class


MimeTypes



{




#


region


应用



///


<summary>



///


【应用程序强制下载】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定指定静态文件为下载文件。



///


</remarks>



///


</summary>



public


static


string


ApplicationForceDownload


=>


“application/force-download”


;



///


<summary>



///


【应用程序


Json






///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


Json


编码格式进行持久化存储的静态文件,同时客户端浏览器也会以


Json


编码格式渲染显示该静态文件。



///


</remarks>



///


</summary>



public


static


string


ApplicationJson


=>


“application/json”


;



///


<summary>



///


【应用程序清单】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


Json/XML


编码格式进行持久化存储的静态文件,同时客户端浏览器也会以


Json/XML


编码格式渲染显示该静态文件。



///


</remarks>



public


static


string


ApplicationManifestJson


=>


“application/manifest+json”


;



///


<summary>



///


【应用程序八位字节流】



///


<remarks>



///


摘要:



///


客户端浏览器向服务器端上传持久化存储静态文件时,只能以二进制数据流(或者字节数组


)


进行上传,且以此标准一次只能向服务器端上传一个静态文件


,


服务器端的接收参数也只能有一个。



///


</remarks>



///


</summary>



public


static


string


ApplicationOctetStream


=>


“application/octet-stream”


;



///


<summary>



///


【应用程序


PDF






///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


PDF


编码格式进行持久化存储的静态文件,同时客户端浏览器也会以


PDF


编码格式渲染显示该静态文件。



///


</remarks>



///


</summary>



public


static


string


ApplicationPdf


=>


“application/pdf”


;



///


<summary>



///


【应用程序


RSSXML






///


<remarks>



///


摘要:



///    1


、据说搜索引擎也会根据这个标签自动去爬行博客的


RSS






///    2


、让


Firefox





IE7


或其它


Feed


机器人自动发现网站的


RSS


视图;



///


</remarks>



///


</summary>



public


static


string


ApplicationRssXml


=>


“application/rss+xml”


;



///


<summary>



///


【应用程序


XML






///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


XML


编码格式进行持久化存储的静态文件,同时客户端浏览器也会以


XML


编码格式渲染显示该静态文件。



///


</remarks>



public


static


string


ApplicationXml


=>


“application/xml”


;



///


<summary>



///


【窗体应用程序】



///


<remarks>



///


摘要:



///


客户端浏览器以键


/


值对的形式把地址栏中的参数值发送到服务器端的指定的控制器行为方法。



///


说明:



///     Postman


以此标准把键


/


值对发送到服务器端的指定的控制器行为方法。



///


</remarks>



///


</summary>



public


static


string


ApplicationXWwwFormUrlencoded


=>


“application/x-www-form-urlencoded”


;



///


<summary>



///


【应用程序


Zip






///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为静态压缩文件,同时客户端浏览器也会以此标准打开静态压缩文件。



///


</remarks>



///


</summary>



public


static


string


ApplicationZip


=>


“application/zip”


;



///


<summary>



///


【应用程序


Zip


扩展】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为静态压缩文件,同时客户端浏览器也会以此标准打开静态压缩文件。



///


</remarks>



///


</summary>



public


static


string


ApplicationXZipCo


=>


“application/x-zip-co”


;



#


endregion



#


region


图片



///


<summary>



///





Bmp


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“bmp”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImageBmp


=>


“image/bmp”


;



///


<summary>



///





Gif


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“Gif”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImageGif


=>


“image/gif”


;



///


<summary>



///





Jpeg


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“jpe/jpeg/jpg/jfif/pjpeg/pjp”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImageJpeg


=>


“image/jpeg”


;



///


<summary>



///





pjpeg


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“jpe/jpeg/jpg/jfif/pjpeg/pjp”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImagePJpeg


=>


“image/pjpeg”


;



///


<summary>



///





Png


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“Png”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImagePng


=>


“image/png”


;



///


<summary>



///





Tiff


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“tiff”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImageTiff


=>


“image/tiff”


;



///


<summary>



///





Webp


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“webp”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImageWebp


=>


“image/webp”


;



///


<summary>



///





Svg


图片】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件以


“svg”


为扩展名的静态图片文件,同时客户端浏览器也会以此标准打开该静态图片文件。



///


</remarks>



///


</summary>



public


static


string


ImageSvg


=>


“image/svg+xml”


;



#


endregion



#


region


文本



///


<summary>



///





CSS


文本】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


CSS


编码格式进行持久化存储的静态文本文件,同时客户端浏览器也会以


CSS


编码格式渲染显示该静态文本文件。



///


</remarks>



///


</summary>



public


static


string


TextCss


=>


“text/css”


;



///


<summary>



///


【】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


Csv


码格式进行持久化存储的静态文本文件,同时客户端浏览器也会以


Csv


编码格式渲染显示该静态


Csv


文本文件。



///


</remarks>



///


</summary>



public


static


string


TextCsv


=>


“text/csv”


;



///


<summary>



///





Javascript


文本】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


Javascript


编码格式进行持久化存储的静态文本文件,同时客户端浏览器也会以


Javascript


编码格式渲染显示该静态


Javascript


文本文件。



///


</remarks>



///


</summary>



public


static


string


TextJavascript


=>


“text/javascript”


;



///


<summary>



///


【纯文本


(text)






///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以纯文本


(text)


编码格式进行持久化存储的静态文本文件,同时客户端浏览器也会以纯文本


(text)


编码格式渲染显示该静态纯文本


(text)


文件。



///


</remarks>



///


</summary>



public


static


string


TextPlain


=>


“text/plain”


;



///


<summary>



///





Excel


文本】



///


<remarks>



///


摘要:



///


客户端浏览器头字典实例中设定服务器端发送的指定文件为以


Excel


编码格式进行持久化存储的静态文本文件,同时客户端浏览器也会以


Excel


编码格式渲染显示该静态


Excel


文本文件。



///


</remarks>



///


</summary>



public


static


string


TextXlsx


=>


“application/vnd.openxmlformats-officedocument.spreadsheetml.sheet”


;



#


endregion



}



}


1.2  WebApi.Controllers.

CustomerController

.


GetPictureContentTypeByFileExtension



///


<param


name


=


“fileExtension”


>


1


个指定图片的扩展名。


</param>



///


<summary>



///


【通过扩展名获取图片类型】



///


</summary>



///


<remarks>



///


摘要:



///


通过


1


个指定图片的扩展名获取


1


个指定图片的类型。



///


</remarks>



///


<returns>



///


返回:



///    1


个指定图片的类型。



///


</returns>



private


string


GetPictureContentTypeByFileExtension


(


string


fileExtension


)



{




string


contentType


=


null


;



switch


(


fileExtension


.


ToLower


())



{




case


“.bmp”


:



contentType


=


MimeTypes


.


ImageBmp


;



break


;



case


“.gif”


:



contentType


=


MimeTypes


.


ImageGif


;



break


;



case


“.jpeg”


:



case


“.jpg”


:



case


“.jpe”


:



case


“.jfif”


:



case


“.pjpeg”


:



case


“.pjp”


:



contentType


=


MimeTypes


.


ImageJpeg


;



break


;



case


“.webp”


:



contentType


=


MimeTypes


.


ImageWebp


;



break


;



case


“.png”


:



contentType


=


MimeTypes


.


ImagePng


;



break


;



case


“.svg”


:



contentType


=


MimeTypes


.


ImageSvg


;



break


;



case


“.tiff”


:



case


“.tif”


:



contentType


=


MimeTypes


.


ImageTiff


;



break


;



default


:



break


;



}



return


contentType


;



}


1.3 WebApi.Controllers.

CustomerController

.


GetAvatarStream



///


<param


name


=


“customerId”


>


1


个指定的长整型值。


</param>



///


<summary>



///


【以数据流形式渲染显示头像图片





无需权限】



///


</summary>



///


<remarks>



///


摘要:



///


获取


1


个指定用户头像图片的数据流,为前端头像图片的渲染显示提供数据支撑。



///


</remarks>



///


<returns>



///


返回:



///     1


个指定用户头像图片的数据流,为前端头像图片的渲染显示提供数据支撑。



///


</returns>



[


HttpGet


]



public


async


Task


<


IActionResult


>


GetAvatarStream


(


long


customerId


)



{




Customer


_customer


=


await


_customerService


.


GetCustomerByIdAsync


(


customerId


);



string


_avatarPath


=


string


.


Empty


;



if


(


_customer


!=


null


)



{




if


(


string


.


IsNullOrEmpty


(


_customer


.


Avatar


))



{




_avatarPath


=


_nopFileProvider


.


Combine


(


_nopFileProvider


.


WebRootPath


,


@”\images\Avatar\Default.jpg”


);



}



else



{




//


去除网络格式路径字符中的第一个字符


“~/”






_customer


.


Avatar


=


_customer


.


Avatar


.


Replace


(


“~/”


,


string


.


Empty


).


TrimStart


(‘


/


‘);



//


去除网络格式路径字符中的最后一个字符


“/”






var


pathEnd


=


_customer


.


Avatar


.


EndsWith


(‘


/


‘)


?


Path


.


DirectorySeparatorChar


.


ToString


()


:


string


.


Empty


;



//


通过拼接操作,拼接出与之相对应的


1


个本地格式的路径字符串。



_avatarPath


=


_nopFileProvider


.


Combine


(


_nopFileProvider


.


WebRootPath


??


string


.


Empty


,


_customer


.


Avatar


)


+


pathEnd


;



}



}




string




_avatarType




=




GetPictureContentTypeByFileExtension




(




_nopFileProvider




.




GetFileExtension




(




_avatarPath




));





var




imageFileStream




=




System




.




IO




.




File




.




OpenRead




(




_avatarPath




);





return




File




(




imageFileStream




,




_avatarType




);




}


2   Swagger


通过IFormFile或IFormCollection参数实例实现文件上传



2.1 415




异常:


Swagger/index.html


在默认情况下是可以通过IFormFile或IFormCollection参数实例向服务器端上传控制器行为方法发送参数实例的实现文件上传功能的,但是由于Framework.Infrastructure.Middleware.

CorsExceptionHandlerMiddleware


中间件定义会出现415异常,

如下图上所示:




2.2




解决方案:重构



Framework.Infrastructure.Middleware.

CorsExceptionHandlerMiddleware



using


Microsoft


.


AspNetCore


.


Cors


.


Infrastructure


;



using


Microsoft


.


AspNetCore


.


Http


;



namespace


Framework


.


Infrastructure


.


Middleware



{




///


<summary>



///


【跨域异常处理中间件





类】



///


<remarks>



///


摘要:



///


该管道中间件类主要为了集中解决在由


vue/uni-app


前端项目跨域


(Cors)


访问当前后端项目时,浏览器或


App


中出现的异常:



///    1





“has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.”






///    2





“has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”






///    3





“has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.”






///


说明:



///     vue/uni-app


前端项目跨域


(Cors)


访问当前后端项目时,浏览器或


App


中出现的异常,可以直接在


vue/uni-app


前端项目中解决;但本人更习惯通过后端定义来集中解决这些异常。



///


</remarks>



///


</summary>



public


class


CorsExceptionHandlerMiddleware



{




#region


拷贝构造方法与变量



///


<summary>



///


【下


1


个】



///


<remarks>



///


摘要:



///     .Net(Core)


框架内置管道中的下


1


个管道中间件实例。



///


</remarks>



///


</summary>



private


readonly


RequestDelegate


_next


;



///


<param


name


=


“next”


>


.Net(Core)


框架内置管道中的下


1


个管道中间件实例。


</param>



///


<summary>



///


【拷贝构造方法】



///


<remarks>



///


摘要:



///


通过该构造方法中的参数实例,实例化


.Net(Core)


框架内置管道中的下


1


个管道中间件实例。



///


</remarks>



///


</summary>



public


CorsExceptionHandlerMiddleware


(


RequestDelegate


next


)



{




_next


=


next


;



}



#endregion



#region


方法



///


<param


name


=


“context”


>


HTTP


上下文实例。


</param>



///


<summary>



///


【异步调用】



///


<remarks>



///


摘要:



///


通过该方法向


.Net(Core)


框架内置管道中集成当前管道中间件,集中解决在由


vue/uni-app


前端项目跨域


(Cors)


访问当前后端项目时,浏览器或


App


中出现的异常:



///    1





“has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.”






///    2





“has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”






///    3





“has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.”






///


</remarks>



///


</summary>



public


async


Task


InvokeAsync


(


HttpContext


context


)



{




//


解决在由


Hbuilder


创建的前端


Xuni-app


项目


(Cors)


访问当前后端项目时,浏览器或


App


中会出现异常:



//“has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.”






if


(!


context


.


Response


.


Headers


.


ContainsKey


(


“Access-Control-Allow-Headers”


))



{




context


.


Response


.


Headers


.


Add


(


“Access-Control-Allow-Headers”


,


“DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization”


);



}



if


(!


context


.


Response


.


Headers


.


ContainsKey


(


“Access-Control-Allow-Methods”


))



{




context


.


Response


.


Headers


.


Add


(


“Access-Control-Allow-Methods”


,


“GET,POST,PUT,DELETE,PATCH,OPTIONS”


);



}



//


解决在由


Hbuilder


创建的前端


Xuni-app


项目


(Cors)


访问当前后端项目时,浏览器或


App


中会出现异常:



//“has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”






if


(!


context


.


Response


.


Headers


.


ContainsKey


(


“Access-Control-Allow-Origin”


))



{




context


.


Response


.


Headers


.


Add


(


“Access-Control-Allow-Origin”


,


“*”


);



}



if


(


context


.


Request


.


Headers


.


ContainsKey


(


CorsConstants


.


Origin


))



{




//


解决在前端通过


“axios.post”


方式调用后端


POST-API





,


如果前端


“axios.post”


方法没有加载


“headers”


参数实例,下


1


行语句中的配置,否则


“axios.post”


方法,访问后端的


POST-API,


否则会出现


:”HTTP:415″


错误。



//context.Request.ContentType = “application/json”;




if




(!




context




.




Request




.




ContentType




.




Contains




(




“multipart/form-data”




))




context


.


Request


.


ContentType


=


“application/json”


;



//


解决在由


Hbuilder


创建的前端


Xuni-app


项目


(Cors)


访问当前后端项目时,浏览器或


App


中会出现异常:



//“’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.”






if


(


context


.


Request


.


Method


.


Equals


(


“OPTIONS”


))



{




context


.


Response


.


StatusCode


=


StatusCodes


.


Status200OK


;



return


;



}



}



await


_next


(


context


);



}



#endregion



}



}


2.3 WebApi.Controllers.



CustomerController



.


PostAvatarStream



///


<param


name


=


“customerId”


>


1


个指定的长整型值。


</param>



///


<param


name


=


“formFile”


>


1


个指定的上传文件的实例。


</param>



///


<summary>



///


【上传单个文件





无需权限】



///


</summary>



///


<remarks>



///


摘要:



///





1


个指定的上传文件从客户端上传到服务器端的指定目录中。



///


</remarks>



///


<returns>



///


返回:



///     1


个指定的上传文件上传操作后的状态信息。



///


</returns>



[


HttpPost


]



public


async


Task


<


IActionResult


>


PostAvatarStream


(


long


customerId


,


/*IFormCollection collection [FromForm]*/


IFormFile


formFile


)



{




Customer


_customer


=


await


_customerService


.


GetCustomerByIdAsync


(


customerId


);



//string _avatarPath = string.Empty;



if


(


_customer


!=


null


&&


formFile


!=


null


)



{




if


(!


string


.


IsNullOrEmpty


(


_customer


.


Avatar


)&&!


_nopFileProvider


.


GetFileName


(


_customer


.


Avatar


).


Equals


(


“Default.jpg”


))



{




//


去除网络格式路径字符中的第一个字符


“~/”






_customer


.


Avatar


=


_customer


.


Avatar


.


Replace


(


“~/”


,


string


.


Empty


).


TrimStart


(


‘/’


);



//


去除网络格式路径字符中的最后一个字符


“/”






var


pathEnd


=


_customer


.


Avatar


.


EndsWith


(


‘/’


) ?


Path


.


DirectorySeparatorChar


.


ToString


() :


string


.


Empty


;



//


通过拼接操作,拼接出与之相对应的


1


个本地格式的路径字符串。



string


_avatarPath


=


_nopFileProvider


.


Combine


(


_nopFileProvider


.


WebRootPath


??


string


.


Empty


,


_customer


.


Avatar


) +


pathEnd


;



_nopFileProvider


.


DeleteFile


(


_avatarPath


);



}



string


_filename


=


customerId


.


ToString


() +


_nopFileProvider


.


GetFileExtension


(


formFile


.


FileName


);



string


_path


=


_nopFileProvider


.


Combine


(


_nopFileProvider


.


WebRootPath


,


@”\images\Avatar\”


,


_filename


);



using


FileStream


fileStream


=


new


FileStream


(


_path


,


FileMode


.


Create


);



await


formFile


.


CopyToAsync


(


fileStream


);



_customer


.


Avatar


=


“/images/Avatar/”


+


_filename


;



await


_customerService


.


UpdateCustomerAsync


(


_customer


);



return


Created


(


WebUtility


.


UrlEncode


(


_customer


.


Avatar


),


_customer


);



}



return


BadRequest


();



}

对以上功能更为具体实现和注释见:230322_045shopDemo(Swagger通过IFormFile或IFormCollection参数实例实现文件上传)。



版权声明:本文为zhoujian_911原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。