2012-02-10 5 views
12

mvc(2)ユーザコントロールの中から、すべてのルート値をループしたいと思います。すなわち、値がユーザーどのようにすべてのルートをループすることができますか?

/user/... 
/account/... 

、アカウント:

UserController 
AccountController 

私のようなURLに表示される値のコレクションを必要とする:

だから私のようなコントローラーを持っている場合。

どうすれば入手できますか?

私はRouteTableを試しましたが、理解できませんでした。

+0

は、あなたがルート値を意味していますか..? – MethodMan

+0

あなたは木/種類のグラフを持っていますか? – Adrian

+2

RouteTableは確かに見る場所です...つまり、我々は逆のやり方をしています:経路を宣伝するために属性を使用し、反射によって経路表を構築します。 –

答えて

15

ああ、本当に私の自己を1時間ビジー状態に保つ良い質問。 必要な機能を実現するには、MVCソースと少しの反射にフックする必要があります。

  1. デフォルトではルート名は使用できませんので、RouteDataトークンにルート名を保存するためにルートコレクション拡張を作成する必要があります。

    public static Route MapRouteWithName(this RouteCollection routes,string name, string url, object defaults=null, object constraints=null) 
    { 
    
    Route route = routes.MapRoute(name, url, defaults, constraints); 
    route.DataTokens = new RouteValueDictionary(); 
    route.DataTokens.Add("RouteName", name); 
    return route; 
    } 
    
  2. のGlobal.asax maprouteコールを変更し、以前の拡張を呼び出すため

    routes.MapRouteWithName(
          "Default", // Route name 
          "{controller}/{action}/{id}", // URL with parameters 
          new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
         ); 
    
  3. MVC PathHelperを少し変更しました。(このプロジェクトでは、このヘルパーを含める)

    using System; 
    using System.Collections.Specialized; 
    using System.Web; 
    
    public static class PathHelpers 
    { 
    
    // this method can accept an app-relative path or an absolute path for contentPath 
    public static string GenerateClientUrl(HttpContextBase httpContext, string contentPath) 
    { 
        if (String.IsNullOrEmpty(contentPath)) 
        { 
         return contentPath; 
        } 
    
        // many of the methods we call internally can't handle query strings properly, so just strip it out for 
        // the time being 
        string query; 
        contentPath = StripQuery(contentPath, out query); 
    
        return GenerateClientUrlInternal(httpContext, contentPath) + query; 
    } 
    
    private static string GenerateClientUrlInternal(HttpContextBase httpContext, string contentPath) 
    { 
        if (String.IsNullOrEmpty(contentPath)) 
        { 
         return contentPath; 
        } 
    
        // can't call VirtualPathUtility.IsAppRelative since it throws on some inputs 
        bool isAppRelative = contentPath[0] == '~'; 
        if (isAppRelative) 
        { 
         string absoluteContentPath = VirtualPathUtility.ToAbsolute(contentPath, httpContext.Request.ApplicationPath); 
         string modifiedAbsoluteContentPath = httpContext.Response.ApplyAppPathModifier(absoluteContentPath); 
         return GenerateClientUrlInternal(httpContext, modifiedAbsoluteContentPath); 
        } 
    
        string relativeUrlToDestination = MakeRelative(httpContext.Request.Path, contentPath); 
        string absoluteUrlToDestination = MakeAbsolute(httpContext.Request.RawUrl, relativeUrlToDestination); 
        return absoluteUrlToDestination; 
    } 
    
    public static string MakeAbsolute(string basePath, string relativePath) 
    { 
        // The Combine() method can't handle query strings on the base path, so we trim it off. 
        string query; 
        basePath = StripQuery(basePath, out query); 
        return VirtualPathUtility.Combine(basePath, relativePath); 
    } 
    
    public static string MakeRelative(string fromPath, string toPath) 
    { 
        string relativeUrl = VirtualPathUtility.MakeRelative(fromPath, toPath); 
        if (String.IsNullOrEmpty(relativeUrl) || relativeUrl[0] == '?') 
        { 
         // Sometimes VirtualPathUtility.MakeRelative() will return an empty string when it meant to return '.', 
         // but links to {empty string} are browser dependent. We replace it with an explicit path to force 
         // consistency across browsers. 
         relativeUrl = "./" + relativeUrl; 
        } 
        return relativeUrl; 
    } 
    
    private static string StripQuery(string path, out string query) 
    { 
        int queryIndex = path.IndexOf('?'); 
        if (queryIndex >= 0) 
        { 
         query = path.Substring(queryIndex); 
         return path.Substring(0, queryIndex); 
        } 
        else 
        { 
         query = null; 
         return path; 
        } 
    } 
    
    } 
    
  4. コントローラーに少数のヘルパーメソッドを追加する

    public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteCollection routeCollection, RequestContext requestContext) 
    { 
    
        RouteValueDictionary mergedRouteValues = MergeRouteValues(actionName, controllerName); 
    
        VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues); 
        if (vpd == null) 
        { 
         return null; 
        } 
    
        string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath); 
        return modifiedUrl; 
    } 
    public static RouteValueDictionary MergeRouteValues(string actionName, string controllerName) 
    { 
        // Create a new dictionary containing implicit and auto-generated values 
        RouteValueDictionary mergedRouteValues = new RouteValueDictionary(); 
    
        // Merge explicit parameters when not null 
        if (actionName != null) 
        { 
         mergedRouteValues["action"] = actionName; 
        } 
    
        if (controllerName != null) 
        { 
         mergedRouteValues["controller"] = controllerName; 
        } 
    
        return mergedRouteValues; 
    } 
    
  5. コントローラ、アクション、およびルーテイン名を読み取るためのリフレクションロジックを書くことができます。ルートには、任意のデフォルトパラメータを定義している場合、それらのコントローラとアクションのURLは空になります:覚えて

    Dictionary<string, List<string>> controllersAndActions = new Dictionary<string, List<string>>(); 
    
    // Get all the controllers 
    var controllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Controller).IsAssignableFrom(t)); 
    
    foreach (var controller in controllers) 
    { 
        List<string> actions = new List<string>(); 
        //Get all methods without HttpPost and with return type action result 
        var methods = controller.GetMethods().Where(m => typeof(ActionResult).IsAssignableFrom(m.ReturnType)).Where(a=>!a.GetCustomAttributes(typeof(HttpPostAttribute),true).Any()); 
        methods.ToList().ForEach(a => { 
         actions.Add(a.Name); 
        }); 
        var controllerName = controller.Name; 
        if (controllerName.EndsWith("Controller")) 
        { 
         var nameLength = controllerName.Length - "Controller".Length; 
         controllerName = controllerName.Substring(0, nameLength); 
        } 
        controllersAndActions.Add(controllerName, actions); 
    } 
    List<string> allowedRoutes = new List<string>(); 
    
    var routeNames = RouteTable.Routes.Where(o=>o.GetRouteData(this.HttpContext)!=null).Select(r=>r.GetRouteData(this.HttpContext).DataTokens["RouteName"].ToString()); 
    foreach (var cName in controllersAndActions) 
    { 
        foreach (var aName in cName.Value) 
        { 
         foreach (var item in routeNames) 
         { 
          allowedRoutes.Add(GenerateUrl(item, aName, cName.Key, RouteTable.Routes, this.Request.RequestContext)); 
         } 
        } 
    
    } 
    
  6. ポイント。例えば上記の例では "/ホーム/インデックス" "/"

  7. ダウンロードサンプルアプリケーションとして表示されますLink To Download

    List item

+0

Woa。巨大な答え、おい! – Almo

+0

はい、方法を見つける約1時間かかりました – Manas

+0

驚くばかり!これは私が必要と思ったものだが、それを書きたくない。私が知っている唯一の他の解決策は、FubuMVCを使用することです。 :) http://codebetter.com/jeremymiller/2010/01/04/fubumvc-diagnostics-sneak-peek/ – Ryan

関連する問題