2012-05-02 20 views
5

私は以下のように設定したルートがあります。MVCルーティング制約

 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/HomeDashboard()に私を取る持っているために燃える欲望を持っているが、これは、(404)は動作しません。私はfriendlyAccountNameコントローラを探しているという理由があると思います。

私のコントローラのいずれかの後にアカウントを指定する必要がある場合は、すべてのコントローラがダウンしても、対応するコントローラが見つからない場合は、次のルートに進む方法がありますか?リフレクションを使用し、コントローラのリストを変更するたびに制約を維持しないようにする方法はありますか?

EDIT

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

答えて

6

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

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

、私はあなたが最初の2つのルートのパラメータはオプションであり、デフォルト値が同一であることから、完全に最初の二つの経路を削除し、ちょうど最後にこだわることができる必要がありますように感じます。

UPDATE

{accountFriendlyId}は、あなたが他のもののカップルを行うことができ、有効なコントローラの操作名可能性がありますので:ルートの最後に

  1. 移動{accountFriendlyId}、代わりの時始まり。これは、リソース内の最も広範なリソースから特定の詳細までのより自然なURLスタイルに従います。
  2. route constraintsを使用してください。理論的にはリフレクションを使ってcustom constraintのコントローラー名にマッチする正規表現を生成するか、手動で書き出すことができます。このような何か:

context.MapRoute(

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

)。

+0

、 'のArあなたは親愛なるidパラメータを埋めるだろうし、デフォルトのコントローラとアクションに私を送り、 'Area/friendly/Controller/Action'は失敗するでしょう。 –

+0

ああ、申し訳ありません、' {accountFriendlyId} '有効な操作名になります。私は答えを更新します。 –

+0

これらの文字列の解析方法は何ですか?私はリテラルでインラインで行うことができないという手がかりを持っていませんでした(特にこれを使用しないでしょう)。 –

2

これは、URLのスペースの問題です。 accountFriendlyIdとcampaignFriendlyIdとコントローラを区別するにはどうすればよいですか?簡単な方法はURLのさまざまなセグメントにそれらを配置することですが、ルートでコントローラを2番目、3番目または4番目のセグメントにすることができます。あなたは明確にする制約を使用し、このようにそれらを注文する必要があります。

context.MapRoute(null, "Area/{controller}/{action}", 
    new { controller = "Home", action = "Dashboard" }, 
    new { controller = "Foo|Bar" }); 

context.MapRoute(null, "Area/{accountFriendlyId}/{controller}/{action}", 
    new { controller = "Home", action = "Dashboard" }, 
    new { controller = "Foo|Bar" }); 

context.MapRoute(null, "Area/{accountFriendlyId}/{campaignFriendlyId}/{controller}/{action}", 
    new { controller = "Home", action = "Dashboard" }); 

コントローラは、次の一致するルートを試し見つからない場合は、提案のアイデア、それはそのように動作しません、一度ルートそうであれば、UrlRoutingModuleを修正してその作業を試みる必要があります。最終的に

+0

そして、このエリアのコントローラ名の文字列を取得するために反射をフィルタリングするために限り?私は 'IController'とコントローラの間に空の' IAreaController'を置くべきでしょうか? –

+0

@ nik.shornikov私はあなたが話していることをよく分かりません。制約をdinamically構築したいのですか? –

+0

yes - 'Assembly.GetCallingAssembly()。GetTypes()。ここで(type => type.IsSubclassOf(typeof(IController)))' –

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