Skip to content

Allow setting EndpointNameMetadata for minimal APIs via a first-class extension method #34538

Closed
@DamianEdwards

Description

@DamianEdwards

Endpoint names are used to lookup endpoints when generating links using LinkGenerator, and as their unique per application are a good candidate for using as the operationId for an endpoint in OpenAPI (Swagger) documents.

(domaindrivendev/Swashbuckle.AspNetCore#2165 is tracking setting the operationId from endpoint name by default in Swashbuckle.)

Endpoint names are set using the Microsoft.AspNetCore.Routing.IEndpointNameMetadata interface. In the framework today this can be set imperatively by adding an instance of Microsoft.AspNetCore.Routing.EndpointNameMetadata to the endpoint's metadata, e.g. builder.WithMetadata(new EndpointNameMetadata("GetTodoById")).

We should add a new extenstion method to allow setting the endpoint name in a more first-class fashion:

using System;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;

namespace Microsoft.AspNetCore.Builder;

public static class RoutingEndpointConventionBuilderExtensions
{
+     /// <summary>
+     /// Adds an <see cref="EndpointNameMetadata"/> item to the <see cref="IEndpointConventionBuilder"/> for all endpoints produced by the builder.
+     /// </summary>
+     /// <remarks>
+     /// Endpoint names must be unique within an application, and can be used to unambiguously
+     /// identify a desired endpoint for URI generation using Microsoft.AspNetCore.Routing.LinkGenerator.
+     /// </remarks>
+     /// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
+     /// <param name="name">The endpoint name.</param>
+     /// <returns>The <see cref="IEndpointConventionBuilder"/>.</returns>
+     public static TBuilder WithName<TBuilder>(this TBuilder  builder, string name) where TBuilder : IEndpointConventionBuilder
+     {
+         builder.WithMetadata(new EndpointNameMetadata(name));
+ 
+         return builder;
+     }
}

The extension method could be used in the following way:

app.MapGet("/todos/{id}", async (int id, TodoDb db) =>
    {
        return await db.Todos.FindAsync(id)
            is Todo todo
                ? Results.Ok(todo)
                : Results.NotFound();
    })
+   .WithName("GetTodoById");

app.MapPost("/todos", async (Todo todo, TodoDb db) =>
    {
        db.Todos.Add(todo);
        await db.SaveChangesAsync();

        return Results.CreatedAtRoute("GetTodoById", new { todo.Id }, todo);
    })
+   .WithName("AddTodo");

Metadata

Metadata

Assignees

Labels

Priority:1Work that is critical for the release, but we could probably ship withoutarea-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcenhancementThis issue represents an ask for new feature or an enhancement to an existing onefeature-minimal-actionsController-like actions for endpoint routingold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions