如何获取 ASP.NET Core 中所有路由的列表?

     2023-02-22     198

关键词:

【中文标题】如何获取 ASP.NET Core 中所有路由的列表?【英文标题】:How to get a list of all routes in ASP.NET Core? 【发布时间】:2015-04-10 17:24:11 【问题描述】:

在 ASP.NET Core 中,有没有办法查看 Startup 中定义的所有路由的列表?我们使用IRouteBuilderMapRoute 扩展方法来定义路由。

我们正在迁移一个旧项目 WebAPI 项目。在那里我们可以使用GlobalConfiguration.Configuration.Routes 来获取所有路线。

更具体地说,我们在动作过滤器中执行此操作。

public class MyFilter : ActionFilterAttribute
      
    public override void OnActionExecuting(ActionExecutingContext actionContext)
    
        base.OnActionExecuting(actionContext);

        // This no longer works
        // var allRoutes = GlobalConfiguration.Configuration.Routes;

        // var allRoutes = ???
    

【问题讨论】:

【参考方案1】:

要获取所有路由,您需要使用 MVC 的 ApiExplorer 部分。您可以使用属性标记所有操作,也可以使用如下约定:

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;
            
        
    

在 Startup.cs 中,在 ConfigureServices(...) 中添加新的

public void ConfigureServices(IServiceCollection services)

    services.AddMvc(
        options => 
        
            options.Conventions.Add(new ApiExplorerVisibilityEnabledConvention());
            options.
        

在您的ActionFilter 中,您可以使用构造函数注入来获取 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,其中有 RelativePath,这是该路由的路由模板:

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

【讨论】:

我希望我能投票 100 次。在 AspNetCore 中很难找到有关 ApiExplorer 的文档,而且微软在 github 上的示例都已过时。谢谢! 为了清楚起见,这也是在 MVC 5 中使用全局 RouteTable.Routes 的替代品吗?仅仅为了枚举应用程序的路由列表,这似乎是一件非常困难的事情。特别是因为路由很容易在启动代码中连续添加。 恐怕这是 .NET 团队的问题。这是一年前推荐给我的方法。 var apiDescription = actionGroup.First().Items; 使 apiDescription 类型为 IReadOnlyList&lt;ApiDescription&gt;,因此 apiDescription.RelativePath 无效。 这是如何获取所有路由的?看起来这只是获取当前请求的路由。【参考方案2】:

如果您使用的是 ASP.NET Core 3.0+,这意味着您使用的是endpoint routing,那么您可以使用EndpointDataSources 列出所有路由。

IEnumerable&lt;EndpointDataSource&gt; 注入您的控制器/端点,然后提取您需要的任何内容。它适用于控制器操作、端点,部分适用于 razor 页面(razor 页面似乎没有公开可用的 HTTP 方法)。

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

当您访问/-/info/endpoints 时,您将获得 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
  ,
]

【讨论】:

非常简单又不错的解决方案! 谢谢!这个对我有用。我将方法的信号从public async Task&lt;ActionResult&gt; ListAllEndpoints()更改为public IActionResult ListAllEndpoints() 为什么注入IEnumerable&lt;EndpointDataSource&gt; 而不仅仅是EndpointDataSource? DI 容器(.Net 5/6)中只有一个EndpointDataSource 注册。 @Granger 是的。但 ASP.NET Core 旨在支持多个端点源。例如,您/一个库可以提供从数据库或上游服务生成端点的另一个源。使用IEnumerable&lt;EndpointDataSource&gt; 注入所有实现会更安全。见source.dot.net/#Microsoft.AspNetCore.Routing/…【参考方案3】:

你可以看看这个很棒的 GitHub 项目:

https://github.com/kobake/AspNetCore.RouteAnalyzer

项目自述文件

=========================

AspNetCore.RouteAnalyzer

查看 ASP.NET Core 项目的所有路由信息。

截取的截图

在您的 ASP.NET Core 项目中的使用

安装 NuGet 包

NuGet Gallery | AspNetCore.RouteAnalyzer

PM&gt; Install-Package AspNetCore.RouteAnalyzer

编辑 Startup.cs

在 Startup.cs 中插入代码 services.AddRouteAnalyzer(); 和所需的 using 指令,如下所示。

using AspNetCore.RouteAnalyzer; // Add

public void ConfigureServices(IServiceCollection services)

    services.AddMvc();
    services.AddRouteAnalyzer(); // Add

案例1:在浏览器上查看路由信息

在 Startup.cs 中插入代码routes.MapRouteAnalyzer("/routes");,如下所示。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    ....
    app.UseMvc(routes =>
    
        routes.MapRouteAnalyzer("/routes"); // Add
        routes.MapRoute(
            name: "default",
            template: "controller/action=Index/id?");
    );

然后你可以访问http://..../routes的url,在你的浏览器上查看所有的路由信息​​。 (此网址/routes可通过MapRouteAnalyzer()自定义。)

案例2:在VS输出面板上打印路由

在 Startup.cs 中插入如下代码块。

public void Configure(
    IApplicationBuilder app,
    IHostingEnvironment env,
    IApplicationLifetime applicationLifetime, // Add
    IRouteAnalyzer routeAnalyzer // Add
)

    ...

    // Add this block
    applicationLifetime.ApplicationStarted.Register(() =>
    
        var infos = routeAnalyzer.GetAllRouteInformations();
        Debug.WriteLine("======== ALL ROUTE INFORMATION ========");
        foreach (var info in infos)
        
            Debug.WriteLine(info.ToString());
        
        Debug.WriteLine("");
        Debug.WriteLine("");
    );

然后就可以在VS输出面板查看所有路由信息了。

【讨论】:

aspnet core 2.2 存在一个问题,您需要使用services.AddMvc(options =&gt; options.EnableEndpointRouting = false; ); 禁用options.EnableEndpointRouting。该项目似乎还可以,但不明白您是否有自定义路由属性。【参考方案4】:

上面没有成功,因为我想要一个完整的 url,我不必搞乱构建 url 的东西,而是让框架处理解决方案。所以从AspNetCore.RouteAnalyzer 和无数的谷歌搜索和搜索,我没有找到明确的答案。

以下适用于典型的家庭控制器和区域控制器:

public class RouteInfoController : Controller

    // for accessing conventional routes...
    private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;

    public RouteInfoController(
        IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
    
        _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
    

    public IActionResult Index()
    
        StringBuilder sb = new StringBuilder();

        foreach (ActionDescriptor ad in _actionDescriptorCollectionProvider.ActionDescriptors.Items)
        
            var action = Url.Action(new UrlActionContext()
            
                Action = ad.RouteValues["action"],
                Controller = ad.RouteValues["controller"],
                Values = ad.RouteValues
            );

            sb.AppendLine(action).AppendLine().AppendLine();
        

        return Ok(sb.ToString());
    

这将在我的简单解决方案中输出以下内容:

/
/Home/Error
/RouteInfo
/RouteInfo/Links
/Area51/SecureArea

以上是使用 dotnetcore 3 preview 完成的,但我认为它应该适用于 dotnetcore 2.2。此外,以这种方式获取 url 将考虑任何已实施的约定,包括 Scott Hanselman's Blog

【讨论】:

这是我的首选解决方案。我首先尝试了 abdusco 的答案,效果很好,但由于具有内部构造函数的密封类(即没有 CreateInstance 恶作剧),我无法进行单元测试。模拟 IActionDescriptorCollectionProvider.ActionDescriptors 属性要简单得多。【参考方案5】:

您可以通过以下方式从 HttpActionContext 获取 HttpRouteCollection:

actionContext.RequestContext.Configuration.Routes

RequestContext

HttpConfiguration

HttpRouteCollection

-- 问题更新后--

ActionExecutingContext 有一个从 ControllerContext 继承的 RouteData 属性,它公开了 DataTokens 属性(这是一个路由值字典)。它可能与您习惯使用的集合不同,但它确实提供了对该集合的访问:

actionContext.RouteData.DataTokens

DataTokens

【讨论】:

好的 - 在我的情况下这是一个空字典。 RouteData 似乎保存与当前路线有关的数据,而不是所有路线的列表。 actionContext.RequestContext.Configuration.Routes 不存在了。【参考方案6】:

使用 iApplicationBuilder 'app' 对象,我编写了这个简单的代码 sn-p,您可以将其添加到 Startup 类中的 Configure 方法的末尾. 它应该检索(至少在 ASP.NET Core 3.1 中)可用的注册路由。它将它们存储到“theRoutes”列表中,您可以简单地在调试会话中进行检查(就像我所做的那样,因为这对我来说已经足够了),或者您可以记录它,等等。

// Put this code at the end of 'Configure' method in 'Startup' class (ASP.Net Core 3.1)
var theRoutes = new List<string>();
var v1 = app.Properties["__EndpointRouteBuilder"];
var v2 = (System.Collections.Generic.List<Microsoft.AspNetCore.Routing.EndpointDataSource>)(v1.GetType().GetProperty("DataSources").GetValue(v1, null));
foreach (var v3 in v2)

    foreach (var v4 in v3.Endpoints)
    
        var v5 = (Microsoft.AspNetCore.Routing.Patterns.RoutePattern) (v4.GetType().GetProperty("RoutePattern").GetValue(v4, null));
        theRoutes.Add(v5.RawText); 
    

【讨论】:

【参考方案7】:

这仅对调试有用:

var routes = System.Web.Http.GlobalConfiguration.Configuration.Routes;
var field = routes.GetType().GetField("_routeCollection", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var collection = field.GetValue(routes) as System.Web.Routing.RouteCollection;
var routeList = collection
    .OfType<IEnumerable<System.Web.Routing.RouteBase>>()
    .SelectMany(c => c)
    .Cast<System.Web.Routing.Route>()
    .Concat(collection.OfType<System.Web.Routing.Route>())
    .Select(r => $"r.Url ( r.GetType().Name)")
    .OrderBy(r => r)
    .ToArray();

routeList 将包含路由和类型的字符串数组。

【讨论】:

如何使用 ASP.NET Core 获取当前路由名称?

】如何使用ASP.NETCore获取当前路由名称?【英文标题】:HowcanIgetthecurrentroutenamewithASP.NETCore?【发布时间】:2019-11-2302:59:35【问题描述】:我有一个基于ASP.NETCore2.2框架编写的应用程序。我有以下控制器publicclassTestController:Controller[R... 查看详情

ASP.Net Core 2.0 如何获取中间件中的所有请求标头? [复制]

】ASP.NetCore2.0如何获取中间件中的所有请求标头?[复制]【英文标题】:ASP.NetCore2.0Howtogetallrequestheadersinmiddleware?[duplicate]【发布时间】:2018-08-2418:06:34【问题描述】:在ASP.NetCore2.0中,我尝试在自定义中间件中验证传入的请求标头... 查看详情

如何在 ASP.NET Core 中强制执行小写路由?

】如何在ASP.NETCore中强制执行小写路由?【英文标题】:HowdoyouenforcelowercaseroutinginASP.NETCore?【发布时间】:2016-07-2109:40:38【问题描述】:在ASP.NET4中,这与应用程序的RegisterRoutes处理程序中的routes.LowercaseUrls=true;一样简单。我在ASP.... 查看详情

获取 ASP .Net Core WebAPI 中的所有身份角色

】获取ASP.NetCoreWebAPI中的所有身份角色【英文标题】:GetallIdentityrolesinASP.NetCoreWebAPI【发布时间】:2021-10-1002:54:22【问题描述】:我的任务是获取数据库中的所有身份角色。我使用下面的代码来获取所有角色。在Asp.Net核心WebAPI中U... 查看详情

如何在 ASP.NET Core 2.0 中根据路由配置服务身份验证

】如何在ASP.NETCore2.0中根据路由配置服务身份验证【英文标题】:HowtoConfigureServicesAuthenticationbasedonroutesinASP.NETCore2.0【发布时间】:2018-03-0922:06:40【问题描述】:在ASP.NETCore1.x中,我可以在Configure中使用身份验证方法,但现在在ASP... 查看详情

如何覆盖 .ASP.NET Core 5 中的路由?

】如何覆盖.ASP.NETCore5中的路由?【英文标题】:Howtooverrideroutein.ASP.NETCore5?【发布时间】:2021-06-2301:34:35【问题描述】:我想在ASP.NETCore5中覆盖路由我试过这个,但它不起作用varlastExistingRoute=routeBuilder.Routes.FirstOrDefault(x=>((Route)... 查看详情

如何在 ASP.NET Core API 控制器中获取多个表的记录

】如何在ASP.NETCoreAPI控制器中获取多个表的记录【英文标题】:HowtofetchrecordofmorethanonetableinASP.NETCoreAPIController【发布时间】:2020-06-2901:17:57【问题描述】:我想从数据库中获取3个表,只是从3个表中获取所有值。这个api在销售控... 查看详情

如何在 ocelot.json 路由 asp.net core 中发布 json body

】如何在ocelot.json路由asp.netcore中发布jsonbody【英文标题】:Howpostjsonbodyinocelot.jsonrouteasp.netcore【发布时间】:2021-09-0311:57:44【问题描述】:"DownstreamPathTemplate":"/ProceedToBuy/PostWishList","DownstreamScheme":"http","DownstreamHostAnd 查看详情

在 ASP.NET Core 3.x Endpoints 路由中,如何指定域名?

】在ASP.NETCore3.xEndpoints路由中,如何指定域名?【英文标题】:InASP.NETCore3.xEndpointsrouting,howtospecifydomainname?【发布时间】:2020-08-0705:22:20【问题描述】:我希望能够根据URL的域名路由到不同的控制器。比如当请求的URL是www.domain1.co... 查看详情

如何在asp.net core中获取当前用户

】如何在asp.netcore中获取当前用户【英文标题】:Howtogetcurrentuserinasp.netcore【发布时间】:2016-08-0702:00:32【问题描述】:我想获取当前用户,以便访问他们的电子邮件地址等字段。但我不能在asp.net核心中做到这一点。这是我的代... 查看详情

ASP.Net Core 如何在 EF Core 和 Identity 中获取用户角色

】ASP.NetCore如何在EFCore和Identity中获取用户角色【英文标题】:ASP.NetCorehowtogettheuserroleinEFCoreandIdentity【发布时间】:2018-01-0814:25:00【问题描述】:您好,我正在使用Identity和自定义用户类和EFCore构建API。我想获取属于用户的角色... 查看详情

如何在 ASP.NET Core 中获取 HttpContext.Current? [复制]

】如何在ASP.NETCore中获取HttpContext.Current?[复制]【英文标题】:HowtogetHttpContext.CurrentinASP.NETCore?[duplicate]【发布时间】:2016-11-2823:44:31【问题描述】:我们目前正在使用ASP.NETCore重写/转换我们的ASP.NETWebForms应用程序。尽量避免重新... 查看详情

ASP.NET Core 3.1 - 如何获取客户端的 IP 地址?

】ASP.NETCore3.1-如何获取客户端的IP地址?【英文标题】:ASP.NETCore3.1-HowdoIgetaclient\'sIPAddress?【发布时间】:2020-05-1609:44:32【问题描述】:我有一个Razor页面Web应用程序并正在记录用户的IP地址。出于某种原因,它返回的是IP地址,... 查看详情

如何在 ASP.NET Core MVC 中获取 Url Referrer?

】如何在ASP.NETCoreMVC中获取UrlReferrer?【英文标题】:HowcanIgetUrlReferrerinASP.NETCoreMVC?【发布时间】:2016-08-0416:08:21【问题描述】:我正在尝试将ASP.NETMVC网络表单迁移到ASP.NETCoreMVC。目前,我在使用Request.UrlReferrer课程时遇到了问题... 查看详情

如何在 ASP.NET Core 中获取我网站的 baseurl?

】如何在ASP.NETCore中获取我网站的baseurl?【英文标题】:HowcanIgetthebaseurlofmysiteinASP.NETCore?【发布时间】:2017-04-2017:56:06【问题描述】:假设我的网站托管在www.example.com的mywebsite文件夹中,我访问了https://www.example.com/mywebsite/home/abo... 查看详情

如何在 Asp.net Core 中获取用户浏览器名称(用户代理)?

】如何在Asp.netCore中获取用户浏览器名称(用户代理)?【英文标题】:HowtogetuserBrowsername(user-agent)inAsp.netCore?【发布时间】:2015-04-2405:52:15【问题描述】:能否告诉我如何获取客户端在MVC6、ASP.NET5中使用的浏览器名称?【问题讨... 查看详情

如何从 ASP.NET Core 的 Main() 中获取环境变量?

】如何从ASP.NETCore的Main()中获取环境变量?【英文标题】:HowtogetenvironmentvariablesfrominsideMain()inASP.NETCore?【发布时间】:2020-06-2618:56:18【问题描述】:我想知道代码是否是Dev/Stage,所以我需要得到它。我尝试了下面的代码,但它似... 查看详情

如何在 ASP.NET CORE 3.1 中获取客户端 IP 地址?

】如何在ASP.NETCORE3.1中获取客户端IP地址?【英文标题】:HowdoIgetclientIPaddressinASP.NETCORE3.1?【发布时间】:2020-04-2921:06:39【问题描述】:在WebAPI项目中编写代码时如何在ASP.NET3.1中获取客户端IP地址【问题讨论】:这能回答你的问题... 查看详情