Skip to content

RouteEndpoint metadata from convention builders are duplicated #34199

@martincostello

Description

@martincostello

Describe the bug

When inspecting endpoints with EndpointDataSource, for example in an IApiDescriptionProvider, some of the metadata on RouteEndpoint instances is duplicated. As shown in the screenshot below, there are two duplicated HTTP method metadata items.

image

Tracing through the code, this appears to be caused by a number of factors that together contribute to the routing endpoint conventions for an endpoint builder being run multiple times. The screenshot below shows the HTTP method metadata being added to the endpoint builder a second time.

image

The contributing factors to this issue appear to be:

  1. There are two CompositeEndpointDataSource instances created by the application:
    _endpointDataSource = new CompositeEndpointDataSource(endpointRouteBuilder.DataSources);
    return new CompositeEndpointDataSource(dataSources);
  2. Each CompositeEndpointDataSource enumerates the Endpoints property of each underlying endpoint data source once:
    _endpoints = _dataSources.SelectMany(d => d.Endpoints).ToArray();
  3. ModelEndpointDataSource calls Build() on each convention builder each time the Endpoints property is accessed
    public override IReadOnlyList<Endpoint> Endpoints => _endpointConventionBuilders.Select(e => e.Build()).ToArray();
  4. Each call to Build() runs the convention action(s):
    foreach (var convention in _conventions)
    {
    convention(EndpointBuilder);
    }
  5. The conventions may mutate the endpoint builder's state multiple times:
    builder.Add(b =>
    {
    foreach (var item in items)
    {
    b.Metadata.Add(item);
    }
    });

The net result is that every time the Endpoints property of an ModelEndpointDataSource is accessed, the number of Metadata items on a route endpoint increases by the number of conventions configured.

Below is an example of four duplicate metadata items in a sample application:

image

To Reproduce

To reproduce this issue, edit this test to have the following code:

app.MapGet("/json", (IApiDescriptionGroupCollectionProvider provider) =>
{
    if (provider.ApiDescriptionGroups is not null)
    {
        // Used to inspect and debug ApiDescriptionGroups
    }

    return Json(new Person("John", 42));
});

Then debug the JsonResult_Works() test with a breakpoint set here:

foreach (var httpMethod in httpMethodMetadata.HttpMethods)

Inspecting routeEndpoint.Metadata with the debugger will show the duplicated metadata as shown in the preceding screenshots.

Further technical details

  • ASP.NET Core version 6.0.0-preview.7.21357.1
  • .NET Core SDK 6.0.100-preview.7.21357.57
  • Visual Studio 2022 17.0.0 Preview 1.1

Metadata

Metadata

Assignees

Labels

Priority:3Work that is nice to havearea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesbugThis issue describes a behavior which is not expected - a bug.feature-minimal-actionsController-like actions for endpoint routingfeature-routinginvestigate

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions