Je commence à utiliser le projet API Web MVC4. J'ai un contrôleur avec plusieurs méthodes HttpPost
. Le contrôleur ressemble à ceci:
Manette
public class VTRoutingController : ApiController
{
[HttpPost]
public MyResult Route(MyRequestTemplate routingRequestTemplate)
{
return null;
}
[HttpPost]
public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
{
return null;
}
}
Here MyRequestTemplate
représente la classe de modèle chargée de traiter le fichier Json entrant dans la requête.
Erreur:
Lorsque je fais une demande en utilisant Fiddler pour http://localhost:52370/api/VTRouting/TSPRoute
ou http://localhost:52370/api/VTRouting/Route
, une erreur se produit:
Plusieurs actions correspondant à la demande ont été trouvées
Si je supprime une des méthodes ci-dessus, cela fonctionne bien.
Global.asax
J'ai essayé de modifier la table de routage par défaut dans global.asax
, mais je reçois toujours l'erreur, je pense que j'ai du mal à définir les itinéraires dans global.asax. Voici ce que je fais dans Global.asax.
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapHttpRoute(
name: "MyTSPRoute",
routeTemplate: "api/VTRouting/TSPRoute",
defaults: new { }
);
routes.MapHttpRoute(
name: "MyRoute",
routeTemplate: "api/VTRouting/Route",
defaults: new { action="Route" }
);
}
Je fais la demande dans Fiddler en utilisant POST, en passant json dans RequestBody pour MyRequestTemplate.
Vous pouvez avoir plusieurs actions dans un seul contrôleur.
Pour cela, vous devez faire les deux choses suivantes.
Commencez par décorer les actions avec l'attribut ActionName
comme
[ActionName("route")]
public class VTRoutingController : ApiController
{
[ActionName("route")]
public MyResult PostRoute(MyRequestTemplate routingRequestTemplate)
{
return null;
}
[ActionName("tspRoute")]
public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate)
{
return null;
}
}
Deuxièmement, définissez les itinéraires suivants dans le fichier WebApiConfig
.
// Controller Only
// To handle routes like `/api/VTRouting`
config.Routes.MapHttpRoute(
name: "ControllerOnly",
routeTemplate: "api/{controller}"
);
// Controller with ID
// To handle routes like `/api/VTRouting/1`
config.Routes.MapHttpRoute(
name: "ControllerAndId",
routeTemplate: "api/{controller}/{id}",
defaults: null,
constraints: new { id = @"^\d+$" } // Only integers
);
// Controllers with Actions
// To handle routes like `/api/VTRouting/route`
config.Routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}"
);
utilisation:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
ce n'est plus une approche RESTful, mais vous pouvez maintenant appeler vos actions par leur nom (plutôt que de laisser l'API Web en déterminer automatiquement une à partir du verbe) comme ceci:
[POST] /api/VTRouting/TSPRoute
[POST] /api/VTRouting/Route
Contrairement à la croyance populaire, cette approche n’est pas fâcheuse et elle n’abuse pas des API Web. Vous pouvez toujours tirer parti de toutes les fonctionnalités impressionnantes de l'API Web (gestionnaires de délégation, négociation de contenu, mediatypeformatters, etc.). Il vous suffit de laisser tomber l'approche RESTful.
Une solution bien meilleure à votre problème serait d'utiliser Route
qui vous permet de spécifier l'itinéraire sur la méthode par annotation:
[RoutePrefix("api/VTRouting")]
public class VTRoutingController : ApiController
{
[HttpPost]
[Route("Route")]
public MyResult Route(MyRequestTemplate routingRequestTemplate)
{
return null;
}
[HttpPost]
[Route("TSPRoute")]
public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
{
return null;
}
}
Un terminal API Web (contrôleur) est une ressource unique qui accepte les verbes get/post/put/delete. C'est pas un contrôleur MVC normal.
Nécessairement, à /api/VTRouting
, il ne peut y avoir que la méthode one HttpPost qui accepte les paramètres que vous envoyez. Le nom de la fonction n'a pas d'importance tant que vous décorez avec le matériel [http]. Je n'ai jamais essayé, cependant.
Edit: Cela ne fonctionne pas. En résolvant, il semble aller par le nombre de paramètres, n'essayant pas de lier le modèle au modèle.
Vous pouvez surcharger les fonctions pour accepter différents paramètres. Je suis presque certain que vous seriez OK si vous le déclariez comme vous le faites, mais que vous utilisiez des paramètres différents (incompatibles) avec les méthodes. Si les paramètres sont identiques, vous êtes faute de chance en tant que modèle de liaison ne saura pas lequel vous vouliez dire.
[HttpPost]
public MyResult Route(MyRequestTemplate routingRequestTemplate) {...}
[HttpPost]
public MyResult TSPRoute(MyOtherTemplate routingRequestTemplate) {...}
Cette partie fonctionne
Le modèle par défaut qu'ils donnent lorsque vous en créez un nouveau le rend très explicite, et je dirais que vous devriez vous en tenir à cette convention:
public class ValuesController : ApiController
{
// GET is overloaded here. one method takes a param, the other not.
// GET api/values
public IEnumerable<string> Get() { .. return new string[] ... }
// GET api/values/5
public string Get(int id) { return "hi there"; }
// POST api/values (OVERLOADED)
public void Post(string value) { ... }
public void Post(string value, string anotherValue) { ... }
// PUT api/values/5
public void Put(int id, string value) {}
// DELETE api/values/5
public void Delete(int id) {}
}
Si vous voulez créer une classe qui fasse beaucoup de choses, pour une utilisation ajax, il n'y a aucune raison importante de ne pas utiliser un modèle de contrôleur/action standard. La seule différence entre vos méthodes est que les signatures de votre méthode ne sont pas aussi jolies et que vous devez envelopper les éléments dans Json( returnValue)
avant de les renvoyer.
Modifier:
La surcharge fonctionne parfaitement lorsque vous utilisez le modèle standard (modifié pour inclure) lorsque vous utilisez des types simples. Je suis aussi allé dans l'autre sens, avec 2 objets personnalisés avec des signatures différentes. Jamais pourrait le faire fonctionner.
Cela a fonctionné pour moi dans ce cas, voyez où cela vous mène. Exception pour les tests uniquement.
public class NerdyController : ApiController
{
public void Post(string type, Obj o) {
throw new Exception("Type=" + type + ", o.Name=" + o.Name );
}
}
public class Obj {
public string Name { get; set; }
public string Age { get; set; }
}
Et appelé comme ceci la console:
$.post("/api/Nerdy?type=white", { 'Name':'Slim', 'Age':'21' } )
Il est possible d'ajouter plusieurs méthodes Get et Post dans le même contrôleur API Web. Ici, la route par défaut cause le problème. L'API Web vérifie la correspondance de l'itinéraire du haut vers le bas et, par conséquent, votre itinéraire par défaut correspond à toutes les demandes. Par défaut, une seule méthode Get et Post est possible dans un contrôleur. Placez le code suivant en haut ou commentez l'itinéraire par défaut
config.Routes.MapHttpRoute("API Default",
"api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
Placez Route Prefix [RoutePrefix ("api/Profiles")] au niveau du contrôleur et mettez une route à la méthode d'action [Route ("LikeProfile")]. Pas besoin de changer quoi que ce soit dans le fichier global.asax
namespace KhandalVipra.Controllers
{
[RoutePrefix("api/Profiles")]
public class ProfilesController : ApiController
{
// POST: api/Profiles/LikeProfile
[Authorize]
[HttpPost]
[Route("LikeProfile")]
[ResponseType(typeof(List<Like>))]
public async Task<IHttpActionResult> LikeProfile()
{
}
}
}
Je pense que la question a déjà été répondu. Je recherchais également un contrôleur webApi possédant les mêmes mehtods mais des noms différents. J'essayais d'implémenter la calculatrice en tant que WebApi. La calculatrice a 4 méthodes avec la même signature mais des noms différents.
public class CalculatorController : ApiController
{
[HttpGet]
[ActionName("Add")]
public string Add(int num1 = 1, int num2 = 1, int timeDelay = 1)
{
Thread.Sleep(1000 * timeDelay);
return string.Format("Add = {0}", num1 + num2);
}
[HttpGet]
[ActionName("Sub")]
public string Sub(int num1 = 1, int num2 = 1, int timeDelay = 1)
{
Thread.Sleep(1000 * timeDelay);
return string.Format("Subtract result = {0}", num1 - num2);
}
[HttpGet]
[ActionName("Mul")]
public string Mul(int num1 = 1, int num2 = 1, int timeDelay = 1)
{
Thread.Sleep(1000 * timeDelay);
return string.Format("Multiplication result = {0}", num1 * num2);
}
[HttpGet]
[ActionName("Div")]
public string Div(int num1 = 1, int num2 = 1, int timeDelay = 1)
{
Thread.Sleep(1000 * timeDelay);
return string.Format("Division result = {0}", num1 / num2);
}
}
et dans le fichier WebApiConfig que vous avez déjà
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
Il suffit de définir l’authentification/autorisation sur IIS et vous avez terminé!
J'espère que cela t'aides!
Je viens d'ajouter "action = nom_action" à l'URL et le moteur de routage sait ainsi quelle action je souhaite effectuer. J'ai également ajouté l'attribut ActionName aux actions, mais je ne suis pas sûr que cela soit nécessaire.