Ejemplo n.º 1
0
        public async Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (candidates == null)
            {
                throw new ArgumentNullException(nameof(candidates));
            }

            // 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 metadata = endpoint.Metadata.GetMetadata <DynamicPageMetadata>();
                if (metadata == null)
                {
                    continue;
                }

                var matchedValues = candidates[i].Values;
                var endpoints     = _selector.SelectEndpoints(metadata.Values);
                if (endpoints.Count == 0)
                {
                    // If there's no match this is a configuration error. We can't really check
                    // during startup that the action you configured exists.
                    throw new InvalidOperationException(
                              "Cannot find the fallback endpoint specified by route values: " +
                              "{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }.");
                }

                // It is possible to have more than one result for pages but they are equivalent.

                var compiled = await _loader.LoadAsync(endpoints[0].Metadata.GetMetadata <PageActionDescriptor>());

                var replacement = compiled.Endpoint;

                // We need to provide the route values associated with this endpoint, so that features
                // like URL generation work.
                var values = new RouteValueDictionary(metadata.Values);

                // Include values that were matched by the fallback route.
                foreach (var kvp in matchedValues)
                {
                    values.TryAdd(kvp.Key, kvp.Value);
                }

                candidates.ReplaceEndpoint(i, replacement, values);
            }
        }
Ejemplo n.º 2
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));
            }

            // 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>();
                if (dynamicPageMetadata != null)
                {
                    dynamicValues = dynamicPageMetadata.Values;
                }
                else if (transformerMetadata != null)
                {
                    var transformer = (DynamicRouteValueTransformer)httpContext.RequestServices.GetRequiredService(transformerMetadata.SelectorType);
                    dynamicValues = await transformer.TransformAsync(httpContext, originalValues);
                }
                else
                {
                    // Not a dynamic page
                    continue;
                }

                if (dynamicValues == null)
                {
                    candidates.ReplaceEndpoint(i, null, null);
                    continue;
                }

                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);
                    }
                }

                // Update the route values
                candidates.ReplaceEndpoint(i, endpoint, values);

                var loadedEndpoints = new List <Endpoint>(endpoints);
                for (var j = 0; j < loadedEndpoints.Count; j++)
                {
                    var compiled = await _loader.LoadAsync(loadedEndpoints[j].Metadata.GetMetadata <PageActionDescriptor>());

                    loadedEndpoints[j] = compiled.Endpoint;
                }

                // Expand the list of endpoints
                candidates.ExpandEndpoint(i, loadedEndpoints, _comparer);
            }
        }