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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

.net core 源码解析-mvc route的注册,激活,调用流程(三)

發布時間:2023/12/4 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .net core 源码解析-mvc route的注册,激活,调用流程(三) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

.net core mvc route的注冊,激活,調用流程

mvc的入口是route,當前請求的url匹配到合適的route之后,mvc根據route所指定的controller和action激活controller并調用action完成mvc的處理流程。下面我們看看服務器是如何調用route的。
core mvc startup基本代碼。重點在AddMvc和UseMvc

public class Startup{ ? ?
? ?
? ?public
IConfigurationRoot Configuration { get; } ? ?// This method gets called by the runtime. Use this method to add services to the container.public void ConfigureServices(IServiceCollection services) ? ?{services.AddMvc();} ? ?// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) ? ?{app.UseStaticFiles();app.UseMvc(routes =>{routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");});} }

AddMvc:把各種service加入IOC容器。比如格式化提供程序,action定位器,controllerFactory,controller激活器等等,一應服務全部在這里加入。
UseMvc:最重要的一行代碼:builder.UseMiddleware (router); 看到這行代碼就清楚的知道route 這個handler 在這里加入到請求委托鏈拉

public static IMvcBuilder AddMvc(this IServiceCollection services){ ? ?var builder = services.AddMvcCore();builder.AddJsonFormatters();builder.AddCors(); ? ?return new MvcBuilder(builder.Services, builder.PartManager); }public static IMvcCoreBuilder AddMvcCore(this IServiceCollection services, Action<MvcOptions> setupAction){ ? ?var builder = services.AddMvcCore();services.Configure(setupAction); ? ?return builder; }internal static void AddMvcCoreServices(IServiceCollection services){services.TryAddSingleton<IActionSelector, ActionSelector>();services.TryAddSingleton<ActionConstraintCache>();services.TryAddSingleton<IActionSelectorDecisionTreeProvider, ActionSelectorDecisionTreeProvider>(); ? ?// This has a cache, so it needs to be a singletonservices.TryAddSingleton<IControllerFactory, DefaultControllerFactory>(); ? ?// Will be cached by the DefaultControllerFactoryservices.TryAddTransient<IControllerActivator, DefaultControllerActivator>();services.TryAddEnumerable(ServiceDescriptor.Transient<IControllerPropertyActivator, DefaultControllerPropertyActivator>()); ? ?// Route Handlersservices.TryAddSingleton<MvcRouteHandler>(); // Only one per appservices.TryAddTransient<MvcAttributeRouteHandler>(); // Many per app}public static IApplicationBuilder UseMvc(this IApplicationBuilder app, Action<IRouteBuilder> configureRoutes){ ? ?var routes = new RouteBuilder(app){DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),};configureRoutes(routes);routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices)); ? ?return app.UseRouter(routes.Build()); }public static IApplicationBuilder UseRouter(this IApplicationBuilder builder, IRouter router){ ? ?return builder.UseMiddleware<RouterMiddleware>(router); }

如此,mvc的入口route handler就加入了我們的請求委托鏈中。后續服務器接收到的請求就能交由route匹配,查找action,激活action處理。

router middleware的激活調用

middleware 請求調用委托鏈的激活調用請看這篇文章

//middleware加入_components請求處理委托鏈
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware){_components.Add(middleware); ?
?return this; }
?
?public static class UseMiddlewareExtensions{ ?
?
? ?private const string InvokeMethodName = "Invoke";
? ?? ?private static readonly MethodInfo GetServiceInfo = typeof(UseMiddlewareExtensions).GetMethod(nameof(GetService), BindingFlags.NonPublic | BindingFlags.Static); ? ?//注冊middleware ? ?

public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args)
? ?
{ ? ? ?
? ?? ??var applicationServices = app.ApplicationServices; ? ? ? ?//將middleware 加入請求處理委托鏈return app.Use(next =>{ ? ? ? ?//解析方法和參數。查找類的Invoke方法作為入口方法。所以middleware只要是個class就行。只要有一個功公共的Invoke方法即可。var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public); ? ? ? ? ?
? ?? ?? ?var invokeMethods = methods.Where(m => string.Equals(m.Name, InvokeMethodName, StringComparison.Ordinal)).ToArray(); ? ?
? ?? ?? ?var methodinfo = invokeMethods[0]; ? ?
? ?? ?? ?var parameters = methodinfo.GetParameters(); ?
? ?? ?? ?var ctorArgs = new object[args.Length + 1];ctorArgs[0] = next;Array.Copy(args, 0, ctorArgs, 1, args.Length); ?
? ?? ?? ?//創建middleware的實例。并且通過構造函數注入相關的servicevar instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs); ? ? ? ? ? ?//如果方法只有一個參數,默認它就是httpcontext。if (parameters.Length == 1){ ? ? ? ? ? ? ? ? ?
? ?? ?? ? ?return (RequestDelegate)methodinfo.CreateDelegate(typeof(RequestDelegate), instance);} ? ? ? ? ?
? ?? ?? ? ? ?//多余一個參數的則構建一個func。并從ioc容器解析參數注入var factory = Compile<object>(methodinfo, parameters); ? ? ? ? ? ?return context =>{ ? ? ? ? ? ? ?
? ?? ?? ? ? ??var serviceProvider = context.RequestServices ?? applicationServices; ? ? ? ? ? ? ?
? ?? ?? ? ? ???return factory(instance, context, serviceProvider);};});}//代碼中的創建實例注入service,創建有多個參數的invoke方法注入service具體代碼就不貼上來了,占地方。//構造函數就是匹配最適合的構造函數,然后從IServiceProvider get實例,注入。//多個參數的invoke就更簡單了。直接從IServiceProvider get實例注入。

上述源代碼git地址,aspnet/HttpAbstractions項目

route handler middleware代碼

public class RouterMiddleware{ ?
? ?private readonly ILogger _logger; ?
? ?private readonly RequestDelegate _next;
? ?private readonly IRouter _router; ? ?//創建middleware的實例。并且通過構造函數注入相關的servicepublic RouterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IRouter router) ? ?{_next = next;_router = router;_logger = loggerFactory.CreateLogger<RouterMiddleware>();} ? ?//被調用的方法。從這里開始進入mvc route。public async Task Invoke(HttpContext httpContext) ? ?{ ?
? ?? ? ?//此處的 IRouter router對象。是我們在Startup中routes.MapRoute...配置的route集合對象:RouteCollection。當然也還有比如attributeroute等等好幾種route。var context = new RouteContext(httpContext);context.RouteData.Routers.Add(_router); ? ? ? ?await _router.RouteAsync(context); ? ? ?
? ?? ? ? ?if (context.Handler == null){ ? ? ? ?//沒有匹配到route的情況_logger.RequestDidNotMatchRoutes(); ? ? ?
? ?? ? ? ?? ? ?await _next.Invoke(httpContext);} ? ?
? ?? ? ?else{httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature(){RouteData = context.RouteData,}; ? ? ? ? ? ?//匹配到路由處理await context.Handler(context.HttpContext);}} }
//Microsoft.AspNetCore.Routing.RouteCollection
public async virtual Task RouteAsync(RouteContext context){ ?
?// Perf: We want to avoid allocating a new RouteData for each route we need to process.// We can do this by snapshotting the state at the beginning and then restoring it// for each router we execute.var snapshot = context.RouteData.PushState(null, values: null, dataTokens: null); ?
??for (var i = 0; i < Count; i++){ ? ? ?
?? ? ?var route = this[i];context.RouteData.Routers.Add(route); ? ?
?? ? ??try{ ? ? ? ? ?//循環所有routes規則,逐一匹配,匹配到一個自然就break。await route.RouteAsync(context); ? ? ? ?
?? ? ?? ? ?if (context.Handler != null) ? ? ? ? ? ?
?? ? ?? ? ? ? ?break;} ? ? ?
?? ? ???finally{ ? ? ? ? ? ?if (context.Handler == null)snapshot.Restore();}} }

UseMvc中有一行非常重要的代碼。給RouteBuilder的DefaultHandler賦值一個handler。記住這行代碼,我們繼續往下看。

public static IApplicationBuilder UseMvc(this IApplicationBuilder app, Action<IRouteBuilder> configureRoutes){ ?
?var routes = new RouteBuilder(app){DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),}; }
?//我們在Startup中routes.MapRoute的所有調用最終調用方法都是這個。new Route( routeBuilder.DefaultHandler,....)//全部都指定了_target為routeBuilder.DefaultHandler

public static IRouteBuilder MapRoute(this IRouteBuilder routeBuilder, string name, string template, object defaults, object constraints, object dataTokens){ ?
??if (routeBuilder.DefaultHandler == null) ?
?? ? ? ?throw new RouteCreationException(Resources.FormatDefaultHandler_MustBeSet(nameof(IRouteBuilder))); ?
?? ? ? ??var inlineConstraintResolver = routeBuilder.ServiceProvider.GetRequiredService<IInlineConstraintResolver>();routeBuilder.Routes.Add(new Route(routeBuilder.DefaultHandler,name, template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new RouteValueDictionary(dataTokens), inlineConstraintResolver)); ?
?? ? ? ???return routeBuilder; }

到這里,我們的邏輯有點繞了,讓我們理理清楚:
1.請求進到RouterMiddleware.Invoke()方法
2.調用RouteCollection.RouteAsync()方法,RouteCollection.RouteAsync方法中循環注冊的每一個route對象。
并調用route對象的RouteAsync()方法(route對象的RouteAsync方法在它的父類中Microsoft.AspNetCore.Routing.RouteBase)。
這里說的route對象即時Startup中routes.MapRoute生成的route對象(Microsoft.AspNetCore.Routing.Route)。Route繼承RouteBase,RouteBase實現IRouter接口
3.RouteBase.RouteAsync()判斷當前請求是否符合當前route規則,如果匹配的話,則調用抽象方法OnRouteMatched
4.RouteBase的抽象方法OnRouteMatched,又回到Route對象的OnRouteMatched方法中。調用_target.RouteAsync();_target對象即上面代碼中的routeBuilder.DefaultHandler。
5.來到Microsoft.AspNetCore.Mvc.Internal.MvcRouteHandler.RouteAsync()方法中。最重要的一行代碼: context.Handler =....
6.調用堆棧最終返回到1中(RouterMiddleware.Invoke())。判斷context.Handler == null。為null沒找到route匹配的action。不為null則await context.Handler(context.HttpContext)
7.context.Handler即為5中賦值的func。即下面的代碼,定位action,調用action。

//Microsoft.AspNetCore.Mvc.Internal.MvcRouteHandler.RouteAsync
public Task RouteAsync(RouteContext context){ ?
?var candidates = _actionSelector.SelectCandidates(context); ?
??if (candidates == null || candidates.Count == 0){_logger.NoActionsMatched(); ? ? ?
?? ?return TaskCache.CompletedTask;} ? ?
?? ?var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates); ?
?? ?if (actionDescriptor == null){_logger.NoActionsMatched(); ? ?
?? ?? ?return TaskCache.CompletedTask;}context.Handler = (c) =>{ ? ?
?? ?? ? ? ?var routeData = c.GetRouteData(); ? ?
?? ?? ? ? ?var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor); ? ? ?
?? ?? ? ? ? ?if (_actionContextAccessor != null)_actionContextAccessor.ActionContext = actionContext; ? ? ? ?var invoker = _actionInvokerFactory.CreateInvoker(actionContext); ? ? ? ?if (invoker == null) ? ? ? ? ?
?? ?? ? ? ? ?throw new InvalidOperationException( Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(actionDescriptor.DisplayName)); ? ? ?
?? ?? ? ? ?return invoker.InvokeAsync();}; ? ?
?? ?? ?
?? ?? ? ? ?return TaskCache.CompletedTask; }

至此,route的處理流程大約交代清楚了。包括route的注冊,route的激活,route的選擇等。

相關文章:?

  • .net core 源碼解析-web app是如何啟動并接收處理請求

  • .net core 源碼解析-web app是如何啟動并接收處理請求(二) kestrel的啟動

原文地址:http://www.cnblogs.com/calvinK/p/6226219.html


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的.net core 源码解析-mvc route的注册,激活,调用流程(三)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。