asp.net core 中间件详解及项目实战
前言
在上篇文章主要介紹了DotNetCore項(xiàng)目狀況,本篇文章是我們?cè)陂_(kāi)發(fā)自己的項(xiàng)目中實(shí)際使用的,比較貼合實(shí)際應(yīng)用,算是對(duì)中間件的一個(gè)深入使用了,不是簡(jiǎn)單的Hello World,如果你覺(jué)得本篇文章對(duì)你有用的話,不妨點(diǎn)個(gè)【推薦】。
目錄
中間件(Middleware)的作用
中間件的運(yùn)行方式
中間件(Middleware)和過(guò)濾器(Filter)的區(qū)別
什么情況我們需要中間件
怎么樣自定義自己的中間件
中間件(Middleware)的作用
我們知道,任何的一個(gè)web框架都是把http請(qǐng)求封裝成一個(gè)管道,每一次的請(qǐng)求都是經(jīng)過(guò)管道的一系列操作,最終到達(dá)我們寫(xiě)的代碼中。那么中間件就是在應(yīng)用程序管道中的一個(gè)組件,用來(lái)攔截請(qǐng)求過(guò)程進(jìn)行一些其他處理和響應(yīng)。中間件可以有很多個(gè),每一個(gè)中間件都可以對(duì)管道中的請(qǐng)求進(jìn)行攔截,它可以決定是否將請(qǐng)求轉(zhuǎn)移給下一個(gè)中間件。
asp.net core 提供了IApplicationBuilder接口來(lái)讓把中間件注冊(cè)到asp.net的管道請(qǐng)求當(dāng)中去,中間件是一個(gè)典型的AOP應(yīng)用。 下面是一個(gè)微軟官方的一個(gè)中間件管道請(qǐng)求圖:
可以看到,每一個(gè)中間件都都可以在請(qǐng)求之前和之后進(jìn)行操作。請(qǐng)求處理完成之后傳遞給下一個(gè)請(qǐng)求。
中間件的運(yùn)行方式
默認(rèn)情況下,中間件的執(zhí)行順序根據(jù)Startup.cs文件中,在public void Configure(IApplicationBuilder app){} 方法中注冊(cè)的先后順序執(zhí)行。
大概有3種方式可以在管道中注冊(cè)"中間件"
app.Use(),IApplicationBuilder接口原生提供,注冊(cè)等都用它。
app.Run() ,是一個(gè)擴(kuò)展方法,它需要一個(gè)RequestDelegate委托,里面包含了Http的上下文信息,沒(méi)有next參數(shù),因?yàn)樗偸窃诠艿雷詈笠徊綀?zhí)行。
app.Map(),也是一個(gè)擴(kuò)展方法,類(lèi)似于MVC的路由,用途一般是一些特殊請(qǐng)求路徑的處理。如:www.example.com/token 等。
上面的Run,Map內(nèi)部也是調(diào)用的Use,算是對(duì)IApplicationBuilder接口擴(kuò)充,如果你覺(jué)得名字都不夠準(zhǔn)確,那么下面這個(gè)擴(kuò)展方法就是正宗的注冊(cè)中間件的了,也是功能最強(qiáng)大的。
app.UseMiddleware<>(),沒(méi)錯(cuò),就是這個(gè)了。 為什么說(shuō)功能強(qiáng)大呢?是因?yàn)樗坏峁┝俗?cè)中間件的功能,還提供了依賴注入(DI)的功能,以后大部分情況就用它了。
中間件(Middleware)和過(guò)濾器(Filter)的區(qū)別
熟悉MVC框架的同學(xué)應(yīng)該知道,MVC也提供了5大過(guò)濾器供我們用來(lái)處理請(qǐng)求前后需要執(zhí)行的代碼。分別是AuthenticationFilter,AuthorizationFilter,ActionFilter,ExceptionFilter,ResultFilter。
根據(jù)描述,可以看出中間件和過(guò)濾器的功能類(lèi)似,那么他們有什么區(qū)別?為什么又要搞一個(gè)中間件呢?
其實(shí),過(guò)濾器和中間件他們的關(guān)注點(diǎn)是不一樣的,也就是說(shuō)職責(zé)不一樣,干的事情就不一樣。
舉個(gè)栗子,中間件像是埃辛諾斯戰(zhàn)刃,過(guò)濾器像是巨龍之怒,泰蕾茍薩的寄魂杖 ,你一個(gè)戰(zhàn)士拿著巨龍之怒,泰蕾茍薩的寄魂杖去戰(zhàn)場(chǎng)殺人,雖然都有傷害,但是你拿著法杖傷害低不說(shuō),還減屬性啊。
同作為兩個(gè)AOP利器,過(guò)濾器更貼合業(yè)務(wù),它關(guān)注于應(yīng)用程序本身,比如你看ActionFilter 和 ResultFilter,它都直接和你的Action,ActionResult交互了,是不是離你很近的感覺(jué),那我有一些比如對(duì)我的輸出結(jié)果進(jìn)行格式化啦,對(duì)我的請(qǐng)求的ViewModel進(jìn)行數(shù)據(jù)驗(yàn)證啦,肯定就是用Filter無(wú)疑了。它是MVC的一部分,它可以攔截到你Action上下文的一些信息,而中間件是沒(méi)有這個(gè)能力的。
什么情況我們需要中間件
那么,何時(shí)使用中間件呢?我的理解是在我們的應(yīng)用程序當(dāng)中和業(yè)務(wù)關(guān)系不大的一些需要在管道中做的事情可以使用,比如身份驗(yàn)證,Session存儲(chǔ),日志記錄等。其實(shí)我們的 asp.net core項(xiàng)目中本身已經(jīng)包含了很多個(gè)中間件。
舉例,我們?cè)谛陆ㄒ粋€(gè) asp.net core應(yīng)用程序的時(shí)候,默認(rèn)生成的模板當(dāng)中
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去查看源碼:
//擴(kuò)展方法`app.UseDeveloperExceptionPage();`public static class DeveloperExceptionPageExtensions{ ? ?// Methodspublic static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app) ? ?{ ? ? ? ?if (app == null){ ? ? ? ? ? ?throw new ArgumentNullException("app");} ? ? ? ?return UseMiddlewareExtensions.UseMiddleware<DeveloperExceptionPageMiddleware>(app, Array.Empty<object>());} } //擴(kuò)展方法`app.UseStaticFiles();`public static class StaticFileExtensions{ ? // Methodspublic 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()等等都是通過(guò)中間件實(shí)現(xiàn)的。
怎么樣自定義自己的中間件
背景:我們項(xiàng)目使用到中間件的情景是,需要和其他部門(mén)進(jìn)行用戶(User)信息的共享。 以平臺(tái)和子系統(tǒng)舉例,我們正在開(kāi)發(fā)一個(gè)子系統(tǒng),其中用戶信息,登錄,注冊(cè)等功能是放在平臺(tái)上的,這是一個(gè)跨多語(yǔ)言的系統(tǒng),平臺(tái)是Java語(yǔ)言開(kāi)發(fā),用戶在訪問(wèn)子系統(tǒng)的一些頁(yè)面的時(shí)候需要驗(yàn)證是否登錄,另外一些頁(yè)面是不需要驗(yàn)證是否登錄的,所以需要一個(gè)身份驗(yàn)證系統(tǒng)來(lái)代替Identity的功能。
幸運(yùn)的是微軟已經(jīng)給我們提供了一套身份驗(yàn)證的中間件,在Microsoft.AspNetCore.Authentication命名空間下,我們只需要拓展,添加自己的功能就行了 。具體怎么做呢?直接看代碼吧。
根據(jù)約定俗成,中間件類(lèi)需要有一個(gè)Invoke方法,簽名是public async Task Invoke(HttpContext context){},下面是一個(gè)中間件的示例類(lèi):
public class RequestLoggerMiddleware{ ? ?private readonly RequestDelegate _next; ? ?private readonly ILogger _logger; ? ?public RequestLoggerMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) ? ?{_next = next;_logger = loggerFactory.CreateLogger<RequestLoggerMiddleware>();} ? ?public async Task Invoke(HttpContext context) ? ?{_logger.LogInformation("Handling request: " + context.Request.Path); ? ? ? ?await _next.Invoke(context);_logger.LogInformation("Finished handling request.");} }了解了上面的約定之后,我們就開(kāi)始定義我們自己的中間件Class。
我們需要一個(gè)流程圖來(lái)理清邏輯思路,以便于寫(xiě)代碼的時(shí)候思路更加的清晰。
平臺(tái)有一個(gè)要求就是,用戶在我們子系統(tǒng)退出之后,要調(diào)用平臺(tái)的一個(gè)接口通知他們,他們要做一些后續(xù)的業(yè)務(wù)。
OK,開(kāi)始擼碼。
首先創(chuàng)建一個(gè)PlatformAuthoricationMiddleware,它繼承于Microsoft.AspNetCore.Authentication下的類(lèi)AuthenticationMiddleware,由于AuthenticationMiddleware已經(jīng)實(shí)現(xiàn)了Invoke功能,所以我們只需要重寫(xiě)(override)它里面的一些方法就可以了。等等,我們好像還需要一些配置,比如流程圖中的ReturnUrl,平臺(tái)的Cookie的Key值,平臺(tái)驗(yàn)證用戶合法性的接口地址等參數(shù)。
建立一個(gè)Options類(lèi)進(jìn)行配置的設(shè)置,我們?nèi)∶譃?#xff1a;PlatformAuthenticationOptions,繼承AuthenticationOptions,并且實(shí)現(xiàn)掉IOptions<T>接口,這樣子就能在Startup中直接配置了。
我們只需要重寫(xiě)AuthenticationMiddleware中的CreateHandler方法就行了,在Handler中可以實(shí)現(xiàn)掉我們中間件的功能。
然后創(chuàng)建一個(gè)處理的Handler類(lèi),取名為PlatformAuthenticationHandler,繼承于AuthenticationHandler<TOptions>用來(lái)處理請(qǐng)求中的調(diào)用。
至此,我們的核心需要的類(lèi)已經(jīng)建立完了,剩下的就是填充代碼。
在PlatformAuthenticationHandler中重寫(xiě)HandleAuthenticateAsync()方法 , 進(jìn)行主流程的控制。
在PlatformAuthenticationHandler中重寫(xiě)FinishResponseAsync()方法,進(jìn)行Session的存儲(chǔ)操作。
在PlatformAuthenticationHandler中重寫(xiě)HandleSignOutAsync()方法,進(jìn)行登出的控制,因?yàn)橛脩舻浅鲋笪覀円ㄖ脚_(tái)做一些其他操作。
在PlatformAuthenticationHandler中重寫(xiě)HandleUnauthorizedAsync()方法,進(jìn)行未認(rèn)證操作。
最后,我們需要一個(gè)擴(kuò)展類(lèi)來(lái)把我們的中間件以擴(kuò)展方法注冊(cè)到管道當(dāng)中去 。
public static class MiddlewareExtensions{ ? ?public static IApplicationBuilder UsePlatformAuthentication(this IApplicationBuilder app) { ? ? ? ?if (app == null) { ? ? ? ? ? ?throw new ArgumentNullException(nameof(app));} ? ? ? ?return app.UseMiddleware<PlatformAuthenticationMiddleware>();} ? ?public static IApplicationBuilder UsePlatformAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options) { ? ? ? ?if (app == null) { ? ? ? ? ? ?throw new ArgumentNullException(nameof(app));} ? ? ? ?if (options == null) { ? ? ? ? ? ?throw new ArgumentNullException(nameof(options));} ? ? ? ?return app.UseMiddleware<PlatformAuthenticationMiddleware>(Options.Create(options));} }在Startup中就是app.UsePlatformAuthentication()
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {loggerFactory.AddConsole(Configuration.GetSection("Logging")); ? ?//注冊(cè)PlatformAuthentication中間件app.UsePlatformAuthentication(new PlatformAuthenticationOptions() {UserSessionStore = new UserSessionStore(),});app.UseMvc(); }現(xiàn)在,我們的中間件核心業(yè)務(wù)流程的實(shí)現(xiàn)已經(jīng)出來(lái)了,我就不大篇幅的粘貼代碼了,會(huì)影響閱讀,感興趣具體實(shí)現(xiàn)的朋友可以去下面的地址查看代碼,有具體流程的注釋。
示例源碼:
https://github.com/yuleyule66/PlatformAuthMiddleware
相關(guān)文章:
ASP.NET Core 1.0 入門(mén)——了解一個(gè)空項(xiàng)目
ASP.NET Core 1.0 部署 HTTPS (.NET Framework 4.5.1)
.NET Core 1.0、ASP.NET Core 1.0和EF Core 1.0簡(jiǎn)介
云服務(wù)器下ASP.NET Core 1.0環(huán)境搭建(包含mono與coreclr)
使用VS Code開(kāi)發(fā)ASP.NET Core 應(yīng)用程序
dotnet run是如何啟動(dòng)asp.net core站點(diǎn)的
ASP.NET Core提供模塊化Middleware組件
“dotnet restore"和"dotnet run"都做了些什么?
探秘 dotnet run 如何運(yùn)行 .NET Core 應(yīng)用程序
.NET Portability Analyzer 已開(kāi)源
ASP.NET Core的配置(1):讀取配置信息
ASP.NET Core的配置(2):配置模型詳解
.NET Core 1.0 RC2 歷險(xiǎn)之旅
使用VS Code開(kāi)發(fā) 調(diào)試.NET Core 應(yīng)用程序
讓我們Core在一起:ASP.NET Core & .NET Core
.NET Core VS Code 環(huán)境配置
官方博客明確了 .NET Core RC2/RTM 時(shí)間表
.NET Core全新的配置管理[共9篇]
利用記事本創(chuàng)建一個(gè)ASP.NET Core RC2 MVC應(yīng)用
微軟.NET 正式劈腿成功,橫跨所有平臺(tái)
.NET Core 1.0 CentOS7 嘗試
解讀發(fā)布:.NET Core RC2 and .NET Core SDK Preview 1
[.NET Core].NET Core R2安裝及示例教程
ASP.NET Core 開(kāi)發(fā)-中間件(Middleware)
結(jié)合Jexus + Kestrel 部署 asp.net core 生產(chǎn)環(huán)境
通過(guò)Jexus 部署 dotnetcore版本MusicStore 示例程序
ASP.NET Core 中文文檔 第一章 入門(mén)
用 Visual Studio Code 在 macOS 上創(chuàng)建首個(gè) ASP.NET Core 應(yīng)用程序
用 Visual Studio 和 ASP.NET Core MVC 創(chuàng)建首個(gè) Web API
用 Visual Studio 發(fā)布一個(gè) Azure 云 Web 應(yīng)用程序
ASP.NET Core MVC 與 Visual Studio 入門(mén)
第二章指南(4.2)添加 Controller
DotNet Core 介紹
原文地址:http://www.cnblogs.com/savorboard/p/5586229.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的asp.net core 中间件详解及项目实战的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 第二章 指南(4.3)添加 View
- 下一篇: 聊聊ASP.NET Core默认提供的这