Example #1
0
    public void GetGroupedEndpoints_ForwardedToChildDataSources()
    {
        var endpoint            = CreateEndpoint("/a");
        var dataSource          = new TestGroupDataSource(new RouteEndpoint[] { endpoint });
        var compositeDataSource = new CompositeEndpointDataSource(new[] { dataSource });

        var prefix = RoutePatternFactory.Parse("/prefix");
        var applicationServices = new ServiceCollection().BuildServiceProvider();
        var metadata            = new EndpointNameMetadata("name");
        var conventions         = new Action <EndpointBuilder>[]
        {
            b => b.Metadata.Add(metadata),
        };

        var context          = new RouteGroupContext(prefix, conventions, applicationServices);
        var groupedEndpoints = compositeDataSource.GetGroupedEndpoints(context);

        var receivedContext = Assert.Single(dataSource.ReceivedRouteGroupContexts);

        Assert.Same(context, receivedContext);

        var resolvedEndpoint = Assert.IsType <RouteEndpoint>(Assert.Single(groupedEndpoints));

        Assert.Equal("/prefix/a", resolvedEndpoint.RoutePattern.RawText);
        var resolvedMetadata = Assert.Single(resolvedEndpoint.Metadata);

        Assert.Same(metadata, resolvedMetadata);
    }
Example #2
0
 public override IReadOnlyList <Endpoint> GetGroupedEndpoints(RouteGroupContext context)
 {
     return(CreateEndpoints(
                context.Prefix,
                _actions.ActionDescriptors.Items,
                Conventions,
                context.Conventions));
 }
Example #3
0
    /// <summary>
    /// Get the <see cref="Endpoint"/> instances for this <see cref="EndpointDataSource"/> given the specified <see cref="RouteGroupContext.Prefix"/> and <see cref="RouteGroupContext.Conventions"/>.
    /// </summary>
    /// <param name="context">Details about how the returned <see cref="Endpoint"/> instances should be grouped and a reference to application services.</param>
    /// <returns>
    /// Returns a read-only collection of <see cref="Endpoint"/> instances given the specified group <see cref="RouteGroupContext.Prefix"/> and <see cref="RouteGroupContext.Conventions"/>.
    /// </returns>
    public virtual IReadOnlyList <Endpoint> GetGroupedEndpoints(RouteGroupContext context)
    {
        // Only evaluate Endpoints once per call.
        var endpoints        = Endpoints;
        var wrappedEndpoints = new RouteEndpoint[endpoints.Count];

        for (int i = 0; i < endpoints.Count; i++)
        {
            var endpoint = endpoints[i];

            // Endpoint does not provide a RoutePattern but RouteEndpoint does. So it's impossible to apply a prefix for custom Endpoints.
            // Supporting arbitrary Endpoints just to add group metadata would require changing the Endpoint type breaking any real scenario.
            if (endpoint is not RouteEndpoint routeEndpoint)
            {
                throw new NotSupportedException(Resources.FormatMapGroup_CustomEndpointUnsupported(endpoint.GetType()));
            }

            // Make the full route pattern visible to IEndpointConventionBuilder extension methods called on the group.
            // This includes patterns from any parent groups.
            var fullRoutePattern = RoutePatternFactory.Combine(context.Prefix, routeEndpoint.RoutePattern);

            // RequestDelegate can never be null on a RouteEndpoint. The nullability carries over from Endpoint.
            var routeEndpointBuilder = new RouteEndpointBuilder(routeEndpoint.RequestDelegate !, fullRoutePattern, routeEndpoint.Order)
            {
                DisplayName         = routeEndpoint.DisplayName,
                ApplicationServices = context.ApplicationServices,
            };

            // Apply group conventions to each endpoint in the group at a lower precedent than metadata already on the endpoint.
            foreach (var convention in context.Conventions)
            {
                convention(routeEndpointBuilder);
            }

            // Any metadata already on the RouteEndpoint must have been applied directly to the endpoint or to a nested group.
            // This makes the metadata more specific than what's being applied to this group. So add it after this group's conventions.
            foreach (var metadata in routeEndpoint.Metadata)
            {
                routeEndpointBuilder.Metadata.Add(metadata);
            }

            // The RoutePattern, RequestDelegate, Order and DisplayName can all be overridden by non-group-aware conventions.
            // Unlike with metadata, if a convention is applied to a group that changes any of these, I would expect these
            // to be overridden as there's no reasonable way to merge these properties.
            wrappedEndpoints[i] = (RouteEndpoint)routeEndpointBuilder.Build();
        }

        return(wrappedEndpoints);
    }
Example #4
0
 public override IReadOnlyList <Endpoint> GetGroupedEndpoints(RouteGroupContext context) =>
 GetGroupedEndpointsWithNullablePrefix(context.Prefix, context.Conventions, context.ApplicationServices);