<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

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

        來源:懂視網 責編:小采 時間:2020-11-27 22:37:02
        文檔

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

        解讀ASP.NET 5 & MVC6系列教程(6):Middleware詳解:在第1章項目結構分析中,我們提到Startup.cs作為整個程序的入口點,等同于傳統的Global.asax文件,即:用于初始化系統級的信息(例如,MVC中的路由配置)。本章我們就來一一分析,在這里如何初始化這些系統級的信息。 新舊版本之間的Pipeline區別 A
        推薦度:
        導讀解讀ASP.NET 5 & MVC6系列教程(6):Middleware詳解:在第1章項目結構分析中,我們提到Startup.cs作為整個程序的入口點,等同于傳統的Global.asax文件,即:用于初始化系統級的信息(例如,MVC中的路由配置)。本章我們就來一一分析,在這里如何初始化這些系統級的信息。 新舊版本之間的Pipeline區別 A

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

        新舊版本之間的Pipeline區別

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

        HttpModule代碼不僅可以在Global.asax中的各事件周期中進行添加,還可以單獨編譯成類庫并在web.config中進行注冊。

        新版的ASP.NET 5拋棄了重量級的System.Web.dll,相應地引入了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.
        在服務器和應用程序之間的管線Pipeline之間,針對特定的目的,穿插多個Middleware組件,從而對request請求和response響應進行檢
        查、路由、或修改。

        該定義和傳統的HttpModule以及HttpHandler特別像。

        Middleware的注冊和配置

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

        Middleware中的依賴處理:ConfigureServices方法

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

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

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

        Middleware的注冊和配置:Configure方法

        Configure方法的簽名如下:

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
        {
         // ...
        }

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

        // Add static files to the request pipeline.
        app.UseStaticFiles();
        
        // Add cookie-based authentication to the request pipeline.
        app.UseIdentity();
        
        // Add MVC to the request pipeline.
        app.UseMvc(routes =>{ /*...*/});

        示例中的UseStaticFilesUseIdentityUseMvc都是IApplicationBuilder上的擴展方法,在擴展方法中,都會通過調用擴展方法app.UseMiddleware方法,最終再調用app.Use方法來注冊新的Middleware,該方法定義如下:

        public interface IApplicationBuilder
        {
         //...
         IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
        }

        通過代碼,可以看出,middleware是Func<RequestDelegate, RequestDelegate>的一個實例,該Func接收一個RequestDelegate的參數,并返回一個RequestDelegate類型的值。RequestDelegate的源碼如下:

        public delegate Task RequestDelegate(HttpContext context);

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

        注意:HttpContextHttpRequestHttpResponse在ASP.NET 5中都是重新定義的新類型。

        Middleware的定義

        既然每個middleare都是Func<RequestDelegate, RequestDelegate>的一個實例,那是不是Middleware的定義要滿足一個規則?是繼承于一個抽象基類還是借口?通過翻查相關的代碼,我們看到,Middleware是基于約定的形式來定義的,具體約定規則如下:

        構造函數的第一個參數必須是處理管線中的下一個處理函數,即RequestDelegate;必須有一個 Invoke 函數, 并接受上下文參數(即HttpContent), 然后返回 Task;

        示例如下:

        public class MiddlewareName
        {
         RequestDelegate _next;
        
         public MiddlewareName(RequestDelegate next)
         {
         _next = next;// 接收傳入的RequestDelegate實例
         }
        
         public async Task Invoke(HttpContext context)
         {
         // 處理代碼,如處理context.Request中的內容
        
         Console.WriteLine("Middleware開始處理");
        
         await _next(context);
        
         Console.WriteLine("Middleware結束處理");
        
         // 處理代碼,如處理context.Response中的內容
         }
        }

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

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

        public class TimeRecorderMiddleware
        {
         RequestDelegate _next;
        
         public TimeRecorderMiddleware(RequestDelegate next)
         {
         _next = next;
         }
        
         public async Task Invoke(HttpContext context)
         {
         var sw = new Stopwatch();
         sw.Start();
        
        
         await _next(context);
        
         var newDiv = @"<div id=""process"">頁面處理時間:{0} 毫秒</div></body>";
         var text = string.Format(newDiv, sw.ElapsedMilliseconds);
         await context.Response.WriteAsync(text);
         }
        }

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

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

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

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

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

        public static IApplicationBuilder UseTimeRecorderMiddleware(this IApplicationBuilder app)
        {
         return app.UseMiddleware<TimeRecorderMiddleware>();
        }

        最后在Startup類的Configure方法內進行注冊,代碼如下:

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
        {
         app.UseTimeRecorderMiddleware(); // 要放在前面,以便進行統計,如果放在Mvc后面的話,就統計不了時間了。
        
         // 等等
        }

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

        常用Middleware功能的使用

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

        app.UseErrorHandler("/Home/Error")
        捕獲所有的程序異常錯誤,并將請求跳轉至指定的頁面,以達到友好提示的目的。

        app.UseStaticFiles()
        開啟靜態文件也能走該Pipeline管線處理流程的功能。

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

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

        由于Middleware是Func<RequestDelegate, RequestDelegate>委托類型的實例,所以我們也可以不必定義一個單獨的類,在Startup類里,使用委托調用的方式就可以了,示例如下:

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
        {
         app.Use(new Func<RequestDelegate, RequestDelegate>(next => content => Invoke(next, content)));
         // 其它
        }
        
        // 注意Invoke方法的參數
        private async Task Invoke(RequestDelegate next, HttpContext content)
        {
         Console.WriteLine("初始化組件開始");
         await next.Invoke(content);
         Console.WriteLine("管道下步執行完畢");
        }

        做個簡便的Middleware基類

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

        /// <summary>
        /// 抽象基類
        /// </summary>
        public abstract class AbstractMiddleware
        {
         protected RequestDelegate Next { get; set; }
         protected AbstractMiddleware(RequestDelegate next)
         {
         this.Next = next;
         }
         public abstract Task Invoke(HttpContext context);
        }
        
        /// <summary>
        /// 示例Middleware
        /// </summary>
        public class DemoMiddleware : AbstractMiddleware
        {
         public DemoMiddleware(RequestDelegate next) : base(next)
         {
         }
         public async override Task Invoke(HttpContext context)
         {
         Console.WriteLine("DemoMiddleware Start.");
         await Next.Invoke(context);
         Console.WriteLine("DemoMiddleware End.");
         }
        }

        使用方法和上面的一樣。

        終止鏈式調用或阻止所有的Middleware

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

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

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

        關于ASP.NET 5 Runtime的內容,請訪問: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<AccountController>(); 
        // 要判斷獲取到的對象是否為null
        
        //如下兩種方式,如果獲取到的AccountController實例為null的話,就會字段拋異常,而不是返回null
        var controller3 = (AccountController)services.GetRequiredService(typeof(AccountController));
        var controller4 = (AccountController)services.GetRequiredService<AccountController>();

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

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

        如何獲取HttpContext實例?
        答案:參考依賴注入章節的普通類的依賴注入

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

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

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

        解讀ASP.NET 5 & MVC6系列教程(6):Middleware詳解:在第1章項目結構分析中,我們提到Startup.cs作為整個程序的入口點,等同于傳統的Global.asax文件,即:用于初始化系統級的信息(例如,MVC中的路由配置)。本章我們就來一一分析,在這里如何初始化這些系統級的信息。 新舊版本之間的Pipeline區別 A
        推薦度:
        標簽: 系列 &amp; ):
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 精品丝袜国产自在线拍亚洲| 免费h片在线观看网址最新| 亚洲一级毛片在线播放| 亚洲女久久久噜噜噜熟女| 性感美女视频在线观看免费精品| 久久综合九色综合97免费下载 | h视频在线观看免费完整版| 国产精品免费久久| 另类图片亚洲校园小说区| 亚洲日韩看片无码电影| 亚洲天堂一区二区三区| 亚洲人成影院在线| 亚洲AV无码国产丝袜在线观看| 国产成人精品久久亚洲| 国产jizzjizz免费看jizz| 精品国产麻豆免费网站| 最近中文字幕免费mv视频7| 四虎1515hh永久久免费| 91青青青国产在观免费影视| 男女午夜24式免费视频| 黄色网站软件app在线观看免费 | 亚洲国产婷婷香蕉久久久久久| 免费观看一级毛片| 在线jyzzjyzz免费视频| 午夜老司机免费视频| 久久不见久久见中文字幕免费 | 亚洲日本va在线观看| 亚洲乱码在线播放| 亚洲人成免费电影| 国产成人亚洲合集青青草原精品 | 午夜视频在线观看免费完整版| 在线v片免费观看视频| 国产成人精品免费午夜app| 久热中文字幕在线精品免费| 美女视频黄的全免费视频网站| 美女视频黄a视频全免费| 永久在线毛片免费观看| 免费日韩在线视频| 亚洲一区二区三区免费| 国产精品亚洲精品日韩已满| 久久亚洲精品国产精品黑人|