轉:https://www.cnblogs.com/savorboard/p/5586229.html
中間件(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()
等等都是通過中間件實現的。