2011-12-22 40 views
9

Tôi muốn xây dựng một RESTI Json RESTful cho ứng dụng MVC3 của tôi. Tôi cần trợ giúp xử lý nhiều động từ Http cho thao tác của một cá thể đối tượng đơn lẻ.MVC3 RESTful API Routing & Http Verb Handling

Những gì tôi đã đọc/nghiên cứu/thử

MVC thuộc tính (HttpGet, HttpPost, vv) cho phép tôi có một bộ điều khiển với nhiều hành động chia sẻ cùng tên, nhưng họ vẫn phải có phương pháp khác nhau chữ ký.

Ràng buộc tuyến đường xảy ra trong mô-đun định tuyến trước MVC khởi động và sẽ dẫn đến tôi có 4 tuyến đường rõ ràng và vẫn yêu cầu các hành động điều khiển được đặt tên riêng.

ASP.NET MVC AcceptVerbs and registering routes

Xây dựng một tùy chỉnh Http Động từ thuộc tính có thể được sử dụng để cướp động từ dùng để truy cập các hành động và sau đó vượt qua nó như là một cuộc tranh cãi như các hành động được gọi - mã sau đó sẽ xử lý các trường hợp chuyển đổi. Vấn đề với phương pháp này là một số phương pháp sẽ yêu cầu ủy quyền cần được xử lý ở cấp độ bộ lọc hành động chứ không phải bên trong chính hành động đó.

http://iwantmymvc.com/rest-service-mvc3


Yêu cầu/Mục tiêu

  1. Một tuyến đường chữ ký cho một đối tượng trường hợp duy nhất, MVC dự kiến ​​sẽ xử lý bốn Verbs Http chính: GET, POST, PUT, XÓA BỎ.

    context.MapRoute("Api-SingleItem", "items/{id}", 
        new { controller = "Items", action = "Index", id = UrlParameter.Optional } 
    ); 
    
  2. Khi URI không được thông qua một tham số Id, một hành động phải xử lý POSTPUT.

    public JsonResult Index(Item item) { return new JsonResult(); } 
    
  3. Khi một tham số Id được chuyển cho URI, một hành động đơn lẻ nên xử lý GETDELETE.

    public JsonResult Index(int id) { return new JsonResult(); } 
    

Câu hỏi

Làm thế nào tôi có thể có nhiều hơn một hành động (chia sẻ cùng tên và chữ ký phương pháp) mỗi phản ứng với một động từ http độc đáo. Ví dụ mong muốn:

[HttpGet] 
public JsonResult Index(int id) { /* _repo.GetItem(id); */} 

[HttpDelete] 
public JsonResult Index(int id) { /* _repo.DeleteItem(id); */ } 

[HttpPost] 
public JsonResult Index(Item item) { /* _repo.addItem(id); */} 

[HttpPut] 
public JsonResult Index(Item item) { /* _repo.updateItem(id); */ } 

Trả lời

10

Đối với các cuộc gọi RESTful, hành động không có ý nghĩa vì bạn chỉ muốn thay đổi bằng phương thức HTTP. Vì vậy, mẹo là sử dụng một tên hành động tĩnh, do đó các phương thức khác nhau trên bộ điều khiển chỉ khác nhau trong phương thức HTTP mà chúng chấp nhận.

Trong khi MVC framework provides a solution for specifying action names, nó có thể được thực hiện ngắn gọn hơn và tự giải thích.Chúng tôi giải quyết nó như thế này:

Thuộc tính đặc biệt được sử dụng để xác định phương pháp RESTful (điều này phù hợp với một tên hành động đặc biệt):

public sealed class RestfulActionAttribute: ActionNameSelectorAttribute { 
    internal const string RestfulActionName = "<<REST>>"; 

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { 
     return actionName == RestfulActionName; 
    } 
} 

Các bộ điều khiển sử dụng nó kết hợp với các phương thức HTTP thuộc tính:

public class MyServiceController: Controller { 
    [HttpPost] 
    [RestfulAction] 
    public ActionResult Create(MyEntity entity) { 
     return Json(...); 
    } 

    [HttpDelete] 
    [RestfulAction] 
    public ActionResult Delete(Guid id) { 
     return Json(...); 
    } 

    [HttpGet] 
    [RestfulAction] 
    public ActionResult List() { 
     return Json(...); 
    } 

    [HttpPut] 
    [RestfulAction] 
    public ActionResult Update(MyEntity entity) { 
     return Json(...); 
    } 
} 

Và để ràng buộc các bộ điều khiển đó thành công, chúng tôi sử dụng các tuyến tùy chỉnh với tên hành động tĩnh từ thuộc tính đã nói trước (cùng một lúc cũng cho phép tùy chỉnh các URL):

routes.MapRoute(controllerName, pathPrefix+controllerName+"/{id}", new { 
    controller = controllerName, 
    action = RestfulActionAttribute.RestfulActionName, 
    id = UrlParameter.Optional 
}); 

Lưu ý rằng tất cả các yêu cầu của bạn có thể dễ dàng đáp ứng với cách tiếp cận này theo như tôi có thể nói; bạn có thể có nhiều thuộc tính [HttpXxx] trên một phương thức để làm cho một phương thức chấp nhận nhiều phương thức HTTP. Ghép nối với một số ModelBinder thông minh (er) này rất mạnh mẽ.

+0

Có lẽ tôi đang thiếu một cái gì đó trong câu trả lời của bạn, nhưng nó không có ý nghĩa. trong ví dụ của bạn, mỗi hành động có tên khác và chữ ký khác. Về cơ bản, tôi cố gắng có 4 hành động riêng biệt với cùng chữ ký phương thức, mỗi câu trả lời cho một động từ http khác nhau. Họ cần phải là hành động riêng biệt bởi vì một số người trong số họ sẽ yêu cầu ủy quyền, những người khác sẽ không. Xem cập nhật. –

+0

@ one.beat.consumer: Điểm ở đây là tên của phương thức là * không liên quan *, vì tất cả chúng đều khớp với cùng tên hành động "<>" được đặt tĩnh theo tuyến đường. Vì vậy, bạn có thể có bất kỳ số phương thức nào (và các bộ điều khiển an toàn) trên một tuyến đường và bạn có thể có bất kỳ số hành động "giống hệt" nào (mặc dù chúng có tên phương thức khác nhau) tương ứng với giải pháp A của bạn hoặc bạn có thể có nhiều HTTP phương pháp cho mỗi phương pháp nếu bạn thích đó sẽ là giải pháp của bạn B, và bạn thậm chí có thể trộn các giải pháp này khi bạn thấy phù hợp. – Lucero

+0

@ one.beat.consumer: (Rời khỏi không gian trong chú thích trước) Lưu ý rằng ủy quyền được thực hiện ở cấp phương thức, không phải mức hành động, do đó điều này sẽ hoạt động tốt nếu bạn thêm thuộc tính '[Authorize]' vào một số phương thức động từ. – Lucero