https://www.cnblogs.com/savorboard/p/5586229.html
前言
在上篇文章主要介紹了DotNetCore項目狀況,本篇文章是我們在開發自己的項目中實際使用的,比較貼合實際應用,算是對中間件的一個深入使用了,不是簡單的Hello World,如果你覺得本篇文章對你有用的話,不妨點個【推薦】。
目錄
- 中間件(Middleware)的作用
- 中間件的運行方式
- 中間件(Middleware)和過濾器(Filter)的區別
- 什么情況我們需要中間件
- 怎么樣自定義自己的中間件
中間件(Middleware)的作用
我們知道,任何的一個web框架都是把http請求封裝成一個管道,每一次的請求都是經過管道的一系列操作,最終到達我們寫的代碼中。那么中間件就是在應用程序管道中的一個組件,用來攔截請求過程進行一些其他處理和響應。中間件可以有很多個,每一個中間件都可以對管道中的請求進行攔截,它可以決定是否將請求轉移給下一個中間件。
asp.net core 提供了IApplicationBuilder接口來讓把中間件注冊到asp.net的管道請求當中去,中間件是一個典型的AOP應用。 下面是一個微軟官方的一個中間件管道請求圖:

可以看到,每一個中間件都都可以在請求之前和之后進行操作。請求處理完成之后傳遞給下一個請求。
中間件的運行方式
默認情況下,中間件的執行順序根據Startup.cs文件中,在public void Configure(IApplicationBuilder app){} 方法中注冊的先后順序執行。
大概有3種方式可以在管道中注冊"中間件"
app.Use(),IApplicationBuilder接口原生提供,注冊等都用它。app.Run(),是一個擴展方法,它需要一個RequestDelegate委托,里面包含了Http的上下文信息,沒有next參數,因為它總是在管道最后一步執行。app.Map(),也是一個擴展方法,類似於MVC的路由,用途一般是一些特殊請求路徑的處理。如:www.example.com/token 等。
上面的Run,Map內部也是調用的Use,算是對IApplicationBuilder接口擴充,如果你覺得名字都不夠准確,那么下面這個擴展方法就是正宗的注冊中間件的了,也是功能最強大的。app.UseMiddleware<>(),沒錯,就是這個了。 為什么說功能強大呢?是因為它不但提供了注冊中間件的功能,還提供了依賴注入(DI)的功能,以后大部分情況就用它了。
中間件(Middleware)和過濾器(Filter)的區別
熟悉MVC框架的同學應該知道,MVC也提供了5大過濾器供我們用來處理請求前后需要執行的代碼。分別是AuthenticationFilter,AuthorizationFilter,ActionFilter,ExceptionFilter,ResultFilter。
根據描述,可以看出中間件和過濾器的功能類似,那么他們有什么區別?為什么又要搞一個中間件呢?
其實,過濾器和中間件他們的關注點是不一樣的,也就是說職責不一樣,干的事情就不一樣。
舉個栗子,中間件像是
埃辛諾斯戰刃,過濾器像是巨龍之怒,泰蕾苟薩的寄魂杖,你一個戰士拿着巨龍之怒,泰蕾苟薩的寄魂杖去戰場殺人,雖然都有傷害,但是你拿着法杖傷害低不說,還減屬性啊。
同作為兩個AOP利器,過濾器更貼合業務,它關注於應用程序本身,比如你看ActionFilter 和 ResultFilter,它都直接和你的Action,ActionResult交互了,是不是離你很近的感覺,那我有一些比如對我的輸出結果進行格式化啦,對我的請求的ViewModel進行數據驗證啦,肯定就是用Filter無疑了。它是MVC的一部分,它可以攔截到你Action上下文的一些信息,而中間件是沒有這個能力的。
什么情況我們需要中間件
那么,何時使用中間件呢?我的理解是在我們的應用程序當中和業務關系不大的一些需要在管道中做的事情可以使用,比如身份驗證,Session存儲,日志記錄等。其實我們的 asp.net core項目中本身已經包含了很多個中間件。
舉例,我們在新建一個 asp.net core應用程序的時候,默認生成的模板當中
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); loggerFactory.AddConsole(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
懶得去下載源碼了,我們使用Reflector去查看源碼:
//擴展方法`app.UseDeveloperExceptionPage();` public static class DeveloperExceptionPageExtensions { // Methods public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException("app"); } return UseMiddlewareExtensions.UseMiddleware<DeveloperExceptionPageMiddleware>(app, Array.Empty<object>()); } }
//擴展方法`app.UseStaticFiles();` public static class StaticFileExtensions { // Methods public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app) { if (app == null) { throw new ArgumentNullException("app"); } return UseMiddlewareExtensions.UseMiddleware<StaticFileMiddleware>(app, Array.Empty<object>()); } }
可以看到 app.UseDeveloperExceptionPage(),app.UseStaticFiles()等等都是通過中間件實現的。
