Asp.net-Mvc
MVC3 RESTful API 路由和 Http 動詞處理
我想為我的 MVC3 應用程序建構一個 RESTful Json Api。我需要幫助來處理多個 Http 動詞以操作單個對象實例。
我讀過/研究過/嘗試過的東西
MVC 屬性(
HttpGet,HttpPost等)允許我擁有一個具有多個共享相同名稱的操作的控制器,但它們仍然必須具有不同的方法簽名。路由約束在MVC 啟動之前發生在路由模組中,這將導致我有 4 個顯式路由,並且仍然需要單獨命名的控制器操作。
建構自定義 Http 動詞屬性可用於獲取用於訪問動作的動詞,然後在呼叫動作時將其作為參數傳遞 - 然後程式碼將處理切換情況。這種方法的問題是某些方法需要授權,這應該在動作過濾器級別處理,而不是在動作本身內部。
http://iwantmymvc.com/rest-service-mvc3
要求/目標
- 單個實例對象的一個路由簽名,MVC 預計處理四個主要的 Http 動詞:GET、POST、PUT、DELETE。
context.MapRoute("Api-SingleItem", "items/{id}", new { controller = "Items", action = "Index", id = UrlParameter.Optional } );
- 當 URI 未傳遞 Id 參數時,操作必須處理
POST和PUT。public JsonResult Index(Item item) { return new JsonResult(); }
- 當將 Id 參數傳遞給 URI 時,單個操作應處理
GET和DELETE。public JsonResult Index(int id) { return new JsonResult(); }問題
我怎樣才能有多個動作(共享相同的名稱和方法簽名)每個都響應一個唯一的 http 動詞。期望的例子:
[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); */ }
對於 RESTful 呼叫,該操作沒有任何意義,因為您只想通過 HTTP 方法進行區分。所以訣竅是使用靜態動作名稱,這樣控制器上的不同方法只在它們接受的HTTP方法上有所不同。
雖然MVC 框架提供了指定動作名稱的解決方案,但它可以更加簡潔和自我解釋。我們是這樣解決的:
特殊屬性用於指定 RESTful 方法(這與特殊操作名稱匹配):
public sealed class RestfulActionAttribute: ActionNameSelectorAttribute { internal const string RestfulActionName = "<<REST>>"; public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { return actionName == RestfulActionName; } }控制器將它與 HTTP 方法屬性結合使用:
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(...); } }為了成功綁定這些控制器,我們使用自定義路由和來自前面提到的屬性的靜態操作名稱(同時也允許自定義 URL):
routes.MapRoute(controllerName, pathPrefix+controllerName+"/{id}", new { controller = controllerName, action = RestfulActionAttribute.RestfulActionName, id = UrlParameter.Optional });請注意,據我所知,這種方法可以輕鬆滿足您的所有要求;你可以有多個
$$ HttpXxx $$一種方法的屬性,使一種方法接受多個 HTTP 方法。與一些智能(er)ModelBinder 配合使用,這是非常強大的。