获取所有路线的列表

clh*_*ian 18 c# routes asp.net-core-mvc asp.net-core

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

我们正在迁移一个较旧的项目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 = ???
    }
}
Run Code Online (Sandbox Code Playgroud)

Dr *_*ang 20

要获得所有路由,您需要使用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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(
        options => 
        {
            options.Conventions.Add(new ApiExplorerVisibilityEnabledConvention());
            options.
        }
}
Run Code Online (Sandbox Code Playgroud)

在你的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
    }
}
Run Code Online (Sandbox Code Playgroud)

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)


abd*_*sco 10

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

注入IEnumerable<EndpointDataSource>您的控制器/端点,然后提取您需要的任何内容。它适用于控制器操作、端点,部分适用于 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当您访问 时/-/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
  },
]
Run Code Online (Sandbox Code Playgroud)

  • @Granger 确实如此。但 ASP.NET Core 旨在支持多个端点源。例如,您/库可以提供另一个从数据库或上游服务生成端点的源。使用“IEnumerable&lt;EndpointDataSource&gt;”注入所有实现会更安全。请参阅 https://source.dot.net/#Microsoft.AspNetCore.Routing/EndpointDataSource.cs,e430965f5ce4b2ff,参考 (3认同)

And*_*dez 6

上面没有成功,因为我想要一个完整的 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());
    }
Run Code Online (Sandbox Code Playgroud)

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

/
/Home/Error
/RouteInfo
/RouteInfo/Links
/Area51/SecureArea
Run Code Online (Sandbox Code Playgroud)

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


Len*_*rri 5

您可以看一下这个很棒的GitHub项目:

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

该项目的自述文件

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

AspNetCore.RouteAnalyzer

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

截图

屏幕截图

在ASP.NET Core项目上的用法

安装NuGet软件包

PM> Install-Package AspNetCore.RouteAnalyzer

编辑Startup.cs

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

使用AspNetCore.RouteAnalyzer的cs; //添加

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddRouteAnalyzer(); // Add
}
Run Code Online (Sandbox Code Playgroud)

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

routes.MapRouteAnalyzer("/routes");如下所示将代码插入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?}");
    });
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以访问的URL,http://..../routes以在浏览器中查看所有路线信息。(/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("");
    });
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在VS输出面板上查看所有路线信息。

屏幕截图

  • aspnet core 2.2存在一个问题,您需要使用services.AddMvc(options =&gt; {options.EnableEndpointRouting = false;});禁用`options.EnableEndpointRouting`。该项目看起来还可以,但是不知道您是否具有自定义路线属性。 (2认同)

pwn*_*ess 3

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

actionContext.RequestContext.Configuration.Routes
Run Code Online (Sandbox Code Playgroud)

请求上下文

Http配置

HttpRoute集合

-- 问题更新后 --

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

actionContext.RouteData.DataTokens
Run Code Online (Sandbox Code Playgroud)

数据代币

  • 好吧 - 对我来说这是一本空字典。RouteData 似乎保存与当前路线相关的数据,而不是所有路线的列表。 (2认同)