In ASP.NET Core, is there a way to see a list of all the routes defined in Startup? We are using the MapRoute
extension method of IRouteBuilder
to define the routes.
We are migrating an older project WebAPI project. There we could use GlobalConfiguration.Configuration.Routes
to get all the routes.
More specifically, we are doing this within an action filter.
public class MyFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext actionContext) { base.OnActionExecuting(actionContext); // This no longer works // var allRoutes = GlobalConfiguration.Configuration.Routes; // var allRoutes = ??? } }
UseRouting adds route matching to the middleware pipeline. This middleware looks at the set of endpoints defined in the app, and selects the best match based on the request. UseEndpoints adds endpoint execution to the middleware pipeline. It runs the delegate associated with the selected endpoint.
In ASP.NET, routing is the process of directing the HTTP requests to the right controller. The MVC middleware must decide whether a request should go to the controller for processing or not. The middleware makes this decision based on the URL and some configuration information.
Every ASP.NET MVC application must configure (register) at least one route in the RouteConfig class and by default, the ASP.NET MVC Framework provides one default route. But you can configure as many routes as you want.
Inside the call to UseEndpoints() , we use the MapControllerRoute() method to create a route by giving the name default . MVC configures the default route template as {controller=Home}/{action=Index}/{id?} . This will match the Index() method in HomeController with an optional parameter id by default.
If you're on ASP.NET Core 3.0+, that means you're using endpoint routing, then you can list all routes with EndpointDataSource
s.
Inject IEnumerable<EndpointDataSource>
to your controller/endpoint then extract anything you need. It works with both controller actions, endpoints, and partially with razor pages (razor pages don't seem to expose available HTTP methods).
[Route("/-/{controller}")] public class InfoController : Controller { private readonly IEnumerable<EndpointDataSource> _endpointSources; public InfoController( IEnumerable<EndpointDataSource> endpointSources ) { _endpointSources = endpointSources; } [HttpGet("endpoints")] public async Task<ActionResult> ListAllEndpoints() { var endpoints = _endpointSources .SelectMany(es => es.Endpoints) .OfType<RouteEndpoint>(); var output = endpoints.Select( e => { var controller = e.Metadata .OfType<ControllerActionDescriptor>() .FirstOrDefault(); var action = controller != null ? $"{controller.ControllerName}.{controller.ActionName}" : null; var controllerMethod = controller != null ? $"{controller.ControllerTypeInfo.FullName}:{controller.MethodInfo.Name}" : null; return new { Method = e.Metadata.OfType<HttpMethodMetadata>().FirstOrDefault()?.HttpMethods?[0], Route = $"/{e.RoutePattern.RawText.TrimStart('/')}", Action = action, ControllerMethod = controllerMethod }; } ); return Json(output); } }
when you visit /-/info/endpoints
, you'll get a list of routes as JSON:
[ { "method": "GET", "route": "/-/info/endpoints", // <-- controller action "action": "Info.ListAllEndpoints", "controllerMethod": "Playground.Controllers.InfoController:ListAllEndpoints" }, { "method": "GET", "route": "/WeatherForecast", // <-- controller action "action": "WeatherForecast.Get", "controllerMethod": "Playground.Controllers.WeatherForecastController:Get" }, { "method": "GET", "route": "/hello", // <-- endpoint route "action": null, "controllerMethod": null }, { "method": null, "route": "/about", // <-- razor page "action": null, "controllerMethod": null }, ]
To get at all the routes, you need to use the ApiExplorer part of MVC. You can either mark all your actions with an attribute or use a convention like this one:
public class ApiExplorerVisibilityEnabledConvention : IApplicationModelConvention { public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { if (controller.ApiExplorer.IsVisible == null) { controller.ApiExplorer.IsVisible = true; controller.ApiExplorer.GroupName = controller.ControllerName; } } } }
In Startup.cs, add your new in ConfigureServices(...)
public void ConfigureServices(IServiceCollection services) { services.AddMvc( options => { options.Conventions.Add(new ApiExplorerVisibilityEnabledConvention()); options. } }
In your ActionFilter
you can then use constructor injection to get the ApiExplorer:
public class MyFilter : ActionFilterAttribute { private readonly IApiDescriptionGroupCollectionProvider descriptionProvider; public MyFilter(IApiDescriptionGroupCollectionProvider descriptionProvider) { this.descriptionProvider = descriptionProvider; } public override void OnActionExecuting(ActionExecutingContext actionContext) { base.OnActionExecuting(actionContext); // The convention groups all actions for a controller into a description group var actionGroups = descriptionProvider.ApiDescriptionGroups.Items; // All the actions in the controller are given by var apiDescription = actionGroup.First().Items.First(); // A route template for this action is var routeTemplate = apiDescription.RelativePath } }
ApiDescription
, which has the RelativePath
, which is the route template for that route:
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Microsoft.AspNetCore.Mvc.ApiExplorer { public class ApiDescription { public string GroupName { get; set; } public string HttpMethod { get; set; } public IList<ApiParameterDescription> ParameterDescriptions { get; } = new List<ApiParameterDescription>(); public IDictionary<object, object> Properties { get; } = new Dictionary<object, object>(); public string RelativePath { get; set; } public ModelMetadata ResponseModelMetadata { get; set; } public Type ResponseType { get; set; } public IList<ApiRequestFormat> SupportedRequestFormats { get; } = new List<ApiRequestFormat>(); public IList<ApiResponseFormat> SupportedResponseFormats { get; } = new List<ApiResponseFormat>(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With