public async Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (candidates == null) { throw new ArgumentNullException(nameof(candidates)); } DynamicPageEndpointSelector?selector = null; // There's no real benefit here from trying to avoid the async state machine. // We only execute on nodes that contain a dynamic policy, and thus always have // to await something. for (var i = 0; i < candidates.Count; i++) { if (!candidates.IsValidCandidate(i)) { continue; } var endpoint = candidates[i].Endpoint; var originalValues = candidates[i].Values; RouteValueDictionary?dynamicValues = null; // We don't expect both of these to be provided, and they are internal so there's // no realistic way this could happen. var dynamicPageMetadata = endpoint.Metadata.GetMetadata <DynamicPageMetadata>(); var transformerMetadata = endpoint.Metadata.GetMetadata <DynamicPageRouteValueTransformerMetadata>(); DynamicRouteValueTransformer?transformer = null; if (dynamicPageMetadata != null) { dynamicValues = dynamicPageMetadata.Values; } else if (transformerMetadata != null) { transformer = (DynamicRouteValueTransformer)httpContext.RequestServices.GetRequiredService(transformerMetadata.SelectorType); if (transformer.State != null) { throw new InvalidOperationException(Resources.FormatStateShouldBeNullForRouteValueTransformers(transformerMetadata.SelectorType.Name)); } transformer.State = transformerMetadata.State; dynamicValues = await transformer.TransformAsync(httpContext, originalValues !); } else { // Not a dynamic page continue; } if (dynamicValues == null) { candidates.ReplaceEndpoint(i, null, null); continue; } selector = ResolveSelector(selector, endpoint); var endpoints = selector.SelectEndpoints(dynamicValues); if (endpoints.Count == 0 && dynamicPageMetadata != null) { // Having no match for a fallback is a configuration error. We can't really check // during startup that the action you configured exists, so this is the best we can do. throw new InvalidOperationException( "Cannot find the fallback endpoint specified by route values: " + "{ " + string.Join(", ", dynamicValues.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }."); } else if (endpoints.Count == 0) { candidates.ReplaceEndpoint(i, null, null); continue; } // We need to provide the route values associated with this endpoint, so that features // like URL generation work. var values = new RouteValueDictionary(dynamicValues); // Include values that were matched by the fallback route. if (originalValues != null) { foreach (var kvp in originalValues) { values.TryAdd(kvp.Key, kvp.Value); } } if (transformer != null) { endpoints = await transformer.FilterAsync(httpContext, values, endpoints); if (endpoints.Count == 0) { candidates.ReplaceEndpoint(i, null, null); continue; } } // Update the route values candidates.ReplaceEndpoint(i, endpoint, values); var loadedEndpoints = new List <Endpoint>(endpoints); for (var j = 0; j < loadedEndpoints.Count; j++) { var metadata = loadedEndpoints[j].Metadata; var actionDescriptor = metadata.GetMetadata <PageActionDescriptor>(); if (actionDescriptor is CompiledPageActionDescriptor) { // Nothing to do here. The endpoint already represents a compiled page. } else { // We're working with a runtime-compiled page and have to Load it. var compiled = actionDescriptor !.CompiledPageDescriptor ?? await _loader.LoadAsync(actionDescriptor, endpoint.Metadata); loadedEndpoints[j] = compiled.Endpoint !; } } // Expand the list of endpoints candidates.ExpandEndpoint(i, loadedEndpoints, _comparer); } }
private async Task <IEnumerable <AreaInfo> > GetAreaInfosAsync(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider, PageLoader pageLoader, LinkGenerator linkGenerator) { //根,从area开始 var result = new List <AreaInfo>(); //遍历区域 foreach (var area in actionDescriptorCollectionProvider.ActionDescriptors.Items.GroupBy(item => item.RouteValues["area"])) { var areaInfo = new AreaInfo { Name = area.Key }; result.Add(areaInfo); //遍历控制器 foreach (var controllerActions in area.OfType <ControllerActionDescriptor>().GroupBy(c => c.ControllerTypeInfo)) { //跳过重复控制器,不知道为什么,里面有些重复项目 if (areaInfo.Controllers.Any(c => c.TypeFullName == controllerActions.Key.FullName)) { continue; } var conInfo = new AreaInfo.ControllerInfo { Name = controllerActions.First().ControllerName, TypeFullName = controllerActions.Key.FullName, Description = (controllerActions.Key.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute) ?.Description, Area = controllerActions.First().RouteValues["area"], }; areaInfo.Controllers.Add(conInfo); //遍历动作 foreach (var action in controllerActions) { var act = new AreaInfo.ControllerInfo.ActionInfo { Name = action.MethodInfo.Name, ActionName = action.ActionName, HandlerIdentification = (action.MethodInfo.GetCustomAttribute(typeof(RequestHandlerIdentificationAttribute)) as RequestHandlerIdentificationAttribute) ?.UniqueKey, Signature = action.MethodInfo.ToString(), Description = (action.MethodInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute) ?.Description, Url = linkGenerator.GetPathByAction(action.ActionName, conInfo.Name, new { area = conInfo.Area }), HttpMethodLimits = action.ActionConstraints?.OfType <HttpMethodActionConstraint>().FirstOrDefault()?.HttpMethods.ToList(), MethodInfo = action.MethodInfo, ActionDescriptor = action }; conInfo.Actions.Add(act); } } //遍历Razor Page foreach (var pageActionDescriptor in area.OfType <PageActionDescriptor>()) { //载入Razor Page,会从程序集加载或编译page文件并缓存 var page = await pageLoader.LoadAsync(pageActionDescriptor); //也是剔除重复 if (areaInfo.Pages.Any(p => p.TypeFullName == page.HandlerTypeInfo.FullName)) { continue; } var pageInfo = new AreaInfo.PageInfo { Name = page.DisplayName, Area = page.AreaName, TypeFullName = page.HandlerTypeInfo.FullName, Description = (page.HandlerTypeInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute) ?.Description }; foreach (var handlerMethod in page.HandlerMethods) { pageInfo.PageHandlers.Add(new AreaInfo.PageInfo.PageHandlerInfo { HttpMethod = handlerMethod.HttpMethod, Name = handlerMethod.Name, HandlerIdentification = (handlerMethod.MethodInfo.GetCustomAttribute(typeof(RequestHandlerIdentificationAttribute)) as RequestHandlerIdentificationAttribute) ?.UniqueKey, Signature = handlerMethod.MethodInfo.ToString(), Description = (handlerMethod.MethodInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute) ?.Description, Url = linkGenerator.GetPathByPage(page.DisplayName, handlerMethod.Name, new { area = page.AreaName }), MethodInfo = handlerMethod.MethodInfo, ActionDescriptor = page }); } areaInfo.Pages.Add(pageInfo); } } return(result); }