asp.net-mvc - MVC3 RESTful API 路由和 Http 动词处理

标签 asp.net-mvc asp.net-mvc-3 rest asp.net-mvc-routing

我想为我的 MVC3 应用程序构建一个 RESTful Json Api。我需要帮助来处理多个 Http 动词以操作单个对象实例。

我读过/研究过/尝试过的

MVC 属性( HttpGetHttpPost 等)允许我拥有一个具有多个共享相同名称的操作的 Controller ,但它们仍然必须具有不同的方法签名。

路由约束在 MVC 启动之前发生在路由模块中,这将导致我有 4 个显式路由,并且仍然需要单独命名的 Controller 操作。

ASP.NET MVC AcceptVerbs and registering routes

构建自定义 Http 动词属性可用于获取用于访问 Action 的动词,然后在调用 Action 时将其作为参数传递 - 然后代码将处理切换情况。这种方法的问题是某些方法需要授权,这应该在 Action 过滤器级别处理,而不是在 Action 本身内部。

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 参数时,操作必须处理 POSTPUT .
    public JsonResult Index(Item item) { return new JsonResult(); }
    
  • 将 Id 参数传递给 URI 时,应由单个操作处理 GETDELETE .
    public JsonResult Index(int id) { return new JsonResult(); }
    

  • 问题

    我怎样才能有多个 Action (共享相同的名称和方法签名)每个都响应一个唯一的 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 方法进行区分。所以诀窍是使用静态 Action 名称,这样 Controller 上的不同方法只在它们接受的HTTP方法上有所不同。

    MVC framework provides a solution for specifying action names ,它可以变得更简洁和不言自明。我们是这样解决的:

    特殊属性用于指定 RESTful 方法(这与特殊操作名称匹配):

    public sealed class RestfulActionAttribute: ActionNameSelectorAttribute {
        internal const string RestfulActionName = "<<REST>>";
    
        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
            return actionName == RestfulActionName;
        }
    }
    

    Controller 将它与 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(...);
        }
    }
    

    为了成功绑定(bind)这些 Controller ,我们使用自定义路由和来自前面提到的属性的静态操作名称(同时也允许自定义 URL):
    routes.MapRoute(controllerName, pathPrefix+controllerName+"/{id}", new {
        controller = controllerName,
        action = RestfulActionAttribute.RestfulActionName,
        id = UrlParameter.Optional
    });
    

    请注意,据我所知,这种方法可以轻松满足您的所有要求;您可以在一种方法上具有多个 [HttpXxx] 属性,以使一种方法接受多个 HTTP 方法。与一些智能(er)ModelBinder 配合使用,这是非常强大的。

    关于asp.net-mvc - MVC3 RESTful API 路由和 Http 动词处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8610451/

    相关文章:

    c# - 使用 Microsoft Fakes 模拟 HttpContextBase - UserGet 属性丢失

    c# - 使用 Fluent NHibernate 编写 MySql 数据库包装器

    java - Jersey2 样本休息服务失败

    java - spring boot Controller 可以接收纯文本吗?

    c# - asp.net mvc razor 中的可点击单选按钮文本

    c# - MVC ListView 和模型

    javascript - MVC RAZOR jQuery Ajax 不在 IE 中执行 javascript

    c# - 在 ASP.NET MVC 3 中注入(inject) IPrincipal - 我做错了什么?

    asp.net-mvc-3 - 使用 ModelMetadataProvider 和 ModelValidatorProvider 的 StructureMap 在 MVC3 中设置 DependancyResolver

    java - Spark-Java:从命令行构建文档示例