March 19, 2020

Resolving the current route name in ASP.NET Core 3.1

Endpoint routing was first introduced in ASP.NET Core 2.2 with the goal of making routing a cross-cutting concern, decoupling it from the MVC framework. You can find a detailed write-up on endpoint routing here.

In our applications we use custom middleware to record metrics about our API usage. Rather than recording every single request (including invalid paths), we only record metrics for genuine routes. Our convention is that if you want a controller action to be tracked, you need to give the corresponding route a name:

[HttpPost(Name = "RequestPayment")]
public async Task<IActionResult> PostAsync([FromBody] PaymentRequest request)
{
    ...
}

In ASP.NET Core 2.2 we registered endpoint routing like so:

app.UseEndpointRouting();

To retrieve the current endpoint name (from the MVC route) we used the following extension:

/// <summary>
/// Gets the current API resource name from HTTP context
/// </summary>
/// <param name="httpContext">The HTTP context</param>
/// <returns>The current resource name if available, otherwise an empty string</returns>
public static string GetMetricsCurrentResourceName(this HttpContext httpContext)
{
    if (httpContext == null)
        throw new ArgumentNullException(nameof(httpContext));

    Endpoint endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;

    return endpoint?.Metadata.GetMetadata<IRouteValuesAddressMetadata>()?.RouteName;
}

As of ASP.NET Core 3.0, the IRouteValuesAddressMetadata type has been removed. To achieve the same result in ASP.NET Core 3.0 onwards, you can do the following:

/// <summary>
/// Gets the current API resource name from HTTP context
/// </summary>
/// <param name="httpContext">The HTTP context</param>
/// <returns>The current resource name if available, otherwise an empty string</returns>
public static string GetMetricsCurrentResourceName(this HttpContext httpContext)
{
    if (httpContext == null)
        throw new ArgumentNullException(nameof(httpContext));

    Endpoint endpoint = httpContext.GetEndpoint();
    return endpoint?.Metadata.GetMetadata<EndpointNameMetadata>()?.EndpointName;
}

© 2020 Ben Foster