31 votes

Comment une méthode MVC WebApi carte à un verbe http?

Dans la vidéo de 5 minutes sur le lien suivant, au 1:10 marque, Jon Galloway dit que l'ajout d'une méthode appelée DeleteComment à son CommentsController contrôleur de classe par la convention de la carte automatiquement à la suppression http verbe.

Comment MVC avec WebApi savoir comment faire pour mettre en déroute les méthodes pour le droit des verbes? Je sais que le routage dans le monde.asax.cs fichier achemine les requêtes vers le contrôleur correct, mais comment fait une demande de suppression d'obtenir "mappé par convention" pour la méthode de suppression, ou toute autre méthode? Surtout quand il peut y avoir plus de 1 méthode pour chaque verbe? "Par convention" me fait penser que c'est seulement en regardant le premier mot d'un nom de méthode ... mais si oui, il aurait à lire la signature des méthodes de dire deux supprimer des méthodes ou des deux méthodes get en dehors ... et où tout cela est-il défini?

Vidéo: http://www.asp.net/web-api/videos/getting-started/delete-and-update

Merci!

Edit: Voici le code dans l'exemple de classe ValuesController qui vient dans la WebApi modèle. C'est l'origine de ma question initiale. Comment fonctionne la "convention" qui fait la différence entre ceux-ci (et de toute autre méthode dans le contrôleur) de travail?

// GET /api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET /api/values/5
    public string Get(int id)
    {
        return value;
    }

60voto

EBarr Points 5824

Je m'excuse à l'avance, ce post s'éloigne un peu de ce que vous avez demandé, mais tout cela bouillonnait quand j'ai lu votre question.

WebAPI Appariement Sémantique
L'appariement sémantique utilisé par (la valeur par défaut routes) WebAPI est assez simple.

  1. Il correspond au nom de l'action avec le verbe (verbe = GET? recherchez le nom de la méthode en commençant par "get")
  2. si un paramètre est passé, l'api cherche une action avec un paramètre

Donc dans votre exemple de code d'une requête GET sans paramètre correspond à l' Get*( ) fonction sans paramètres. Un contenant et ID recherche un Get***(int id).

Exemples
Alors que l'appariement sémantique est simple, elle crée une certaine confusion pour MVC développeurs (bien au moins ce développeur). Regardons quelques exemples :

Bizarre Noms - Votre méthode get peut être nommé n'importe quoi, tant que ça commence par "get". Ainsi, dans le cas d'un widget contrôleur, vous pouvez nommer vos fonctions GetStrawberry() et il sera toujours appariés. Pensez à la correspondance que quelque chose comme : methodname.StartsWith("Get")

Plusieurs Méthodes d'Appariement - Ce qui arrive si vous disposez de deux méthodes Get sans paramètres? GetStrawberry() et GetOrange(). Du mieux que je peux dire, la fonction définie à la première (en haut du fichier) dans votre code gagne ...étrange. Cela a pour effet secondaire de faire certaines méthodes dans votre contrôleur inaccessible (au moins avec les routes par défaut)....un étranger.

REMARQUE : la bêta se sont comportés comme ci-dessus pour la correspondance de multiples méthodes " - la RC et la version est un peu plus trouble obsessionnel-compulsif. Il renvoie une erreur si il y a plusieurs correspondances possibles. Cette modification supprime la confusion de plusieurs ambigu matchs. Dans le même temps, il réduit notre capacité à mélanger les REPOS et RPC interfaces de style dans le même contrôleur, en s'appuyant sur l'ordre et le chevauchement des routes.

Que faire?
Eh bien, WebAPI est nouveau, et le consensus est toujours la coalescence. La communauté semble être atteint pour le REPOS des principes tout à fait un peu. Pourtant, pas tous les API peut ou devrait être paisible, certains sont plus naturellement exprimée dans un style RPC. Reposez-vous et que les gens appellent le RESTE semble être la source de tout à fait un peu de confusion, bien au moins de Roy Fielding.

Comme un pragmatique, je pense que nombre d'API sera de 70% Reposante, avec une poignée de type RPC méthodes. Tout d'abord, le contrôleur de la prolifération seul (compte tenu de la webapi méthode de reliure) va conduire les développeurs de dingue. Deuxièmement, WebAPI n'a pas vraiment intégré dans la façon de créer une structure imbriquée des api chemins (ce qui signifie: /api/controller/ est facile, mais /api/CATEGORY/Sub-Category/Controller , c'est faisable, mais une douleur).

De mon point de vue, j'aimerais voir la webAPI structure de dossier de contrôle de la valeur par défaut de l'API chemins... de sens que si je créer un dossier de Catégorie dans mon INTERFACE alors /api/Category serait le chemin d'accès par défaut (quelque chose de parallèle à cette MVC article).

Qu'ai-je fait?
Donc, j'avais quelques exigences: (1) pour être en mesure d'utiliser reposant syntaxe dans la plupart des cas, (2) d'avoir un peu d'espace de noms" séparation des contrôleurs (pensez à les sous-dossiers), (3) être en mesure d'appeler d'autres rpc-comme des méthodes si nécessaire. La mise en œuvre de ces exigences est descendu à intelligent de routage.

// SEE NOTE AT END ABOUT DataToken change from RC to RTM

Route r;
r = routes.MapHttpRoute( name          : "Category1", 
                         routeTemplate : "api/Category1/{controller}/{id}", 
                         defaults      : new { id = RouteParameter.Optional } );
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category1"};

r = routes.MapHttpRoute( name          : "Category2", 
                         routeTemplate : "api/Category2/{controller}/{id}", 
                         defaults      : new { id = RouteParameter.Optional } );
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category2"};

routes.MapHttpRoute(     name          : "ApiAllowingBL", 
                         routeTemplate : "api/{controller}/{action}/{id}",
                         defaults      : new { id = RouteParameter.Optional } );

routes.MapHttpRoute(     name          : "DefaultApi",  
                         routeTemplate : "api/{controller}/{id}",           
                         defaults      : new { id = RouteParameter.Optional } );
  • Les deux premières voies de créer des "sous-dossier" routes. J'ai besoin de créer une route pour chaque sous-dossier, mais je me suis restreint à grandes catégories, alors je n'en ai jusqu'à la fin avec 3-10 de ces. Remarquez comment ces routes ajouter l' Namespace données jeton, pour limiter ce que les classes sont recherchées pour un itinéraire particulier. Cela correspond bien aux caractéristiques de l'espace de noms de la configuration que vous ajouter des dossiers à la une de l'INTERFACE.
  • Le troisième itinéraire permet à des noms de méthodes pour être appelé (comme mvc traditionnel). Depuis l'API web fait disparaître le nom de l'action dans l'URL, il est relativement facile de savoir qui appelle souhaitez que cette route.
  • La dernière entrée de gamme est le site web par défaut de l'api de la route. Ce prises toutes les classes, en particulier ceux qui sont en dehors de mon "sous-dossiers".

Dit D'Une Autre Manière
Ma solution est venue vers le bas pour séparer les contrôleurs un peu plus /api/XXXX n'a pas trop encombré.

  • J'ai créer un dossier dans mon INTERFACE(disons Category1), et de mettre contrôleurs d'api dans le dossier.
  • Visual studio naturellement définit la classe des espaces de noms basés sur le dossier. Donc, Widget1 dans la Category1 le dossier est un espace de noms par défaut de UI.Category1.Widget1.
  • Naturellement, je voulais Url de l'api afin de refléter la structure de dossier (/api/Category1/Widget). La première carte que vous voyez ci-dessus accomplit que par le codage en dur /api/Category1 dans la route, puis l' namespace jeton restreint de classes qui vont être recherchés pour la correspondance du contrôleur.

REMARQUE: dans la version DataTokens ont la valeur null par défaut. Je ne suis pas sûr que si c'est un bug ou une fonctionnalité. J'ai donc écrit une petite aide méthode et ajouté à mon RouteConfig.cs le fichier....

r.AddRouteToken("Namespaces", new string[] {"UI.Controllers.Category1"});

private static Route AddRouteToken(this Route r, string key, string[] values) {
  //change from RC to RTM ...datatokens is null
if (r.DataTokens == null) {
       r.DataTokens = new RouteValueDictionary();
    }
    r.DataTokens[key] = values;
    return r;
}

NOTE 2: même pensé que c'est une WebAPI 1 poste, comme @Jamie_Ide points dans les commentaires de la solution ci-dessus ne fonctionne pas dans WebAPI 2, car IHttpRoute.DataTokens n'a pas de setter. Pour contourner cela, vous pouvez utiliser une simple extension de la méthode comme ceci:

private static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, string[] namespaceTokens)
{   
    HttpRouteValueDictionary    defaultsDictionary      = new HttpRouteValueDictionary(defaults);
    HttpRouteValueDictionary    constraintsDictionary   = new HttpRouteValueDictionary(constraints);
    IDictionary<string, object> tokens                  = new Dictionary<string, object>();
                                tokens.Add("Namespaces", namespaceTokens);

    IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: tokens, handler:null);
    routes.Add(name, route);

    return route;
}

3voto

Aliostad Points 47792

Cela arrive assez souvent. Et il y a différents points de vue sur cette. Personnellement, je n'ai pas souscrit à aucune idée pour l'instant mais il semble que l'un avec un contrôleur-par-ressource pour être le plus populaire parmi le RESTE de la communauté.

Donc, fondamentalement, vous pouvez:

  1. Exposer l'action dans votre itinéraire (Web API traite le mot action similaire à la MVC), mais ce n'est généralement pas destinés à être utilisés.
  2. Définir des méthodes avec différents paramètres comme par ce post
  3. Comme je l'ai dit, le plus recommandé est à l'aide d' un contrôleur par ressource. Ainsi, même dans l'API Web de l'échantillon, le contrôleur de la collecte d'une entité est différente pour le contrôleur de l'entité elle-même. Lire ce post par Rob Conery et ici est de Glenn réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X