ASP.NET Core 1.0中的管道-中间件模式
ASP.NET Core 1.0借鑒了Katana項目的管道設計(Pipeline)。日志記錄、用戶認證、MVC等模塊都以中間件(Middleware)的方式注冊在管道中。顯而易見這樣的設計非常松耦合并且非常靈活,你可以自己定義任意功能的Middleware注冊在管道中。這一設計非常適用于“請求-響應”這樣的場景——消息從管道頭流入最后反向流出。
在本文中暫且為這種模式起名叫做“管道-中間件(Pipeline-Middleware)”模式吧。
本文將描述”管道-中間件模式”的“契約式”設計和“函數式”設計兩種方案。
一、什么是管道-中間件模式?
在此模式中抽象了一個類似管道的概念,所有的組件均以中間件的方式注冊在此管道中,當請求進入管道后:中間件依次對請求作出處理,然后從最后一個中間件開始處理響應內容,最終反向流出管道。
二、契約式設計
契約式設計是從面向對象的角度來思考問題,根據管道-中間件的理解,中間件(Middleware)有兩個職責:
| 1 2 3 4 5 | public? interface? IMiddleware { ???? Request ProcessRequest(Request request); ???? Response ProcessResponse(Response response); } |
管道(Pipeline)抽象應該能夠注冊中間件(Middleware):
| 1 2 3 4 5 6 7 8 9 | public? interface? IApplicationBuilder { ???? void? Use(IMiddleware middleware); ???? void? UseArrange(List<IMiddleware> middlewares); ???? Context Run(Context context); } |
實現IApplicationBuilder:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 3 2 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | public? class? ApplicationBuilder : IApplicationBuilder { ???? public? IWindsorContainer Container { get ; private? set ; } ???? private? readonly? List<IMiddleware> _middlewares; ???? public? ApplicationBuilder(IWindsorContainer container) ???? { ???????? Contract.Requires(container!= null , "container!=null" ); ???????? _middlewares= new? List<IMiddleware>(); ???????? Container = container; ???? } ???? public? void? Use(IMiddleware middleware) ???? { ???????? Contract.Requires(middleware != null , "middleware!=null" ); ???????? _middlewares.Add(middleware); ???? } ???? public? void? UseArrange(List<IMiddleware> middlewares) ???? { ???????? Contract.Requires(middlewares != null , "middlewares!=null" ); ???????? _middlewares.AddRange(middlewares); ???? } ???? public? Context Run(Context context) ???? { ???????? Contract.Requires(context!= null , "context!=null" ); ???????? var? request=context.Request; ???????? var? response=context.Response; ???????? foreach? ( var? middleware in? _middlewares) ???????? { ???????????? request = middleware.ProcessRequest(request); ???????? } ???????? _middlewares.Reverse(); ???????? foreach? ( var? middleware in? _middlewares) ???????? { ???????????? response = middleware.ProcessResponse(response); ???????? } ???????? return? new? Context(request,response); ???? } } |
Run()方法將依次枚舉Middleware并對消息的請求和響應進行處理,最后返回最終處理過的消息。
接下來需要實現一個Middleware:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public? class? DefaultMiddleware:IMiddleware ? { ????? public? Request ProcessRequest(Request request) ????? { ????????? request.Process( "default request" , "processed by defaultMiddleware" ); ????????? return? request; ????? } ????? public? Response ProcessResponse(Response response) ????? { ????????? response.Process( "default response" , "processed by defaultMiddleware" ); ????????? return? response; ????? } ? } |
為了將Middleware注冊進管道,我們還可以寫一個擴展方法增加代碼的可讀性:
| 1 2 3 4 5 6 7 8 9 10 11 12 | public? static? void? UseDefaultMiddleware( this? IApplicationBuilder applicationBuilder) { ???? applicationBuilder.Use<DefaultMiddleware>(); } public? static? void? Use<TMiddleware>( this? IApplicationBuilder applicationBuilder) ???? where? TMiddleware:IMiddleware { ???? var? middleware = applicationBuilder.Container.Resolve<TMiddleware>(); ???? applicationBuilder.Use(middleware); } |
寫個測試看看吧:
寫第二個Middleware:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 1 15 16 | public? class? GreetingMiddleware:IMiddleware { ???? public? Request ProcessRequest(Request request) ???? { ???????? request.Process( "hello, request" , "processed by greetingMiddleware" ); ???????? return? request; ???? } ???? public? Response ProcessResponse(Response response) ???? { ???????? response.Process( "hello, request" , "processed by greetingMiddleware" ); ???????? return? response; ???? } } |
編寫測試:
三、函數式設計方案
此方案也是Owin和ASP.NET Core采用的方案,如果站在面向對象的角度,第一個方案是非常清晰的,管道最終通過枚舉所有Middleware來依次處理請求。
站在函數式的角度來看,Middleware可以用Func<Context, Context>來表示,再來看看這張圖:
一個Middleware的邏輯可以用Func<Func<Context, Context>, Func<Context, Context>>來表示,整個Middleware的邏輯可以用下面的代碼描述:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public? Func<Func<Context, Context>, Func<Context, Context>> Process() { ???? Func<Func<Context, Context>, Func<Context, Context>> middleware = next => ???? { ???????? Func<Context, Context> process = context => ???????? { ???????????? /*process request*/ ??????????? ???????????? next(context); ???????????? /*process response*/ ???????????? return? context; ???????? }; ???????? return? process; ???? }; ???? return? middleware; } |
這一過程是理解函數式方案的關鍵,所有Middleware可以聚合為一個Func<Context,Context>,為了易于閱讀,我們可以定義一個委托:
| 1 | public? delegate? Context RequestDelegate(Context context); |
給定初始RequestDelegate,聚合所有Middleware:
| 1 2 3 4 5 6 7 8 9 10 11 1 13 | public? IApplication Build() { ???? RequestDelegate request = context => context; ???? _middlewares.Reverse(); ???? foreach? ( var? middleware in? _middlewares) ???? { ???????? request = middleware(request); ???? } ???? return? new? Application(request); } |
自定義一個函數式Middleware:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 8 19 20 21 22 | public? class? DefaultMiddleware:IMiddleware { ???? public? Func<RequestDelegate, RequestDelegate> Request() ???? { ???????? Func<RequestDelegate, RequestDelegate> request = next => ???????? { ???????????? return? context => ???????????? { ???????????????? context.Request.Process( "default request" , "processed by defaultMiddleware" ); ???????????????? next(context); ???????????????? context.Response.Process( "default response" , "processed by defaultMiddleware" ); ???????????????? return? context; ???????????? }; ???????? }; ???????? return? request; ???? } } |
所有代碼提供下載:https://git.oschina.net/richieyangs/Pipeline.Middleware.git
相關文章
ASP.NET Core 1.0 入門——Application Startup
ASP.NET Core 1.0 入門——了解一個空項目
ASP.NET Core 1.0 部署 HTTPS (.NET Framework 4.5.1)
.NET Core 1.0、ASP.NET Core 1.0和EF Core 1.0簡介
云服務器下ASP.NET Core 1.0環境搭建(包含mono與coreclr)
使用VS Code開發ASP.NET Core 應用程序
dotnet run是如何啟動asp.net core站點的
ASP.NET Core提供模塊化Middleware組件
“dotnet restore"和"dotnet run"都做了些什么?
探秘 dotnet run 如何運行 .NET Core 應用程序
.NET Portability Analyzer 已開源
.NET跨平臺之旅:corehost 是如何加載 coreclr 的
ASP.NET Core 行軍記 -----拔營啟程
如何遷移#SNMP到.NET Core平臺的一些體會
原文地址:http://www.cnblogs.com/richieyang/p/5315390.html
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的ASP.NET Core 1.0中的管道-中间件模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows 10中国定制版完工!更专
- 下一篇: ASP.NET 开发人员不必担心 Nod