65

I am new to .NET Core. I want to get a list of all registered routes in ASP.NET Core. In ASP.NET MVC we had route table in System.Web.Routing, is there something equivalent in ASP.NET Core? I want to get the routes list in my Controller Action.

Beaumind
  • 876
  • 1
  • 6
  • 13

11 Answers11

60

I've created the NuGet package "AspNetCore.RouteAnalyzer" that provides a feature to get all route information.

Try it if you'd like.

Usage

Package Manager Console

PM> Install-Package AspNetCore.RouteAnalyzer

Startup.cs

using AspNetCore.RouteAnalyzer; // Add
.....
public void ConfigureServices(IServiceCollection services)
{
    ....
    services.AddRouteAnalyzer(); // Add
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ....
    app.UseMvc(routes =>
    {
        routes.MapRouteAnalyzer("/routes"); // Add
        ....
    });
}

Browse

Run project and you can access the url /routes to view all route information of your project.

kobake
  • 1,091
  • 1
  • 12
  • 15
  • Tell please, you return type of request(get, post) with routes list. I didn`t find this information – Stefan Hansch Nov 03 '18 at 09:37
  • 28
    The NuGet package is not maintained anymore and it is not working with core 2.2 and up. Below answers are much simpller and workd well for both MVC and razor pages. – Allan Xu Dec 19 '19 at 03:23
  • 1
    Please update more info on how this works for web api projects . and also later versions. The above answer doesn't work for web api projects. – Soundararajan Jan 15 '21 at 08:28
  • is there an easy way to use this lib if you do not use `app.UseMvc`? – workabyte Oct 30 '22 at 15:53
  • Doesn't work, just returns "TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint' from assembly 'Microsoft.AspNetCore.Mvc.Core, Version=7.0.0.0, Culture=neutral, PublicKeyToken=xxxx'." – ataraxia Aug 22 '23 at 08:08
38

You can take an ActionDescriptor collection from IActionDescriptorCollectionProvider. In there, you can see all actions referred to in the project and can take an AttributeRouteInfo or RouteValues, which contain all information about the routes.

Example:


    using System.Linq;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Infrastructure;

    public class EnvironmentController : Controller
    {
        private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;

        public EnvironmentController(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
        {
            _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
        }

        [HttpGet("routes", Name = "ApiEnvironmentGetAllRoutes")]
        [Produces(typeof(ListResult<RouteModel>))]
        public IActionResult GetAllRoutes()
        {

            var result = new ListResult<RouteModel>();
            var routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items.Where(
                ad => ad.AttributeRouteInfo != null).Select(ad => new RouteModel
                {
                    Name = ad.AttributeRouteInfo.Name,
                    Template = ad.AttributeRouteInfo.Template
                }).ToList();
            if (routes != null && routes.Any())
            {
                result.Items = routes;
                result.Success = true;
            }
            return Ok(result);
        }
    }




    internal class RouteModel
    {
        public string Name { get; set; }
        public string Template { get; set; }
    }


    internal class ListResult<T>
    {
        public ListResult()
        {
        }

        public List<RouteModel> Items { get; internal set; }
        public bool Success { get; internal set; }
    }

granadaCoder
  • 26,328
  • 10
  • 113
  • 146
Edgar Mesquita
  • 489
  • 4
  • 6
  • 12
    I think there should be an easier way... :( so far, all this asp.net core MVC stuff looks pretty complex to me. Not sure why they did not provide easy transition from traditional MVC... – Alexander May 06 '17 at 11:11
  • @Alexander It may seem a bit complicated but I tried Edgar Mesquita's solution and it works. He included his own classes there which you could replace with Tuple to make it simpler. – Alex G. Apr 23 '18 at 22:20
  • 3
    Based on your answer, I updated the action to return a HTML response with all the routes and the according controller/actions: https://pastebin.com/WK7GPrQf – Robar Feb 28 '19 at 10:42
22

You can also use Template = x.AttributeRouteInfo.Template value from ActionDescriptors.Items array. Here is a full code sample from there :

    [Route("monitor")]
    public class MonitorController : Controller {
        private readonly IActionDescriptorCollectionProvider _provider;

        public MonitorController(IActionDescriptorCollectionProvider provider) {
          _provider = provider;
        }

        [HttpGet("routes")]
        public IActionResult GetRoutes() {
            var routes = _provider.ActionDescriptors.Items.Select(x => new { 
               Action = x.RouteValues["Action"], 
               Controller = x.RouteValues["Controller"], 
               Name = x.AttributeRouteInfo.Name, 
               Template = x.AttributeRouteInfo.Template 
            }).ToList();
            return Ok(routes);
        }
      }
kkost
  • 3,640
  • 5
  • 41
  • 72
  • Consider adding " .Where(ad => ad.AttributeRouteInfo != null) " before the .Select to avoid null-exceptions. – granadaCoder Mar 04 '21 at 22:53
  • My next comment is my overly(?) null-safety-check version (too big to put into one comment) – granadaCoder Mar 04 '21 at 22:55
  • 1
    var routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items .Where(ad => ad.AttributeRouteInfo != null) .Select(x => new { Action = null != x && null != x.RouteValues && null != x.RouteValues["action"] ? x.RouteValues["action"] : "n/a", Controller = null != x && null != x.RouteValues && null != x.RouteValues["controller"] ? x.RouteValues["controller"] : "n/a", Name = x.AttributeRouteInfo.Name ?? "n/a", Template = x.AttributeRouteInfo.Template ?? "n/a" }).ToList(); – granadaCoder Mar 04 '21 at 22:55
8

List routes using ActionDescriptor WITH http method (get,post etc)

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Infrastructure;

[Route("")]
[ApiController]
public class RootController : ControllerBase
{
    private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;

    public RootController(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
    {
        _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
    }

    public RootResultModel Get()
    {
        var routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items.Where(
            ad => ad.AttributeRouteInfo != null).Select(ad => new RouteModel
        {
            Name = ad.AttributeRouteInfo.Template,
            Method = ad.ActionConstraints?.OfType<HttpMethodActionConstraint>().FirstOrDefault()?.HttpMethods.First(),
            }).ToList();

        var res = new RootResultModel
        {
            Routes = routes
        };

        return res;
    }
}

internal class RouteModel
{
    public string Name { get; set; }
    public string Template { get; set; }
    public string Method { get; set; }
}

internal class RootResultModel
{
    public List<RouteModel> Routes { get; set; }
}

Result

granadaCoder
  • 26,328
  • 10
  • 113
  • 146
Reft
  • 2,333
  • 5
  • 36
  • 64
  • Can you share RouteModel and RootResultModel too? – Large Feb 14 '20 at 21:13
  • @Rentering.com Im afraid the code has gone missing, but I think RouteModel.Name/Method = String and rootResultModel.Routes = RouteModel [] – Reft Mar 09 '20 at 18:46
7

Using Swashbuckle did the trick for me.

You just need to use AttributeRouting on controllers you want to list (and on their actions)

Guillaume
  • 1,076
  • 10
  • 21
5

Please up-vote OTHER answers before mine.

My contribution is taking several of the answers and merging them into one.

I also contributed:

Use of anonymous-type (to avoid strong-objects) (99.9% of the time, I prefer strongly-typed-objects, but this is a purely friendly-informational information).

null check safety (it might be overkill, but i'd prefer overkill to a ArgumentNullException when I'm trying to figure something out).

I included "using" statements. #gasp

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Infrastructure;

namespace My.WebApiProject.Controllers
{
    public class EnvironmentController : Controller
    {
        private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;

        public EnvironmentController(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
        {
            _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
        }

        [HttpGet("routes", Name = "ApiEnvironmentGetAllRoutes")]
        public IActionResult GetAllRoutes()
        {
            /* intentional use of var/anonymous class since this method is purely informational */
            var routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items
                .Where(ad => ad.AttributeRouteInfo != null)
                .Select(x => new {
                Action = null != x && null != x.RouteValues && null != x.RouteValues["action"] ? x.RouteValues["action"] : "n/a",
                Controller = null != x && null != x.RouteValues && null != x.RouteValues["controller"] ? x.RouteValues["controller"] : "n/a",
                Name = x.AttributeRouteInfo.Name ?? "n/a",
                Template = x.AttributeRouteInfo.Template ?? "n/a",
                Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>().FirstOrDefault()?.HttpMethods.First()
                }).ToList();
            return Ok(routes);
        }
    }
}

"Name = x.AttributeRouteInfo.Name ?? "n/a",

the "n/a" actually shows up from time to time.

This below optional package may be required.

 <PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
granadaCoder
  • 26,328
  • 10
  • 113
  • 146
4

If you don't use MVC call GetRouteData().Routers.OfType<RouteCollection>().First() for access to RouteCollection:

app.UseRouter(r => {
    r.MapGet("getroutes", async context => {
        var routes = context.GetRouteData().Routers.OfType<RouteCollection>().First();
        await context.Response.WriteAsync("Total number of routes: " + routes.Count.ToString() + Environment.NewLine);
        for (int i = 0; i < routes.Count; i++)
        {
            await context.Response.WriteAsync(routes[i].ToString() + Environment.NewLine);
        }               
    });
    // ...
    // other routes
});

Make sure to call GetRouteData() inside route handler otherwise it returns null.

Vadim
  • 111
  • 1
  • 3
  • In an asp.net core razor page application what is considered "inside the route handler"? after adding the suggested block of code to my startup where can I read the routes written to the context? – T3.0 Jun 09 '20 at 21:02
4

The collection of routes can be listed by retrieving the collection of EndpointDataSource from DI.

Example for .NET 6:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseRouting();

if (app.Environment.IsDevelopment())
{
    app.MapGet("/debug/routes", (IEnumerable<EndpointDataSource> endpointSources) =>
        string.Join("\n", endpointSources.SelectMany(source => source.Endpoints)));
}

app.Run();

enter image description here

For more details, go here

Nur.B
  • 319
  • 2
  • 4
2

I did also using IActionDescriptorCollectionProvider getting the information from the RouteValues.

var routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items
    .Select(ad => new
    {
        Action = ad.RouteValues["action"],
        Controller = ad.RouteValues["controller"]
    }).Distinct().ToList();
Tiago Ávila
  • 2,737
  • 1
  • 31
  • 34
1

You are trying to get a router of type RouteCollection. To get all routes of that type you should be able to call .All() on routers of type RouteCollection.

Example: var routes = RouteData.Routers.OfType<RouteCollection>().All();

Credit to: https://rimdev.io/get-registered-routes-from-an-asp.net-mvc-core-application/

Refer to above article if .All() doesn't work.

1

You can inject that on your constructor of your controller

IEnumerable<EndpointDataSource> endpointSources

Then it contains all of mapped routes.