2011-09-27 15 views
7

Sử dụng bộ định vị phương pháp nằm ngoài ASP.NET MVC (3 hoặc 4DP), có cách nào để khung MVC phân biệt giữa chuỗi và hướng dẫn mà không cần phân tích tham số trong hành động điều khiển?Phân biệt các tham số chuỗi và hướng dẫn trong MVC 3

Định nghĩa trên sẽ cho URL

http://[domain]/customer/details/F325A917-04F4-4562-B104-AF193C41FA78

để thực hiện phương pháp

public ActionResult Details(Guid guid) 

, và

http://[domain]/customer/details/bill-gates

để thực hiện

public ActionResult Details(string id) 

phương pháp.

Với không có thay đổi, rõ ràng là các phương pháp là mơ hồ, như sau:

public ActionResult Details(Guid id) 
{ 
    var model = Context.GetData(id); 
    return View(model); 
} 

public ActionResult Details(string id) 
{ 
    var model = Context.GetData(id); 
    return View(model); 
} 

dẫn đến lỗi:

The current request for action 'Details' on controller type 'DataController' is ambiguous between the following action methods: 
System.Web.Mvc.ActionResult Details(System.Guid) on type Example.Web.Controllers.DataController 
System.Web.Mvc.ActionResult Details(System.String) on type Example.Web.Controllers.DataController 

tôi cố gắng sử dụng một hạn chế tùy chỉnh (dựa trên How can I create a route constraint of type System.Guid?) để thử và đẩy thông qua định tuyến:

routes.MapRoute(
    "Guid", 
    "{controller}/{action}/{guid}", 
    new { controller = "Home", action = "Index" }, 
    new { guid = new GuidConstraint() } 
); 

routes.MapRoute(
    "Default", // Route name 
    "{controller}/{action}/{id}", 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
); 

Và chuyển chữ ký hành động để:

public ActionResult Details(Guid guid) 
{ 
    var model = Context.GetData(guid); 
    return View(model); 
} 

public ActionResult Details(string id) 
{ 
    var model = Context.GetData(id); 
    return View(model); 
} 

Ràng buộc thực hiện và vượt qua, do đó lập luận được gửi đến một hành động, nhưng dường như vẫn còn là một chuỗi, và do đó không rõ ràng với hai chữ ký phương pháp. Tôi hy vọng rằng có một cái gì đó trong cách các phương pháp hành động được đặt mà gây ra sự mơ hồ, và do đó có thể được ghi đè bằng cách cắm vào một mô-đun tùy chỉnh để xác định vị trí phương pháp. Kết quả tương tự có thể đạt được bằng cách phân tích cú pháp tham số chuỗi, nhưng sẽ rất tốt nếu ngắn gọn để tránh logic đó trong hành động (chưa kể đến hy vọng tái sử dụng một ngày nào đó sau này).

+0

bạn nói đúng, phương pháp hành động định vị là không biết gì về các hạn chế đường. Nếu bạn loại bỏ phương thức hành động chuỗi, phương thức hành động guid có được chọn không? – bzlm

+1

MVC không hỗ trợ quá tải phương thức chỉ dựa trên chữ ký - giải pháp đơn giản nhất có thể đơn giản là có hai phương thức hành động được đặt tên duy nhất, một chi tiết của GUID (Chi tiết) và khác. ?). – Tommy

+0

@bzlm - Đúng, loại bỏ chuỗi hành động sẽ chọn Hướng dẫn (giả sử nó vượt qua ràng buộc HOẶC có thể được phân tích cú pháp thành một Hướng dẫn). – falquan

Trả lời

11

Trước tiên, bạn phải disambigute phương pháp của bạn bằng cách cho họ hai tên gọi khác nhau:

public ActionResult DetailsGuid(Guid guid) 
{ 
    var model = Context.GetData(guid); 
    return View(model); 
} 

public ActionResult DetailsString(string id) 
{ 
    var model = Context.GetData(id); 
    return View(model); 
} 

Tiếp theo, bạn cần một handler đường tùy chỉnh để kiểm tra theo yêu cầu, và thay đổi tên phương pháp phù hợp:

using System.Web.Mvc; 
using System.Web.Routing; 

public class MyRouteHandler : IRouteHandler 
{ 
    public IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     var routeData = requestContext.RouteData; 
     var stringValue = routeData.Values["id"].ToString(); 
     Guid guidValue; 
     var action = routeData.Values["action"]; 
     if (Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty); 
      routeData.Values["action"] = action + "Guid"; 

     else 
      routeData.Values["action"] = action + "String"; 

     var handler = new MvcHandler(requestContext); 
     return handler; 
    } 
} 

Cuối cùng, thêm một tuyến đường Details ở phía trên cùng của tuyến đường của bạn, như sau:

routes.Add("Details", 
    new Route("{controller}/Details/{id}", 
     new RouteValueDictionary( 
      new { controller = "Home", action = "Details" }), 
      new MyRouteHandler() 
     ) 
    ); 
); 

Khi có yêu cầu để biết chi tiết, tuyến đường Details sẽ sử dụng trình xử lý tuyến đường tùy chỉnh của bạn để kiểm tra mã thông báo id. Trình xử lý tuyến đường thêm vào tên hành động dựa trên biểu mẫu mã thông báo id, do đó yêu cầu sẽ được chuyển đến hành động thích hợp.

8

Ý kiến ​​của tôi là sử dụng công cụ chọn phương thức hành động dễ sử dụng hơn và ít mã hóa hơn.

public class GuidMethodSelectorAttribute : ActionMethodSelectorAttribute 
{ 
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) 
    { 
     var idStr = controllerContext.RouteData.Values["id"]; 
     if (idStr == null) 
      return false; 
     Guid a; 
     var result = Guid.TryParse(idStr.ToString(), out a); 
     return result; 
    } 
} 

Công cụ chọn này kiểm tra yêu cầu tham số ID. Nếu đó là guid, nó trả về true. Vì vậy, để sử dụng nó:

public class HomeController : Controller 
{ 
    [GuidMethodSelector] 
    public ActionResult Index(Guid id) 
    { 
     return View(); 
    } 
    public ActionResult Index(string id) 
    { 
     return View(); 
    } 
} 
+0

Bạn có thể sử dụng lớp GuidRouteConstraint sẵn có hơn là cần thêm mã tùy chỉnh. Tôi đánh giá cao rằng đây có thể không phải là trường hợp tại thời điểm viết bài. –

5

Nếu bạn vẫn đang đăng ký các tuyến đường theo cách này thì() lớp GuidRouteConstraint đã được bổ sung trong phiên bản mới của MVC và nên được sử dụng thay vì một thực hiện tùy chỉnh:

public override void RegisterArea(AreaRegistrationContext context) 
{ 
    context.MapRoute(
     "Guid", 
     "{controller}/{action}/{guid}", 
     new { controller = "Home", action = "Index" }, 
     new { guid = new GuidRouteConstraint() } 
    ); 
} 

Sau đó, bạn chỉ có thể tạo ra kết quả hành động của bạn như:

public class HomeController : Controller { 
    public ActionResult Index(Guid guid) { 
    } 
} 
+2

Làm việc một điều trị, chỉ cần đảm bảo rằng bạn sử dụng quyền 'sử dụng' tuyên bố - bạn có thể muốn' bằng cách sử dụng System.Web.Mvc.Routing.Constraints; 'và không System.Web.Http.Routing.Constraints –