5

私は次のようにルートを設定しています:

        context.MapRoute(
        name: "Area",
        url: "Area/{controller}/{action}",
        defaults: new
        {
            controller = "Home",
            action = "Dashboard"
        }
        );

        context.MapRoute(
        name: "AccountArea",
        url: "Area/{accountFriendlyId}/{controller}/{action}",
        defaults: new
        {
            controller = "Home",
            action = "Dashboard",
            accountFriendlyId = RouteParameter.Optional
        }
        );

        context.MapRoute(
        name: "AccountCampaignArea",
        url: "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}",
        defaults: new
                {
                    controller = "Home", 
                    action = "Dashboard",
                    accountFriendlyId = RouteParameter.Optional,
                    campaignFriendlyId = RouteParameter.Optional
                }
        );

Area/friendlyAccountName/Homeそして、私は私を連れて行きたいという燃えるような願望を持っていますDashboard()が、これはうまくいきません(404)。その理由は、friendlyAccountNameコントローラーを探しに行くからだと思います。

コントローラーの1つがクラッシュした後にアカウントに名前を付けることを選択した場合、文字列が対応するコントローラーを見つけられなかった場合に次のルートにフォールスルーする方法はありますか?コントローラーのリストを変更するたびにリフレクションを使用して制約を維持しないようにする方法はありますか?

編集

リフレクションを使用しない方法、または少なくともこの領域への派生型検索を含む方法を知っていますか?2番目のルートパラメーターがコントローラー名と一致するときにそのオーバーヘッドが2回発生するという考えは好きではありません(コントローラーを構築するときに制約を渡してから再度検索します)。コントローラーを構築し、バックアップして次のルートにフォールスルーする時点で例外をキャッチする方法があればいいのにと思います。

4

3 に答える 3

7

なぜ最初のルートが必要なのですか?がオプションの場合{accountFriendlyId}は、省略して、最初に登録したルートと同じデフォルトのルートを取得できるはずです。

そうAccountAreaすれば、最初に名前付きルートで一致し、これが必要です。次に、{accountFriendlyId}が指定されていない場合は、エリアの後の最初のトークンをコントローラーとして扱います。

実際、最初の 2 つのルートを完全に削除して、最後のルートのみを使用できるようにすべきだと思います。最初の 2 つのルート パラメータはオプションであり、デフォルトは同一であるためです。

アップデート

は有効なコントローラー操作名である可能性があるため{accountFriendlyId}、他にもいくつかのことができます。

  1. {accountFriendlyId}ルートの最初ではなく、最後に移動します。これは、最も広範なリソースからリソース内の特定の詳細まで、より自然な URL スタイルに従います。
  2. ルート制約を使用します。理論的には、リフレクションを使用して正規表現を生成し、カスタム制約のコントローラー名に一致させるか、手動で書き出すことができます。このようなもの:

context.MapRoute(

    name: "Area",
    url: "Area/{controller}/{action}",
    defaults: new
    {
        controller = "Home",
        action = "Dashboard",
        new { controller = @"(Account|Profile|Maintenance)" }
    }

);

于 2012-05-02T18:37:00.013 に答える
6

最終的に、私が望んでいたことを容易にするために (これは、アプリが任意の文字列とコントローラー名を動的に区別することに依存していました)、次のようなルートを設定しました。

public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
        name: "AccountCampaignArea",
        url: "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}",
        defaults: new
            {
                controller = "Home",
                action = "Dashboard",
                accountFriendlyId = RouteParameter.Optional,
                campaignFriendlyId = RouteParameter.Optional,
                id = UrlParameter.Optional
            },
        constraints: new { accountFriendlyId = new ControllerNameConstraint(), campaignFriendlyId = new ControllerNameConstraint() }
        );

        context.MapRoute(
            name: "AccountArea",
            url: "Area/{accountFriendlyId}/{controller}/{action}",
            defaults: new
                {
                    controller = "Home",
                    action = "Dashboard",
                    accountFriendlyId = RouteParameter.Optional,
                    id = UrlParameter.Optional
                },
            constraints: new { accountFriendlyId = new ControllerNameConstraint() }
            );

        context.MapRoute(
        name: "Area",
        url: "Area/{controller}/{action}",
        defaults: new
            {
                controller = "Home",
                action = "Dashboard"
            }
        );
    }

そして、次のような制約を設定します (制約は と呼ばれることもありますNotControllerNameContraint):

public class ControllerNameConstraint : IRouteConstraint
{
    private static List<Type> GetSubClasses<T>()
    {
        return Assembly.GetCallingAssembly().GetTypes().Where(
            type => type.IsSubclassOf(typeof(T))).ToList();
    }

    public List<string> GetControllerNames()
    {
        List<string> controllerNames = new List<string>();
        GetSubClasses<Controller>().ForEach(
            type => controllerNames.Add(type.Name));
        return controllerNames;
    }
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (values.ContainsKey(parameterName))
        {
            string stringValue = values[parameterName] as string;
            return !GetControllerNames().Contains(stringValue + "Controller");
        }

        return true;
    }
}

クレジット: https://stackoverflow.com/a/1152735/938472

于 2012-05-03T20:36:44.077 に答える