コード例 #1
0
    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);
        }
    }
コード例 #2
0
        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);
        }