2012-02-10 30 views
12

Từ bên trong một điều khiển người dùng mvc (2), tôi muốn lặp qua tất cả các giá trị tuyến đường.Làm thế nào tôi có thể lặp qua tất cả các tuyến đường?

Vì vậy, nếu tôi có điều khiển như:

UserController 
AccountController 

tôi cần một bộ sưu tập của các giá trị đó sẽ xuất hiện trong url như:

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

ví dụ: người dùng giá trị, tài khoản.

Làm cách nào để nhận được thông báo này?

Tôi đã thử RouteTables nhưng không thể tìm ra.

+0

làm bạn có nghĩa là giá trị gốc ..? – MethodMan

+0

bạn có cây/đồ thị các loại? – Adrian

+2

RouteTable thực sự là nơi để xem ... Điều đó nói rằng, chúng ta thực hiện theo cách khác: chúng ta sử dụng các thuộc tính để quảng cáo tuyến đường và xây dựng bảng định tuyến thông qua sự phản chiếu - và dĩ nhiên chúng ta có thể chạy phản chiếu đó danh sách các tuyến đường –

Trả lời

15

Ồ, thực sự là một câu hỏi hay để tôi tự bận rộn trong một giờ. Để đạt được các chức năng cần thiết, chúng ta cần phải móc vào nguồn MVC và một chút phản xạ.

  1. Theo mặc định Tên tuyến không khả dụng, vì vậy chúng tôi cần viết tiện ích mở rộng Tập hợp tuyến đường để lưu Tên tuyến đường trong mã thông báo 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. Sửa đổi các cuộc gọi global.asax maproute để gọi mở rộng trước

    routes.MapRouteWithName(
          "Default", // Route name 
          "{controller}/{action}/{id}", // URL with parameters 
          new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
         ); 
    
  3. Modified các PathHelper MVC một chút. (Bao gồm helper này trong dự án)

    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. Thêm vài phương pháp trợ giúp trong bộ điều khiển

    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. Bây giờ chúng ta có thể viết một số phản ánh logic để đọc bộ điều khiển, hành động và tên định tuyến.

    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. Điểm cần nhớ: Nếu trong tuyến đường bạn đã xác định bất kỳ thông số mặc định nào, thì url cho bộ điều khiển và hành động đó sẽ trống. ví dụ. trong ví dụ trên "/ Home/Index" sẽ được hiển thị là "/"

  7. Tải ứng dụng mẫu Link To Download

    List item

+0

Woa. Câu trả lời lớn, dude! – Almo

+0

Có, mất khoảng một giờ tìm một cách – Manas

+0

Tuyệt vời! Đây là những gì tôi figured sẽ được yêu cầu nhưng không muốn viết nó ra. Giải pháp duy nhất mà tôi biết là sử dụng FubuMVC. :) http://codebetter.com/jeremymiller/2010/01/04/fubumvc-diagnostics-sneak-peek/ – Ryan

Các vấn đề liên quan