我是靠谱客的博主 谦让海燕,最近开发中收集的这篇文章主要介绍Owin Katana 的底层源码分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

最近看了一下开源项目asp.net katana,感觉公开的接口非常的简洁优雅,channel 9 说是受到node.js的启示设计的,Katana是一个比较老的项目,现在已经整合到asp.net core中。 从github克隆下来的项目,这个博客专门是从代码视点去了解katana项目,所以本篇随笔针对已经对OWIN有所了解的人,假如仅仅入门的话能够跑一下MSDN的源码再来阅览本篇文章。 代码结构如上,简略剖析一下各个文件夹的含义,这对于了解katana项目的全体结构有一个大的轮廓。   .build文件夹顾名思义便是编译的文件夹,在没使用vs的时分你能够单击build.cmd 去编译这个项目,非常的便利。   .Nuget便是包办理东西的配置文件,这个咱们能够忽略。同理.Prerelease。   Development是本次的研究要点,当你打开这个文件夹的时分你会发现一个类库Microsoft.Owin的类库,这个是OWIN组件的经典完成。   FunctionTests是单元测试的类库   Hosting 是server的抽象层,OWIN 将服务器进行抽象化,Hosting 便是能够办理Server的一层,像WebApp就能敞开一个httplister服务,详细稍后再讲。   Middleware是一些中间件的完成,在katana已经将管道模型虚拟化成中间件   Performance 和Sandbox 是微软的一些测试东西   Security 是微软已经写好的验证中间件,其中包括JWT和Oauth的验证方式   Server 便是服务器的完成   Owin.Analysis是我自己建的web程序用来debug 上面已经介绍了各个文件夹所对应的功用,相必大部分人都是一脸遮盖,但是不必担心,下面就来看看详细的代码,当然是从最小的比如动身。点击 getting started with owin and katan 你就能 跳到MSDN得到最小的比如。里边的一系列操作就为了增加下面的一个类和几个reference.现在咱们看一下这个类。 仿制代码 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 } 仿制代码 看起来这个代码非常的优雅,增加几个reference和一个类就让恳求抵达Hello World。咱们先剖析这个类,首先程序集特性OwinStartupAtribute将当前类保存在元数据中。然后写了一个 Configuration办法,获取一个IAppBuilder 参数调用Run办法,Run办法传递一个托付进去,咱们的处理逻辑就在这一个托付里。 这儿边咱们剖析一下核心接口IAppBuilder的经典完成者AppBuilder,IAppBuilder的接口如下, 仿制代码 using System; using System.Collections.Generic; namespace Owin { public interface IAppBuilder { IDictionary Properties { get; }//恳求的参数 object Build(Type returnType);//中间件链接 IAppBuilder New();//创立一个新的目标 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); } 仿制代码 在经典的完成中,参数middleware会有两种状况,一种是delegate,一种是type,假如是type类型,则他的结构办法接受next为参数,并且里边有一个公开的Invoke办法。假如是托付,当前托付作为 参数传递到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类型的一切结构办法,第8行获取结构办法的一切参数,在第14行有个trick,用zip办法判别参数类型是否和结构办法类型是共同的。假如是共同的则持续往下走,在第22行和第23行 使用托付将结构办法创立成lambda表达式,然后生成元祖,第一个是next的类型,第二个是type的结构办法,第三个是type结构办法所需的参数。然后将元祖加入到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 } 仿制代码 这个时分咱们已经将中间件注册到AppBuilder目标了。注册完中间件的目标咱们还需求做一件事便是将这些中间件chained together,这些完成便是Build 办法中,而Build办法BuildInternal办法, 这个时分会产生一个entry point供调用。 现在咱们要点看一下这个build办法。 public object Build(Type returnType) { return BuildInternal(returnType); } Build办法调用私有的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便是结构函数的第一个类型,第二个托付是useHandlerMiddleware的 结构办法,第三个是结构办法的参数(除了第一个),Reverse的办法会将中间件逆序,这样保证调用的顺序便是你注册的顺序,后面的是chain的逻辑,app的变量实际上便是下一个中间件结构函数 的next,当得到第一个中间件的时分,里边的next会保存第二个中间件的处理逻辑,同样第二个next便是第三个...,这样chained together得到的便是第一个中间件的逻辑,所以你们在用app.Use的 办法就会有一个参数next,并且需求手动调用一下。 得到这些之后需求的便是要将中间件注册到application管道事情呢。因为asp.net的是一个大的切面结构。 仿制代码 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,这个是一个链表结构,每个对应的便是管道事情,每个stage都有entry point,这样便利咱们在不同的管道事情中运行中间件,在 BeginEvent里咱们得到stage 的entry point,然后异步调用得到成果。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会创立一个IntegratedPipelineBlueprintStage,上文说这是一个链表结构,之间用next属性连接。在不同的stage中会有entry point,然后在上面的比如中注册到不同的管道中去调用。下 图是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 转载请注明

最后

以上就是谦让海燕为你收集整理的Owin Katana 的底层源码分析的全部内容,希望文章能够帮你解决Owin Katana 的底层源码分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(82)

评论列表共有 0 条评论

立即
投稿
返回
顶部