web-dev-qa-db-ja.com

すべてのルートのリストを取得する

ASP.NET Coreで、スタートアップで定義されたすべてのルートのリストを表示する方法はありますか?ルートを定義するためにMapRouteIRouteBuilder拡張メソッドを使用しています。

古いプロジェクトの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 = ???
    }
}
21
clhereistian

すべてのルートを取得するには、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>();
    }
}
_
20
Dr Rob Lang

この素晴らしいGitHubプロジェクトをご覧ください。

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

プロジェクトのReadme

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

AspNetCore.RouteAnalyzer

ASP.NET Coreプロジェクトのすべてのルート情報を表示します。

ピックアップしたスクリーンショット

screenshot

ASP.NET Coreプロジェクトでの使用

NuGetパッケージをインストールする

_PM> Install-Package AspNetCore.RouteAnalyzer_

Startup.csを編集する

次のように、コードservices.AddRouteAnalyzer();および必要なusingディレクティブをStartup.csに挿入します。

_using AspNetCore.RouteAnalyzer; // Add

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

ケース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?}");
    });
}
_

次に、_http://..../routes_のURLにアクセスして、ブラウザーにすべてのルート情報を表示できます。 (このURL _/routes_はMapRouteAnalyzer()によってカスタマイズできます。)

screenshot

ケース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出力パネルですべてのルート情報を表示できます。

screenshot

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

これは私の簡単な解決策で以下を出力します:

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

上記はdotnetcore 3プレビューを使用して行われましたが、dotnetcore 2.2で動作するはずです。さらに、この方法でURLを取得すると、明らかになった優れたslugifyなど、導入されているすべての規則が考慮されます Scott Hanselman's Blog

4
Andez

次のようにして、HttpActionContextからHttpRouteCollectionを取得できます。

actionContext.RequestContext.Configuration.Routes

RequestContext

HttpConfiguration

HttpRouteCollection

-質問が更新された後-

ActionExecutingContextには、ControllerTokenから継承するRouteDataプロパティがあり、これはDataTokensプロパティ(ルート値辞書)を公開します。おそらく、これまで使用していたコレクションとは異なりますが、そのコレクションへのアクセスを提供します。

actionContext.RouteData.DataTokens

DataTokens

3
pwnyexpress

これはデバッグのみに役立ちます:

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には、ルートとタイプの文字列配列が含まれます。

0
N-ate