2012-02-10 20 views
12

Desde dentro de un control de usuario mvc (2), quiero recorrer todos los valores de la ruta.¿Cómo puedo recorrer todas las rutas?

lo que si tengo los controladores como:

UserController 
AccountController 

necesito una colección de los valores que van a aparecer en la url como:

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

es decir, el usuario los valores, cuenta.

¿Cómo puedo obtener esto?

Probé RouteTables pero no pude encontrarlo.

+0

Qué quiere decir los valores de raíz ..? – MethodMan

+0

¿tiene algún tipo de árbol/gráfico? – Adrian

+2

El RouteTable es de hecho el lugar para mirar ... Dicho esto, lo hacemos al revés: usamos atributos para anunciar rutas, y construimos la tabla de rutas a través de la reflexión, y podemos, por supuesto, ejecutar esa reflexión a voluntad para enumere las rutas –

Respuesta

15

Oh, realmente una buena pregunta para mantenerme ocupado durante una hora. Para lograr la funcionalidad requerida, necesitamos engancharnos a la fuente MVC y un poco de reflexiones.

  1. Por nombres de ruta por defecto no están disponibles, por lo que necesitamos para escribir una extensión colección de rutas para salvar Nombre de ruta en fichas 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. modifique la llamada global.asax MapRoute para invocar la extensión anterior

    routes.MapRouteWithName(
          "Default", // Route name 
          "{controller}/{action}/{id}", // URL with parameters 
          new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
         ); 
    
  3. Modificado el MVC PathHelper un poco. (Incluir este helper en el proyecto)

    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. Agregue algunos métodos de ayuda en el controlador

    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. Ahora podemos escribir algunas lógicas de reflexión para leer controladores, acciones y nombres de rutas.

    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. Puntos para recordar: Si en la ruta que haya definido los parámetros por defecto, entonces url para aquellos controlador y la acción estará vacía. p.ej. en el ejemplo anterior "/ home/Índice" se mostrará como

  7. Descargar la aplicación "/" muestra Link To Download

    List item

+0

Woa. Enorme respuesta, amigo! – Almo

+0

Sí, tomó alrededor de una hora encontrar la manera – Manas

+0

¡Impresionante! Esto es lo que pensé que sería necesario pero no quería escribirlo. La única otra solución que conozco es usar FubuMVC. :) http://codebetter.com/jeremymiller/2010/01/04/fubumvc-diagnostics-sneak-peek/ – Ryan

Cuestiones relacionadas