2012-05-02 26 views
5

Tôi có tuyến đường thiết lập như:MVC Routing Hạn chế trên điều khiển tên

 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 
       } 
     ); 

Và tôi có một khát vọng cháy bỏng để có Area/friendlyAccountName/Home đưa tôi đến Dashboard() nhưng điều này không làm việc (404). Tôi nghĩ lý do là chúng ta đi tìm một bộ điều khiển friendlyAccountName.

Thoải mái với kiến ​​thức rằng nếu tôi nên chọn đặt tên cho tài khoản sau khi một trong các bộ điều khiển của tôi bị hỏng, có cách nào đi qua tuyến kế tiếp trong trường hợp chuỗi không tìm được bộ điều khiển tương ứng không? Có cách nào để sử dụng phản ánh và tránh duy trì một ràng buộc mỗi khi tôi sửa đổi danh sách các bộ điều khiển của tôi?

EDIT

Bạn có biết một cách mà không sử dụng phản ánh hoặc ít nhất là có chứa các tìm kiếm loại có nguồn gốc đến lĩnh vực này? Tôi không thích ý tưởng phát sinh phí đó hai lần khi tham số tuyến thứ hai khớp với tên bộ điều khiển (ràng buộc vượt qua rồi tìm kiếm lại khi xây dựng bộ điều khiển). Tôi muốn có một cách để bắt ngoại lệ tại thời điểm xây dựng một bộ điều khiển và sau đó sao lưu và đi qua các tuyến đường tiếp theo.

Trả lời

6

Tại sao bạn cần tuyến đường đầu tiên? Nếu {accountFriendlyId} là tùy chọn, bạn sẽ có thể bỏ qua và nhận được cùng một tuyến đường mặc định là tuyến đường được đăng ký đầu tiên của bạn.

Bằng cách đó, nó sẽ khớp trên tuyến đường được đặt trước AccountArea, đó là những gì bạn muốn và sau đó nếu {accountFriendlyId} không được chỉ định, nó sẽ xử lý mã thông báo đầu tiên sau khu vực làm bộ điều khiển. Trong thực tế, tôi cảm thấy như bạn có thể loại bỏ hoàn toàn hai tuyến đầu tiên và chỉ dính vào hai tuyến đầu tiên, vì hai thông số tuyến đầu tiên là tùy chọn và mặc định là giống hệt nhau.

CẬP NHẬT

Kể từ khi {accountFriendlyId} có thể là một tên hoạt động điều khiển hợp lệ, bạn có thể làm một vài điều khác:

  1. Move {accountFriendlyId} đến cuối con đường, thay vì ở bắt đầu. Điều này tuân theo phong cách URL tự nhiên hơn của tài nguyên rộng nhất đến chi tiết cụ thể trong tài nguyên.
  2. Sử dụng route constraints. Bạn về mặt lý thuyết có thể sử dụng sự phản chiếu để tạo ra các regex để phù hợp với tên bộ điều khiển trong một custom constraint, hoặc bạn chỉ có thể viết chúng ra bằng tay. Một cái gì đó như thế này:

context.MapRoute (

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

);

+0

Nếu không có hai tuyến đường đầu tiên, 'Ar ea/Controller/Action' sẽ điền vào các thông số id thân thiện và gửi cho tôi vào bộ điều khiển và hành động mặc định và 'Area/friendly/Controller/Action' sẽ thất bại –

+0

Ah, xin lỗi, tôi không bắt được' {accountFriendlyId} ' sẽ là tên hoạt động hợp lệ. Tôi sẽ cập nhật câu trả lời. –

+0

Quy ước về cách các chuỗi này được phân tích cú pháp là gì? Tôi đã không có đầu mối bạn có thể làm điều đó nội tuyến với một chữ (tôi có lẽ sẽ không sử dụng chúng cho điều này đặc biệt). –

2

Đây là vấn đề về không gian URL. Làm thế nào để bạn phân biệt giữa một accountFriendlyId, một campaignFriendlyId và một bộ điều khiển? Cách dễ dàng là đặt chúng vào các phân đoạn khác nhau của URL, nhưng với tuyến đường của bạn, bộ điều khiển có thể là phân đoạn thứ hai, thứ ba hoặc thứ tư.Bạn phải sử dụng hạn chế để disambiguate, và ra lệnh cho họ như thế này:

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" }); 

Ý tưởng bạn đề nghị, nếu một bộ điều khiển không được tìm thấy sau đó thử các tuyến đường phù hợp tiếp theo, nó không hoạt động theo cách đó, khi tuyến đường một phù hợp với nó, bạn sẽ phải sửa đổi các UrlRoutingModule để cố gắng làm cho công việc đó.

+0

Và như xa như lọc phản xạ để có được các chuỗi tên bộ điều khiển trong khu vực này chỉ? Tôi có nên gắn một 'IAreaController' trống giữa' IController' và bộ điều khiển trong vùng này không? –

+0

@ nik.shornikov Tôi không chắc chắn những gì bạn đang nói về, bạn muốn xây dựng các ràng buộc dinamically? –

+0

có - 'Assembly.GetCallingAssembly() GetTypes(). Ở đâu (type => type.IsSubclassOf (typeof (IController)))' –

6

Cuối cùng, để tạo điều kiện những gì tôi muốn (mà phụ thuộc vào việc có các ứng dụng tự động phân biệt giữa chuỗi tùy ý và tên controller) tôi thiết lập các tuyến đường như thế này:

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" 
      } 
     ); 
    } 

Và thiết lập một hạn chế như thế này (hạn chế cũng có thể được gọi 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; 
    } 
} 

Điểm Uy Tín: https://stackoverflow.com/a/1152735/938472

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