在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 = ???
}
}
答案 0 :(得分:18)
要获得所有路线,您需要使用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>();
}
}
答案 1 :(得分:5)
如果您使用的是 ASP.NET Core 3.0+,这意味着您使用的是 endpoint routing,那么您可以列出所有带有 EndpointDataSource
的路由。
将 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);
}
}
当您访问 /-/info/endpoints
时,您将获得 JSON 格式的路线列表:
[
{
"method": "GET",
"route": "/-/info/routes", // <-- controller action
"action": "Info.ListAllRoutes",
"controllerMethod": "Playground.Controllers.InfoController:ListAllRoutes"
},
{
"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
},
]
答案 2 :(得分:4)
你可以看一下这个很棒的GitHub项目:
https://github.com/kobake/AspNetCore.RouteAnalyzer
=======================
查看ASP.NET Core项目的所有路由信息。
PM> Install-Package AspNetCore.RouteAnalyzer
将代码services.AddRouteAnalyzer();
和必需的using
指令插入Startup.cs,如下所示。
```CS 使用AspNetCore.RouteAnalyzer; //添加
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddRouteAnalyzer(); // Add
}
将代码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?}");
});
}
然后,您可以访问http://..../routes
的网址,以查看浏览器上的所有路线信息。 (此网址/routes
可以由MapRouteAnalyzer()
自定义。)
将如下代码块插入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输出面板上查看所有路线信息。
答案 3 :(得分:2)
您可以通过以下方式从HttpActionContext获取HttpRouteCollection:
actionContext.RequestContext.Configuration.Routes
- 问题更新后 -
ActionExecutingContext有一个RouteData属性,它继承自ControllerContext,后者公开DataTokens属性(这是一个路由值字典)。它可能与您习惯使用的集合不同,但它确实提供了对该集合的访问:
actionContext.RouteData.DataTokens
答案 4 :(得分:1)
上述操作并不成功,因为我想要一个完整的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预览版完成的,但我认为它应与dotnetcore 2.2一起使用。此外,以这种方式获取url将考虑已制定的所有约定,包括
上公开的出色的Slugify。答案 5 :(得分:0)
这仅对调试有用:
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将包含路由和类型的字符串数组。
答案 6 :(得分:0)
我使用iApplicationBuilder'app'对象编写了这个简单的代码段,您可以将其添加到 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);
}
}