获取所有在ASP.NET Core中注册的路由

67

我是.NET Core的新手。我想要获取ASP.NET Core中所有已注册路由的列表。在ASP.NET MVC中,我们可以通过System.Web.Routing中的路由表来实现,那么在ASP.NET Core中也有类似的东西吗?我想要在我的控制器操作中获取路由列表。


3
可能是 获取所有路由列表 的重复问题。 - Set
5
那里没有我要找的答案! - Beaumind
11个回答

61

我创建了NuGet包"AspNetCore.RouteAnalyzer",提供了一个功能来获取所有路由信息。

如果您想尝试,请使用它。

用法

包管理器控制台

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
        ....
    });
}

浏览

运行项目后,您可以访问URL/routes来查看您的项目的所有路由信息。


请告诉我,您能否提供请求(get、post)的返回类型和路由列表。我没有找到这些信息。 - Stefan Hansch
31
NuGet包不再维护,也无法与core 2.2及以上版本一起使用。下面的答案更简单,并且适用于MVC和razor页面。 - Allan Xu
1
请在如何在Web API项目中使用此方法方面提供更多信息,包括后续版本。以上答案不适用于Web API项目。 - Soundararajan
如果您不使用 app.UseMvc,有没有简单的方法来使用这个库? - workabyte
无法工作,只返回“TypeLoadException: 无法从程序集'Microsoft.AspNetCore.Mvc.Core, Version=7.0.0.0, Culture=neutral, PublicKeyToken=xxxx'中加载类型'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint'。” - ataraxia

39
你可以从 IActionDescriptorCollectionProvider 中获取一个 ActionDescriptor 集合。在那里,你可以查看项目中引用的所有操作,并可以获取包含路由信息的 AttributeRouteInfoRouteValues

示例:


    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; }
    }


12
我认为应该有一种更简单的方式... :( 到目前为止,所有这些 asp.net core MVC 的东西对我来说看起来非常复杂。不确定为什么他们没有提供从传统 MVC 的简单过渡方式... - Alexander
@Alexander,这可能看起来有点复杂,但我尝试了Edgar Mesquita的方法,它是有效的。他在其中包含了自己的类,你可以将其替换为Tuple<string, string>以使其更简单。 - Alex G.
3
根据你的回答,我更新了操作以返回一个包含所有路由及其对应控制器/操作的HTML响应:https://pastebin.com/WK7GPrQf - Robar

22

你还可以使用ActionDescriptors.Items数组中的Template = x.AttributeRouteInfo.Template值。以下是来自此处的完整代码示例:

    [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);
        }
      }

考虑在 .Select 之前添加 " .Where(ad => ad.AttributeRouteInfo != null) " 以避免空异常。 - granadaCoder
我的下一个评论是我的过度(?)的空值安全检查版本(太大了,无法放入一个评论中)。 - granadaCoder
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
你可以通过将其转换为ControllerActionDescriptor来获得对控制器相关信息的键入访问。例如,如果你只对控制器的操作感兴趣,可以这样做:actionDescriptorCollectionProvider.ActionDescriptors.Items.OfType<ControllerActionDescriptor>()(获取仅包含在控制器中定义的操作的列表,并且其中的项具有类型化属性,例如ControllerTypeInfo)。 - undefined

8

使用ActionDescriptor列出具有HTTP方法(get、post等)的路由

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; }
}

结果


你能分享RouteModel和RootResultModel吗? - Large
@Rentering.com 很抱歉,代码已经丢失了,但我认为 RouteModel.Name/Method = String 和 rootResultModel.Routes = RouteModel []。 - Reft

7

我使用Swashbuckle 轻松实现了此功能。

您只需在要列出的控制器(和它们的操作)上使用AttributeRouting。


5
请先给其他答案点赞,再考虑我的回答。
我的贡献是将几个答案合并成一个。
我还提供了以下内容:
使用匿名类型(避免强类型对象)(99.9%的情况下,我更喜欢强类型对象,但这是纯友好信息)。
空值检查安全性(可能有些过度,但当我尝试解决问题时,我宁愿过度而不是ArgumentNullException)。
我包括了"using"语句。#吃惊
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",

这里的 "n/a" 是指在某些情况下会出现。
有时可能需要使用以下可选包。

This below optional package may be required.

 <PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />

4
如果您不使用MVC,则可以调用GetRouteData().Routers.OfType<RouteCollection>().First()来访问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
});

请确保在路由处理程序内调用GetRouteData(),否则它将返回null。


在一个asp.net core razor页面应用程序中,“路由处理程序内部”是什么意思?在将建议的代码块添加到我的启动文件后,我在哪里可以读取写入上下文的路由? - T3.0

4

可以通过从 DI 中检索 EndpointDataSource 集合来列出路由的集合。

.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();

在这里输入图像描述

欲了解更多详情,请点击此处


2
我还使用了 IActionDescriptorCollectionProviderRouteValues 中获取信息。
var routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items
    .Select(ad => new
    {
        Action = ad.RouteValues["action"],
        Controller = ad.RouteValues["controller"]
    }).Distinct().ToList();

1

3
这个方法不起作用,提供的链接没有使用 .All() 方法也没有提供源代码。 - Rentering.com

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接