2012-02-10 5 views
12

Изнутри пользовательского элемента управления mvc (2) я хочу выполнить все значения маршрута.Как проехать по всем маршрутам?

Так что, если у меня есть контроллеры, такие как:

UserController 
AccountController 

мне нужна коллекция значений, которые будут отображаться в URL, как:

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

т.е. пользователем значения, счета.

Как я могу это получить?

Я пробовал RouteTables, но не мог понять это.

+0

вы имеете в виду значения корень ..? – MethodMan

+0

У вас есть дерево/граф? – Adrian

+2

RouteTable - это действительно место для поиска ... Это говорит о том, что мы делаем это наоборот: мы используем атрибуты для рекламы маршрутов и строим таблицу маршрутов через отражение - и мы можем, конечно, запустить это отражение по своему усмотрению перечислите маршруты –

ответ

15

О, действительно хороший вопрос, чтобы я не мог заняться в течение часа. Для достижения требуемой функциональности нам нужно подключиться к источнику 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. Теперь мы можем написать некоторые логики отражения для чтения контроллеров, действий и профайлов.

    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. следует помнить: Если в маршруте вы определили параметры по умолчанию либо, то URL-адрес для тех, контроллер и действие будет пустым. например в приведенном выше примере "/ Home/Index" будет отображаться как "/"

  7. Скачать пример приложения Link To Download

    List item

+0

Woa. Огромный ответ, чувак! – Almo

+0

Да, занял около часа найти способ – Manas

+0

Удивительный! Это то, что я понял, потребуется, но не хотел его выписывать. Единственное другое решение, которое я знаю, это использовать FubuMVC. :) http://codebetter.com/jeremymiller/2010/01/04/fubumvc-diagnostics-sneak-peek/ – Ryan

Смежные вопросы