日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Owin Katana 的底层源码分析

發(fā)布時間:2023/12/18 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Owin Katana 的底层源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

最近看了一下開源項目asp.net katana,感覺公開的接口非常的簡潔優(yōu)雅,channel 9 說是受到node.js的啟示設(shè)計的,Katana是一個比較老的項目,現(xiàn)在已經(jīng)整合到asp.net core中。 從github克隆下來的項目,這個博客專門是從代碼視點去了解katana項目,所以本篇隨筆針對已經(jīng)對OWIN有所了解的人,假如僅僅入門的話能夠跑一下MSDN的源碼再來閱覽本篇文章。 代碼結(jié)構(gòu)如上,簡略剖析一下各個文件夾的含義,這對于了解katana項目的全體結(jié)構(gòu)有一個大的輪廓。   .build文件夾顧名思義便是編譯的文件夾,在沒使用vs的時分你能夠單擊build.cmd 去編譯這個項目,非常的便利。   .Nuget便是包辦理東西的配置文件,這個咱們能夠忽略。同理.Prerelease。   Development是本次的研究要點,當你打開這個文件夾的時分你會發(fā)現(xiàn)一個類庫Microsoft.Owin的類庫,這個是OWIN組件的經(jīng)典完成。   FunctionTests是單元測試的類庫   Hosting 是server的抽象層,OWIN 將服務(wù)器進行抽象化,Hosting 便是能夠辦理Server的一層,像WebApp就能敞開一個httplister服務(wù),詳細稍后再講。   Middleware是一些中間件的完成,在katana已經(jīng)將管道模型虛擬化成中間件   Performance 和Sandbox 是微軟的一些測試東西   Security 是微軟已經(jīng)寫好的驗證中間件,其中包括JWT和Oauth的驗證方式   Server 便是服務(wù)器的完成   Owin.Analysis是我自己建的web程序用來debug 上面已經(jīng)介紹了各個文件夾所對應(yīng)的功用,相必大部分人都是一臉遮蓋,但是不必擔心,下面就來看看詳細的代碼,當然是從最小的比如動身。點擊 getting started with owin and katan 你就能 跳到MSDN得到最小的比如。里邊的一系列操作就為了增加下面的一個類和幾個reference.現(xiàn)在咱們看一下這個類。 仿制代碼 1 using Microsoft.Owin; 2 3 [assembly: OwinStartup(typeof(Owin.Analysis.Startup))] 4 namespace Owin.Analysis 5 { 6 public class Startup 7 { 8 public void Configuration(IAppBuilder app) 9 { 10 app.Run(context => 11 { 12 context.Response.ContentType = "text/plain"; 13 return context.Response.WriteAsync("Hello World"); 14 }); 15 } 16 } 17 } 仿制代碼 看起來這個代碼非常的優(yōu)雅,增加幾個reference和一個類就讓懇求抵達Hello World。咱們先剖析這個類,首先程序集特性O(shè)winStartupAtribute將當前類保存在元數(shù)據(jù)中。然后寫了一個 Configuration辦法,獲取一個IAppBuilder 參數(shù)調(diào)用Run辦法,Run辦法傳遞一個托付進去,咱們的處理邏輯就在這一個托付里。 這兒邊咱們剖析一下核心接口IAppBuilder的經(jīng)典完成者AppBuilder,IAppBuilder的接口如下, 仿制代碼 using System; using System.Collections.Generic; namespace Owin { public interface IAppBuilder { IDictionary?Properties { get; }//懇求的參數(shù) object Build(Type returnType);//中間件鏈接 IAppBuilder New();//創(chuàng)立一個新的目標 IAppBuilder Use(object middleware, params object[] args);//注冊中間件 } } 仿制代碼 好的咱們來剖析一下AppBuilder中間件的注冊完成。在app.Run 打完break point你就能夠進入app.use辦法,首先在AppBuilderUseExtensions這個類里對use的入口寫了一大堆擴展辦法。app.Run就 是其中的一個,當你用app.Run注冊中間件的時分是沒有下一個中間件的引用的。 仿制代碼 public static void Run(this IAppBuilder app, Func?handler) { if (app == null) { throw new ArgumentNullException("app"); } if (handler == null) { throw new ArgumentNullException("handler"); } app.Use(handler); } 仿制代碼 在經(jīng)典的完成中,參數(shù)middleware會有兩種狀況,一種是delegate,一種是type,假如是type類型,則他的結(jié)構(gòu)辦法接受next為參數(shù),并且里邊有一個公開的Invoke辦法。假如是托付,當前托付作為 參數(shù)傳遞到next中。 public IAppBuilder Use(object middleware, params object[] args) { _middleware.Add(ToMiddlewareFactory(middleware, args)); return this; } 下面的代碼是ToMiddlewareFactory的完成,在第9行和第27行別離判別了中間件目標是托付類型還是type類型,因為本題比如是type目標,咱們剖析一下ToConstructorMiddlewareFactory辦法。 仿制代碼 1 private static Tuple?ToMiddlewareFactory(object middlewareObject, object[] args) 2 { 3 if (middlewareObject == null) 4 { 5 throw new ArgumentNullException("middlewareObject"); 6 } 7 8 var middlewareDelegate = middlewareObject as Delegate; 9 if (middlewareDelegate != null) 10 { 11 return Tuple.Create(GetParameterType(middlewareDelegate), middlewareDelegate, args); 12 } 13 14 Tuple?factory = ToInstanceMiddlewareFactory(middlewareObject, args); 15 if (factory != null) 16 { 17 return factory; 18 } 19 20 factory = ToGeneratorMiddlewareFactory(middlewareObject, args); 21 if (factory != null) 22 { 23 return factory; 24 } 25 26 if (middlewareObject is Type) 27 { 28 return ToConstructorMiddlewareFactory(middlewareObject, args, ref middlewareDelegate); 29 } 30 31 throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, 32 Resources.Exception_MiddlewareNotSupported, middlewareObject.GetType().FullName)); 33 } 仿制代碼 在第5行獲取type類型的一切結(jié)構(gòu)辦法,第8行獲取結(jié)構(gòu)辦法的一切參數(shù),在第14行有個trick,用zip辦法判別參數(shù)類型是否和結(jié)構(gòu)辦法類型是共同的。假如是共同的則持續(xù)往下走,在第22行和第23行 使用托付將結(jié)構(gòu)辦法創(chuàng)立成lambda表達式,然后生成元祖,第一個是next的類型,第二個是type的結(jié)構(gòu)辦法,第三個是type結(jié)構(gòu)辦法所需的參數(shù)。然后將元祖加入到AppBuild所保護的中間件目標。 仿制代碼 1 2 private static Tuple?ToConstructorMiddlewareFactory(object middlewareObject, object[] args, ref Delegate middlewareDelegate) 3 { 4 var middlewareType = middlewareObject as Type; 5 ConstructorInfo[] constructors = middlewareType.GetConstructors(); 6 foreach (var constructor in constructors) 7 { 8 ParameterInfo[] parameters = constructor.GetParameters(); 9 Type[] parameterTypes = parameters.Select(p => p.ParameterType).ToArray(); 10 if (parameterTypes.Length != args.Length + 1) 11 { 12 continue; 13 } 14 if (!parameterTypes 15 .Skip(1) 16 .Zip(args, TestArgForParameter) 17 .All(x => x)) 18 { 19 continue; 20 } 21 22 ParameterExpression[] parameterExpressions = parameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); 23 NewExpression callConstructor = Expression.New(constructor, parameterExpressions); 24 middlewareDelegate = Expression.Lambda(callConstructor, parameterExpressions).Compile(); 25 return Tuple.Create(parameters[0].ParameterType, middlewareDelegate, args); 26 } 27 28 throw new MissingMethodException(string.Format(CultureInfo.CurrentCulture, 29 Resources.Exception_NoConstructorFound, middlewareType.FullName, args.Length + 1)); 30 } 仿制代碼 這個時分咱們已經(jīng)將中間件注冊到AppBuilder目標了。注冊完中間件的目標咱們還需求做一件事便是將這些中間件chained together,這些完成便是Build 辦法中,而Build辦法BuildInternal辦法, 這個時分會產(chǎn)生一個entry point供調(diào)用。 現(xiàn)在咱們要點看一下這個build辦法。 public object Build(Type returnType) { return BuildInternal(returnType); } Build辦法調(diào)用私有的BuildInternal的辦法。 仿制代碼 private object BuildInternal(Type signature) { object app; if (!_properties.TryGetValue(Constants.BuilderDefaultApp, out app)) { app = NotFound; } foreach (var middleware in _middleware.Reverse()) { Type neededSignature = middleware.Item1; Delegate middlewareDelegate = middleware.Item2; object[] middlewareArgs = middleware.Item3; app = Convert(neededSignature, app); object[] invokeParameters = new[] { app }.Concat(middlewareArgs).ToArray(); app = middlewareDelegate.DynamicInvoke(invokeParameters); app = Convert(neededSignature, app); } return Convert(signature, app); } 仿制代碼 咱們能夠看到它是怎樣將中間件chained together的,在咱們之前注冊的時分實際上middleware元祖會保存三個信息,第一個type便是結(jié)構(gòu)函數(shù)的第一個類型,第二個托付是useHandlerMiddleware的 結(jié)構(gòu)辦法,第三個是結(jié)構(gòu)辦法的參數(shù)(除了第一個),Reverse的辦法會將中間件逆序,這樣保證調(diào)用的順序便是你注冊的順序,后面的是chain的邏輯,app的變量實際上便是下一個中間件結(jié)構(gòu)函數(shù) 的next,當?shù)玫降谝粋€中間件的時分,里邊的next會保存第二個中間件的處理邏輯,同樣第二個next便是第三個...,這樣chained together得到的便是第一個中間件的邏輯,所以你們在用app.Use的 辦法就會有一個參數(shù)next,并且需求手動調(diào)用一下。 得到這些之后需求的便是要將中間件注冊到application管道事情呢。因為asp.net的是一個大的切面結(jié)構(gòu)。 仿制代碼 public void Initialize(HttpApplication application) { for (IntegratedPipelineBlueprintStage stage = _blueprint.FirstStage; stage != null; stage = stage.NextStage) { var segment = new IntegratedPipelineContextStage(this, stage); switch (stage.Name) { case Constants.StageAuthenticate: application.AddOnAuthenticateRequestAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StagePostAuthenticate: application.AddOnPostAuthenticateRequestAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StageAuthorize: application.AddOnAuthorizeRequestAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StagePostAuthorize: application.AddOnPostAuthorizeRequestAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StageResolveCache: application.AddOnResolveRequestCacheAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StagePostResolveCache: application.AddOnPostResolveRequestCacheAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StageMapHandler: application.AddOnMapRequestHandlerAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StagePostMapHandler: application.AddOnPostMapRequestHandlerAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StageAcquireState: application.AddOnAcquireRequestStateAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StagePostAcquireState: application.AddOnPostAcquireRequestStateAsync(segment.BeginEvent, segment.EndEvent); break; case Constants.StagePreHandlerExecute: application.AddOnPreRequestHandlerExecuteAsync(segment.BeginEvent, segment.EndEvent); break; default: throw new NotSupportedException( string.Format(CultureInfo.InvariantCulture, Resources.Exception_UnsupportedPipelineStage, stage.Name)); } } // application.PreSendRequestHeaders += PreSendRequestHeaders; // Null refs for async un-buffered requests with bodies. application.AddOnEndRequestAsync(BeginFinalWork, EndFinalWork); } 仿制代碼 這兒邊有一個概念便是IntegratedPipelineBlueprintStage,這個是一個鏈表結(jié)構(gòu),每個對應(yīng)的便是管道事情,每個stage都有entry point,這樣便利咱們在不同的管道事情中運行中間件,在 BeginEvent里咱們得到stage 的entry point,然后異步調(diào)用得到成果。entry point 便是咱們上例build得到的成果。 仿制代碼 private async Task RunApp(AppFunc entryPoint, IDictionary?environment, TaskCompletionSourcetcs, StageAsyncResult result) { try { await entryPoint(environment); tcs.TrySetResult(null); result.TryComplete(); } catch (Exception ex) { // Flow the exception back through the OWIN pipeline. tcs.TrySetException(ex); result.TryComplete(); } } 仿制代碼 然后咱們剖析一下怎樣在不同的管道中注冊事情。在MSDN的文檔描述的。 app.UseStageMarker(PipelineStage.Authenticate) 這個api會創(chuàng)立一個IntegratedPipelineBlueprintStage,上文說這是一個鏈表結(jié)構(gòu),之間用next屬性連接。在不同的stage中會有entry point,然后在上面的比如中注冊到不同的管道中去調(diào)用。下 圖是api的代碼。 仿制代碼 public static IAppBuilder UseStageMarker(this IAppBuilder app, string stageName) { if (app == null) { throw new ArgumentNullException("app"); } object obj; if (app.Properties.TryGetValue(IntegratedPipelineStageMarker, out obj)) { var addMarker = (Action)obj; addMarker(app, stageName); } return app; } 仿制代碼 好的,到這兒了,謝謝我們閱覽,假如有任何不了解的歡迎溝通:)

本文來自:https://www.jmwww.net/a/13201.html?轉(zhuǎn)載請注明

總結(jié)

以上是生活随笔為你收集整理的Owin Katana 的底层源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。