简体   繁体   English

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

[英]How to get a list of all routes in ASP.NET Core?

In ASP.NET Core, is there a way to see a list of all the routes defined in Startup?在 ASP.NET Core 中,有没有办法查看 Startup 中定义的所有路由的列表? We are using the MapRoute extension method of IRouteBuilder to define the routes.我们使用IRouteBuilderMapRoute扩展方法来定义路由。

We are migrating an older project WebAPI project.我们正在迁移一个较旧的项目 WebAPI 项目。 There we could use GlobalConfiguration.Configuration.Routes to get all the routes.在那里我们可以使用GlobalConfiguration.Configuration.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 = ???
    }
}

To get at all the routes, you need to use the ApiExplorer part of MVC.要获取所有路由,您需要使用 MVC 的 ApiExplorer 部分。 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(...)在 Startup.cs 中,在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:在您的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 , which has the RelativePath , which is the route template for that route: 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>();
    }
}

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.如果您使用的是 ASP.NET Core 3.0+,这意味着您正在使用端点路由,那么您可以使用EndpointDataSource列出所有路由。

Inject IEnumerable<EndpointDataSource> to your controller/endpoint then extract anything you need.IEnumerable<EndpointDataSource>注入您的控制器/端点,然后提取您需要的任何内容。 It works with both controller actions, endpoints, and partially with razor pages (razor pages don't seem to expose available HTTP methods).它适用于控制器操作、端点,部分适用于 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);
    }
}

when you visit /-/info/endpoints , you'll get a list of routes as JSON:当您访问/-/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
  },
]

You can take a look at this awesome GitHub project:你可以看看这个很棒的 GitHub 项目:

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

Readme from the project项目自述文件

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

AspNetCore.RouteAnalyzer AspNetCore.RouteAnalyzer

View all route information for ASP.NET Core project.查看 ASP.NET Core 项目的所有路由信息。

Pickuped screenshot截取的屏幕截图

截屏

Usage on your ASP.NET Core project在 ASP.NET Core 项目上的使用

Install NuGet package安装 NuGet 包

PM> Install-Package AspNetCore.RouteAnalyzer

Edit Startup.cs编辑 Startup.cs

Insert code services.AddRouteAnalyzer();插入代码services.AddRouteAnalyzer(); and required using directive into Startup.cs as follows.并且需要using指令进入 Startup.cs,如下所示。

using AspNetCore.RouteAnalyzer; // Add

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddRouteAnalyzer(); // Add
}

Case1: View route information on browser案例1:在浏览器上查看路线信息

Insert code routes.MapRouteAnalyzer("/routes");插入代码routes.MapRouteAnalyzer("/routes"); into Startup.cs as follows.进入 Startup.cs 如下。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ....
    app.UseMvc(routes =>
    {
        routes.MapRouteAnalyzer("/routes"); // Add
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action=Index}/{id?}");
    });
}

Then you can access url of http://..../routes to view all route informations on your browser.然后您可以访问http://..../routes的 url 以在浏览器上查看所有路由信息。 (This url /routes can be customized by MapRouteAnalyzer() .) (这个 url /routes可以通过MapRouteAnalyzer()自定义。)

截屏

Case2: Print routes on VS output panel Case2:在 VS 输出面板上打印路由

Insert a code block as below into Startup.cs.将如下代码块插入 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("");
    });
}

Then you can view all route informations on VS output panel.然后您可以在 VS 输出面板上查看所有路由信息。

截屏

Not been successful with the above, as I wanted a full url which I didn't have to mess around with things to construct the url, but instead let the framework handle the resolution.上面的方法没有成功,因为我想要一个完整的 url,我不必搞乱构造 url 的东西,而是让框架处理分辨率。 So following on from AspNetCore.RouteAnalyzer and countless googling and searching, I didn't find a definitive answer.因此,继AspNetCore.RouteAnalyzer和无数的谷歌搜索之后,我没有找到明确的答案。

The following works for me for typical home controller and area controller:以下适用于典型的家庭控制器和区域控制器:

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

This will output the following in my simple solution:这将在我的简单解决方案中输出以下内容:

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

The above was done using dotnetcore 3 preview but I think it should work with dotnetcore 2.2.以上是使用 dotnetcore 3 preview 完成的,但我认为它应该适用于 dotnetcore 2.2。 Additionally getting the url this way will take into consideration any conventions that have been put in place including the excellent slugify as brought to light on Scott Hanselman's Blog此外,以这种方式获取 url 将考虑已实施的任何约定,包括在Scott Hanselman 的博客上展示的出色的 slugify

You can get an HttpRouteCollection from the HttpActionContext via:您可以通过以下方式从 HttpActionContext 获取 HttpRouteCollection:

actionContext.RequestContext.Configuration.Routes

RequestContext 请求上下文

HttpConfiguration HttpConfiguration

HttpRouteCollection HttpRouteCollection

-- After Question Updated -- -- 问题更新后 --

The ActionExecutingContext has a RouteData property that it inherits from ControllerContext, which exposes the DataTokens property (which is a route value dictionary). ActionExecutingContext 有一个从 ControllerContext 继承的 RouteData 属性,它公开了 DataTokens 属性(这是一个路由值字典)。 It is probably not the same collection you're used to working with, but it does provide access to that collection:它可能与您习惯使用的集合不同,但它确实提供了对该集合的访问:

actionContext.RouteData.DataTokens

DataTokens 数据令牌

Playing wit the the iApplicationBuilder 'app' object, I wrote this simple code snippet that you can add at the end of the Configure method in the Startup class.使用 iApplicationBuilder 'app' 对象,我编写了这个简单的代码片段,您可以将其添加到Startup类的Configure方法的末尾。 It supposedly retrieve (at least in ASP.NET Core 3.1) the available registered routes.它应该检索(至少在 ASP.NET Core 3.1 中)可用的注册路由。 It store them into the 'theRoutes' list, that you can simply inspect on a debug session (like I did, since it was enough for me), or you can log it, etc.它将它们存储到“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); 
    }
}

This is useful for debugging only:这仅对调试有用:

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 will contain a string array of routes and types. routeList 将包含路由和类型的字符串数组。

You can inject that on your controller.您可以将其注入您的控制器。

IEnumerable<EndpointDataSource> endpointSources

Then it contains all of mapped routes.然后它包含所有映射的路由。

_actionDescriptorCollectionProvider works only for routes mapped with route attribute. _actionDescriptorCollectionProvider 仅适用于使用路由属性映射的路由。 But in my case I was modernizing an old mvc application.但就我而言,我正在对旧的 mvc 应用程序进行现代化改造。 I mapping all of my controllers with app.MapControllerRoute.我用 app.MapControllerRoute 映射我的所有控制器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 获取 ASP.NET Core 中所有注册的路由 - Get all registered routes in ASP.NET Core 如何在asp.net MVC中获取所有已配置的WebApi路由的列表? - How do I get a list of all configured WebApi routes in asp.net MVC? 如何将所有 404 路由重定向到 ASP.NET Core MVC 中的一个中心操作? - How to redirect all 404 routes to one central action in ASP.NET Core MVC? 如何在ASP.NET Core 2.0控制器上同时具有“通过ID获取”和“按名称获取”路由? - How to have both 'get by id' and 'get by name' routes on ASP.NET core 2.0 controller? 获取ASP.NET Core 1中的所有缓存 - Get all cache in ASP.NET Core 1 当 `RoutePrefix` 或 `Route` 属性未使用时,获取所有路由列表 (ASP.NET) - Get list of all routes (ASP.NET) when `RoutePrefix` or `Route` attributes are not using 如何在ASP.NET Core 2.0 MVC中为GET和POST请求添加单独的默认路由? - How can add separate default routes for GET and POST requests in ASP.NET Core 2.0 MVC? 如何在 ASP.NET Core MVC 中为 Identity 添加自定义路由? - How to add custom routes in ASP.NET Core MVC for Identity? 如何重定向到 asp.net 核心 razor 页面(无路由) - How to redirect to a asp.net core razor page (no routes) 使用asp.net核心启用角度路由 - Enable angular routes with asp.net core
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM