MVC3 RESTful API Routing & Http Verb Handling

je veux construire une Api RESTful Json pour mon application MVC3. J'ai besoin d'aide pour gérer plusieurs verbes Http pour la manipulation d'une instance d'un seul objet.

Ce que j'ai lu/étudié/essayé

attributs MVC (HttpGet,HttpPost, etc.) permettez-moi d'avoir un controller avec plusieurs actions partageant le même nom, mais elles doivent quand même avoir des signatures de méthode différentes.

les contraintes de Route se produisent dans le module de routage avant MVC entre en jeu et me permettrait d'avoir 4 routes explicites, tout en exigeant des actions de controller individuellement nommées.

ASP.NET MVC AcceptVerbs and registring routes

construire un attribut de verbe Http personnalisé pourrait être utilisé pour enlever le verbe utilisé pour accéder à l'action et le passer ensuite comme un argument pendant que l'action est invoquée - le code traiterait alors les cas de switch. Le problème avec cette approche est certaines méthodes exiger une autorisation qui devrait être traitée au niveau du filtre d'action, et non à l'intérieur de l'action elle-même.

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


Exigences / Objectifs

  1. une signature de route pour un seul objet d'instance, MVC est censé gérer les quatre principaux verbes Http: GET, POST, PUT, DELETE.

    context.MapRoute("Api-SingleItem", "items/{id}", 
        new { controller = "Items", action = "Index", id = UrlParameter.Optional }
    );
    
  2. quand L'URI n'est pas passé un Id paramètre, une action doit gérer POST et PUT.

    public JsonResult Index(Item item) { return new JsonResult(); }
    
  3. Lorsqu'un paramètre Id est passé à L'URI, une seule action doit gérer GET et DELETE.

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

Question

Comment puis-je avoir plus d'une action (partageant le même nom et la même signature de méthode) chacune répond à un verbe http unique. Souhaité exemple:

[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); */ }
9
demandé sur Community 2011-12-23 02:32:52

1 réponses

pour les appels RESTful, l'action n'a pas de sens, puisque vous ne voulez différer que par les méthodes HTTP. Le truc est donc d'utiliser un nom d'action statique, de sorte que les différentes méthodes sur le controller ne soient différentes que dans la méthode HTTP qu'elles acceptent.

MVC framework fournit une solution pour spécifier les noms d'action, il peut être plus concis et explicite. Nous l'avons résolu comme ceci:

un attribut spécial est utilisé pour spécifier RESTful méthodes (ce qui correspond à un nom d'action):

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

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

les controllers l'utilisent en combinaison avec les attributs de la méthode 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(...);
    }
}

et pour lier ces controllers avec succès, nous utilisons des routes personnalisées avec le nom d'action statique de l'attribut beforementioned (qui permet en même temps de personnaliser les URLs):

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

notez que toutes vos exigences peuvent être facilement satisfaites avec cette approche autant que je peux dire; vous peut avoir plusieurs attributs [HttpXxx] sur une méthode pour qu'une méthode accepte plusieurs méthodes HTTP. Jumelé avec un(er) ModelBinder intelligent c'est très puissant.

10
répondu Lucero 2017-05-23 10:26:50