成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

解讀ASP.NET 5 & MVC6系列(6):Middleware詳解

移動開發(fā) Android
在第1章項目結(jié)構(gòu)分析中,我們提到Startup.cs作為整個程序的入口點,等同于傳統(tǒng)的Global.asax文件,即:用于初始化系統(tǒng)級的信息(例如,MVC中的路由配置)。本章我們就來一一分析,在這里如何初始化這些系統(tǒng)級的信息。

 在第1章項目結(jié)構(gòu)分析中,我們提到Startup.cs作為整個程序的入口點,等同于傳統(tǒng)的Global.asax文件,即:用于初始化系統(tǒng)級的信息(例如,MVC中的路由配置)。本章我們就來一一分析,在這里如何初始化這些系統(tǒng)級的信息。

新舊版本之間的Pipeline區(qū)別

ASP.NET 5和之前版本的***區(qū)別是對HTTP Pipeline的全新重寫,在之前的版本中,請求過濾器的通常是以HttpModule為模塊組件,這些組件針對HttpApplication里定義的各個周期內(nèi)的事件進行響應(yīng),從而用于實現(xiàn)認證、全局錯誤處理、日志等功能。傳統(tǒng)的Form表單認證就是一個HTTPModule。HTTPModule不僅能夠過濾Request請求,還可以和Response響應(yīng)進行交互并修改。這些HTTPModule組件都繼承于IHttpModule接口,而該接口是位于System.Web.dll中。

HttpModule代碼不僅可以在Global.asax中的各事件周期中進行添加,還可以單獨編譯成類庫并在web.config中進行注冊。新版的ASP.NET 5拋棄了重量級的System.Web.dll,相應(yīng)地引入了Middleware的概念,Middleware的官方定義如下:

Pass through components that form a pipeline between a server and application to inspect, route, or modify request and response messages for a specific purpose.

在服務(wù)器和應(yīng)用程序之間的管線Pipeline之間,針對特定的目的,穿插多個Middleware組件,從而對request請求和response響應(yīng)進行檢

查、路由、或修改。該定義和傳統(tǒng)的HttpModule以及HttpHandler特別像。

Middleware的注冊和配置

在ASP.NET5中,request請求管線(Pipeline)的訪問是在Startup類中進行的,該類時一個約定類,并且里面的ConfigureServices方法、Configure方法、以及相應(yīng)的參數(shù)也是事先約定的,所以不能進行改動。

Middleware中的依賴處理:ConfigureServices方法

在ASP.NET5中的各種默認的Middleware中,都使用了依賴注入的功能,所以在使用Middleware中的功能時,需要提前將依賴注入所需要的類型及映射關(guān)系都注冊到依賴注入管理系統(tǒng)中,即IServiceCollection集合,而ConfigureServices方法接收的就一個IServiceCollection類型的參數(shù),該參數(shù)就是所有注冊過類型的集合,通過原生的依賴注入組件進行管理(關(guān)于ASP.NET5中的依賴注入,我們會在單獨章節(jié)中進行講解),在該方法內(nèi),我們可以向該集合中添加新的類型和類型映射關(guān)系,示例如下:

  1. // Add MVC services to the services container. 
  2. services.AddMvc(); 

示例中的代碼用于向系統(tǒng)添加Mvc模塊相關(guān)的Service類型以支撐MVC功能,該方法是一個擴展方法,用于在集合中添加與MVC相關(guān)的多個類型。

Middleware的注冊和配置:Configure方法

Configure方法的簽名如下:

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) 
  2.     // ... 

Configure方法接收了三個參數(shù):IApplicationBuilder類型的參數(shù)用于構(gòu)建整個應(yīng)用程序的配置信息,IHostingEnvironment類的env參數(shù)用于訪問系統(tǒng)環(huán)境變量相關(guān)的內(nèi)容,ILoggerFactory類型的loggerfactory用于日志相關(guān)的內(nèi)容處理,其中IApplicationBuilder類型的參數(shù)最為重要,該參數(shù)實例app上有一系列的擴展方法用于將各種Middleware注冊到request請求管線(Pipeline)中。這種方式和之前ASP.NET中的HTTP管線的主要區(qū)別是:新版本中的組合模型替換了舊版本中的事件模型。這也就要求,在新版ASP.NET中,Middleware組件注冊的順序是非常重要的,因為后一個組件可能要使用到前一個組件,所以必須按照依賴的先后順序進行注冊,舉例如下,當前MVC項目的模板代碼示例如下

  1. // Add static files to the request pipeline. 
  2. app.UseStaticFiles(); 
  3.  
  4. // Add cookie-based authentication to the request pipeline. 
  5. app.UseIdentity(); 
  6.  
  7. // Add MVC to the request pipeline. 
  8. app.UseMvc(routes =>{ /*...*/}); 

示例中的UseStaticFiles、UseIdentity、UseMvc都是IApplicationBuilder上的擴展方法,在擴展方法中,都會通過調(diào)用擴展方法app.UseMiddleware方法,最終再調(diào)用app.Use方法來注冊新的Middleware,該方法定義如下:

  1. public interface IApplicationBuilder 
  2.     //... 
  3.     IApplicationBuilder Use(Func 

通過代碼,可以看出,middleware是Func

  1. public delegate Task RequestDelegate(HttpContext context); 

通過源碼,我們可以看出,RequestDelegate是一個委托函數(shù),其接收HttpContext類型的實例,并返回一個Task類型的異步對象。也就是說RequestDelegate是一個可以返回自身RequestDelegate類型函數(shù)的函數(shù),整個ASP.NET也就是利用這種方式構(gòu)建了管線(Pipelien)的組成,在這里,每個middleware都鏈式到下一個middleware上,并在整個過程中可以對HttpConext對象進行修改或維護,當然,HttpContext中就包括了我們常操作的HttpRequest和HttpResponse實例對象。

注意:HttpContext、HttpRequest、HttpResponse在ASP.NET 5中都是重新定義的新類型。

Middleware的定義

既然每個middleare都是Func

構(gòu)造函數(shù)的***個參數(shù)必須是處理管線中的下一個處理函數(shù),即RequestDelegate;

必須有一個 Invoke 函數(shù), 并接受上下文參數(shù)(即HttpContent), 然后返回 Task;

示例如下:

  1. public class MiddlewareName 
  2.     RequestDelegate _next; 
  3.  
  4.     public MiddlewareName(RequestDelegate next) 
  5.     { 
  6.         _next = next;// 接收傳入的RequestDelegate實例 
  7.     } 
  8.  
  9.     public async Task Invoke(HttpContext context) 
  10.     { 
  11.         // 處理代碼,如處理context.Request中的內(nèi)容 
  12.  
  13.         Console.WriteLine("Middleware開始處理"); 
  14.  
  15.         await _next(context); 
  16.  
  17.         Console.WriteLine("Middleware結(jié)束處理"); 
  18.  
  19.         // 處理代碼,如處理context.Response中的內(nèi)容 
  20.     } 

通過該模板代碼可以看到,首先一個Middleware的構(gòu)造函數(shù)要接收一個RequestDelegate的實例,先保存在一個私有變量里,然后通過調(diào)用Invoke方法(并接收HttpContent實例)并返回一個Task,并且在調(diào)用Invoke的方法中,要通過await _next(context);語句,鏈式到下一個Middleware上,我們的處理代碼主要就是在鏈式語句的前后執(zhí)行相關(guān)的代碼。

舉個例子,如果我們要想記錄頁面的執(zhí)行時間,首先,我們先定義一個TimeRecorderMiddleware,代碼如下:

  1. public class TimeRecorderMiddleware 
  2.     RequestDelegate _next; 
  3.  
  4.     public TimeRecorderMiddleware(RequestDelegate next) 
  5.     { 
  6.         _next = next; 
  7.     } 
  8.  
  9.     public async Task Invoke(HttpContext context) 
  10.     { 
  11.         var sw = new Stopwatch(); 
  12.         sw.Start(); 
  13.  
  14.  
  15.         await _next(context); 
  16.  
  17.         var newDiv = @" 
  18. 頁面處理時間:{0} 毫秒 
  19. "; 
  20.         var text = string.Format(newDiv, sw.ElapsedMilliseconds); 
  21.         await context.Response.WriteAsync(text); 
  22.     } 
  23. }

Middleware的注冊有很多種方式,如下是實例型注冊代碼:

  1. app.Use(next => new TimeRecorderMiddleware(next).Invoke); 

或者,你也可以使用UseMiddleware擴展方法進行注冊,示例如下:

  1. app.UseMiddleware(); //app.UseMiddleware(typeof(TimeRecorderMiddleware)); 兩種方式都可以

當然,你也可以定義一個自己的擴展方法用于注冊該Middleware,代碼如下:

  1. public static IApplicationBuilder UseTimeRecorderMiddleware(this IApplicationBuilder app) 
  2.     return app.UseMiddleware(); }

***在Startup類的Configure方法內(nèi)進行注冊,代碼如下:

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) 
  2.     app.UseTimeRecorderMiddleware(); // 要放在前面,以便進行統(tǒng)計,如果放在Mvc后面的話,就統(tǒng)計不了時間了。 
  3.  
  4.     // 等等 
  5.  
  6.   

編譯,重啟,并訪問頁面,在頁面的底部即可看到頁面的運行時間提示內(nèi)容。

常用Middleware功能的使用

app.UseErrorPage()

在IHostingEnvironment.EnvironmentName為Development的情況下,才顯示錯誤信息,并且錯誤信息的顯示種類,可以通過額外的ErrorPageOptions參數(shù)來設(shè)定,可以設(shè)置全部顯示,也可以設(shè)置只顯示Cookies、Environment、ExceptionDetails、Headers、Query、SourceCode SourceCodeLineCount中的一種或多種。

  1. app.UseErrorHandler("/Home/Error"

捕獲所有的程序異常錯誤,并將請求跳轉(zhuǎn)至指定的頁面,以達到友好提示的目的。

  1. app.UseStaticFiles() 

開啟靜態(tài)文件也能走該Pipeline管線處理流程的功能。

  1. app.UseIdentity() 

開啟以cookie為基礎(chǔ)的ASP.NET identity認證功能,以支持Pipeline請求處理。

直接使用委托定義Middleware的功能

由于Middleware是Func

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) 
  2.    app.Use(new Func 

做個簡便的Middleware基類

雖然有約定方法,但有時候我們在開發(fā)的時候往往會犯迷糊,想不起來到底是什么樣的約定,所以,在這里我們可以定義一個抽象基類,然后以后所有的Middleware在定義的時候都繼承該抽象類并重載Invoke方法即可,從而可以避免約定忘記的問題。代碼如下:

  1. ///  /// 抽象基類 ///  
  2. public abstract class AbstractMiddleware 
  3.     protected RequestDelegate Next { get; set; } 
  4.     protected AbstractMiddleware(RequestDelegate next) 
  5.     { 
  6.         this.Next = next; 
  7.     } 
  8.     public abstract Task Invoke(HttpContext context); 
  9.  
  10. ///  /// 示例Middleware ///  
  11. public class DemoMiddleware : AbstractMiddleware 
  12.     public DemoMiddleware(RequestDelegate next) : base(next) 
  13.     { 
  14.     } 
  15.     public async override Task Invoke(HttpContext context) 
  16.     { 
  17.         Console.WriteLine("DemoMiddleware Start."); 
  18.         await Next.Invoke(context); 
  19.         Console.WriteLine("DemoMiddleware End."); 
  20.     } 
  21.  
  22.   

使用方法和上面的一樣。

終止鏈式調(diào)用或阻止所有的Middleware

在有些情況下,當然根據(jù)某些條件判斷以后,可能不在需要繼續(xù)往下執(zhí)行下去了,而是想知己誒返回結(jié)果,那么你可以在你的Middleware里忽略對await next.Invoke(content);的調(diào)用,直接使用·Response.WriteAsync·方法輸出內(nèi)容。

另外,在有些情況下,你可能需要實現(xiàn)類似之前版本中的handler的功能,即不經(jīng)常任何Pipeline直接對Response進行響應(yīng),新版ASP.NET里提供了一個run方法用于實現(xiàn)該功能,只需要在Configure方法里調(diào)用如下代碼即可實現(xiàn)類似的內(nèi)容輸出

  1. app.Run(async context => 
  2.     context.Response.ContentType = "text/html"
  3.     await context.Response.WriteAsync("Hello World!"); 
  4. }); 

關(guān)于ASP.NET 5 Runtime的內(nèi)容,請訪問:https://msdn.microsoft.com/en-us/magazine/dn913182.aspx

遺留問題

在Mvc項目中,所有的依賴注入類型都是通過IServiceProvider實例來獲取的,目前可以通過以下形式獲取該實例:

var services = Context.RequestServices; // Controller中
var services = app.ApplicationServices; // Startup中

獲取了該實例以后,即可通過如下方法來獲取某個類型的對象:

var controller = (AccountController)services.GetService(typeof(AccountController));
// 要判斷獲取到的對象是否為null

如果你引用了Microsoft.Framework.DependencyInjection命名空間的話,還可以使用如下三種擴展方法:

var controller2 = (AccountController)services.GetService();   // 要判斷獲取到的對象是否為null  //如下兩種方式,如果獲取到的AccountController實例為null的話,就會字段拋異常,而不是返回null var controller3 = (AccountController)services.GetRequiredService(typeof(AccountController)); var controller4 = (AccountController)services.GetRequiredService();

那么問題來了?如何不在Startup和Controller里就可以獲取到HttpContext和IApplicationBuilder實例以便使用這些依賴注入服務(wù)?

如何獲取IApplicationBuilder實例?

答案:在Startup里將IApplicationBuilder實例保存在一個單例中的變量上,后期全站就可以使用了。

如何獲取HttpContext實例?

答案:參考依賴注入章節(jié)的普通類的依賴注入

引用:http://www.mikesdotnetting.com/article/269/asp-net-5-middleware-or-where-has-my-httpmodule-gone

責任編輯:chenqingxiang 來源: 湯姆大叔的博客
相關(guān)推薦

2015-06-29 10:00:02

ASP.NETMVC6

2015-06-18 16:29:14

ASP.NET

2015-06-16 15:01:59

ASP.NET 5

2015-06-17 16:01:30

ASP.NET

2015-06-17 16:45:28

ASP.NET

2015-06-18 14:13:36

ASP.NET

2015-06-18 16:39:17

ASP.NET

2015-06-18 17:04:22

ASP.NET

2015-06-17 16:04:36

ASP.NET

2015-06-17 17:01:48

ASP.NET

2015-06-17 10:16:30

ASP.NET

2015-06-18 17:37:19

ASP.NET

2015-06-17 14:16:50

ASP.NET

2015-06-17 14:09:36

ASP.NET

2015-06-17 14:18:50

ASP.NET

2015-06-18 17:34:25

ASP.NET

2015-06-18 14:25:56

ASP.NET

2015-06-30 14:58:20

技術(shù)周刊

2014-08-26 09:22:40

ASP.NET MVCRouting

2010-03-19 09:17:16

ASP.NET MVC
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 日韩午夜在线观看 | 天天久久 | 一级欧美一级日韩片免费观看 | 韩日免费视频 | 久久不卡 | 久久aⅴ乱码一区二区三区 亚洲国产成人精品久久久国产成人一区 | 亚洲精品日韩一区二区电影 | 国产区在线观看 | www.亚洲成人网 | 欧美视频第三页 | 激情三区 | 国产精品久久久久久久久久久久久 | 国产精品久久777777 | 国产欧美精品一区二区色综合朱莉 | 美女爽到呻吟久久久久 | 颜色网站在线观看 | 日韩av在线一区 | 国产91网站在线观看 | 亚洲视频免费 | 成人免费视频观看视频 | 在线免费观看a级片 | 在线视频亚洲 | 精产国产伦理一二三区 | 我爱操 | 超碰成人在线观看 | 国产探花在线精品一区二区 | 国产中文视频 | 久久精品国产99国产精品 | 亚洲精品久久久久久久久久久久久 | 欧美在线一区二区三区 | 91国产精品| 亚洲欧美视频一区 | 性色的免费视频 | 亚洲欧美久久 | 四虎影院在线免费观看 | 日本高清视频在线播放 | 国产精品视频一区二区三 | 国产精品九九视频 | 久久大全 | 国产在线激情视频 | 精品国产一区二区三区久久久蜜月 |