-
Notifications
You must be signed in to change notification settings - Fork 9.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
get the route name given an http method & uri #48034
Comments
Can you clarify? Where are you trying to get this information? What does it have to do with the |
I need this to clean up telemetry in a couple of places for our Azure Resource Provider. When an
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRouting().Configure<RouteOptions>(options => {});
var app = builder.Build();
app.MapGet("/hello", () => "Hello!").WithName(RouteNames.Hello);
app.MapGet("/world", () => "World!").WithName(RouteNames.World);
app.StartAsync();
var endpointDataSource = app.Services.GetService<IEnumerable<EndpointDataSource>>()?.Single() as CompositeEndpointDataSource;
var routeName = GetRouteName(app, "GET", "http://localhost/world");
Console.WriteLine($"routeName: {routeName}");
string? GetRouteName(WebApplication app, string requesHttpMethod, string requestUri)
{
return null; // TODO: Implement
}
static class RouteNames
{
public const string Hello = "Hello";
public const string World = "World";
} I'll start a Teams chat to give more MS internal specifics. |
It's not 100% clear if you intend to use this on the server side or the client side. It would appear to be the server side. If you're on the server side, then you can get the mapping - when defined - without any additional lookup. When matched, here is the world's simplest middleware that would capture the name and API version of the endpoint/route that was invoked, if any: app.Use( ( context, next ) =>
{
if ( context.GetEndpoint() is Endpoint endpoint )
{
var name = endpoint.Metadata.GetMetadata<IEndpointNameMetadata>()?.EndpointName ?? "(no name)";
var version = context.GetRequestedApiVersion();
Debug.WriteLine( $"Endpoint = {name}, API Version = {version}" );
}
return next();
} ); In the context of Minimal APIs, It terms of a reverse lookup for a route/endpoint name from an URL, that is not supported and, honestly, cannot really work as expected. For example, if the incoming request URL is Collating APIs for versioning faces a similar challenge, which is why APIs are not collated by route template; they are collated by logical name for controllers and an optionally named set for Minimal APIs. This is just the surface of the problem. When you throw versioning into the mix, you could end up with templates such as I don't want to discourage you from saying it's impossible, but this is really, really hard, likely brittle, and probably not worth the effort. The best option IMHO is to let the routing system do its thing and then pull the metadata you're interested from the matched endpoint, if any. |
Thank you @commonsensesoftware to answer here and at https://stackoverflow.com/questions/76153365/in-asp-net-core-minimal-api-how-can-you-get-the-route-name . The solution you provided works for me. Combined with using Microsoft.AspNetCore.TestHost;
using System.Diagnostics;
var host = new HostBuilder()
.ConfigureWebHost(webHost => webHost.UseTestServer().Configure(app =>
{
app.UseRouting();
app.Use((context, next) =>
{
if (context.GetEndpoint() is Endpoint endpoint)
{
var endpointName = endpoint.Metadata.GetMetadata<IEndpointNameMetadata>()?.EndpointName;
if (endpointName != null)
{
context.Response.Headers.Add(TagKeys.EndpointName, endpointName);
}
}
return next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/hello", () => "Hello!").WithName(RouteNames.Hello);
endpoints.MapGet("/world", () => "World!").WithName(RouteNames.World);
});
})
.ConfigureServices(services =>
{
services.AddRouting().Configure<RouteOptions>(routeOptions => { });
}
)
).Build();
host.Start();
var httpClient = host.GetTestClient();
await PrintEndpointName(httpClient, new HttpRequestMessage(HttpMethod.Get, "/"));
await PrintEndpointName(httpClient, new HttpRequestMessage(HttpMethod.Get, "/hello"));
await PrintEndpointName(httpClient, new HttpRequestMessage(HttpMethod.Get, "/world"));
async Task PrintEndpointName(HttpClient httpClient, HttpRequestMessage request)
{
var httpResponse = await httpClient.SendAsync(request);
IEnumerable<string>? headers;
httpResponse.Headers.TryGetValues(TagKeys.EndpointName, out headers);
var endpointName = headers?.FirstOrDefault();
Debug.WriteLine($"{((int)httpResponse.StatusCode)} {endpointName}");
}
static class RouteNames
{
public const string Hello = "Hello";
public const string World = "World";
}
static class TagKeys
{
public const string EndpointName = "endpoint.name";
} I'd like to be able to skip the execution of the rest of the endpoint function. May be removing |
Is there an existing issue for this?
Is your feature request related to a problem? Please describe the problem.
I'm using
WithName
to set the operation ID from the API specification. Given an HTTP request, I want to return that name. I only want to use the routing code and not the whole WebApplication plumbing.Previously posted at https://stackoverflow.com/questions/76153365/in-asp-net-core-minimal-api-how-can-you-get-the-route-name , but now feels like this is a feature request.
WithName
expects an operation ID.Describe the solution you'd like
Something that wires up the routing other than
app.Run()
and provides access to the routing.Additional context
No response
The text was updated successfully, but these errors were encountered: