web-dev-qa-db-fra.com

Routage API Web - api / {contrôleur} / {action} / {id} "dysfonctionnements" api / {contrôleur} / {id}

J'ai la route par défaut dans Global.asax:

 RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

Je voulais pouvoir cibler une fonction spécifique, j'ai donc créé un autre itinéraire:

RouteTable.Routes.MapHttpRoute(
         name: "WithActionApi",
         routeTemplate: "api/{controller}/{action}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

Donc, dans mon contrôleur, j'ai:

    public string Get(int id)
    {
        return "object of id id";
    }        

    [HttpGet]
    public IEnumerable<string> ByCategoryId(int id)
    {
        return new string[] { "byCategory1", "byCategory2" };
    }

Appeler .../api/records/bycategoryid/5 Me donnera ce que je veux. Cependant, appeler .../api/records/1 Me donnera l'erreur

Plusieurs actions correspondant à la demande ont été trouvées: ...

Je comprends pourquoi: les routes définissent simplement les URL valides, mais pour ce qui est de la correspondance des fonctions, Get(int id) et ByCategoryId(int id) correspondent api/{controller}/{id}. confuse le cadre.

Que dois-je faire pour que la route par défaut de l'API fonctionne à nouveau et conserve celle avec {action}? J'ai pensé créer un autre contrôleur nommé RecordByCategoryIdController pour qu'il corresponde à la route par défaut de l'API, pour laquelle je demanderais .../api/recordbycategoryid/5. Cependant, je trouve que c'est une solution "sale" (donc insatisfaisante). J'ai cherché des réponses à ce sujet et aucun tutoriel sur l'utilisation d'une route avec {action} Ne mentionne même ce problème.

92
Mickael Caruso

Le moteur de routage utilise la même séquence lorsque vous y ajoutez des règles. Une fois qu'il aura obtenu la première règle correspondante, il cessera de vérifier les autres règles et utilisera cette information pour rechercher un contrôleur et une action.

Donc tu devrais:

  1. Faites passer vos règles spécifiques avant vos règles générales (comme les règles par défaut), ce qui signifie utiliser RouteTable.Routes.MapHttpRoute pour mapper "WithActionApi" en premier, puis "DefaultApi".

  2. Retirer le defaults: new { id = System.Web.Http.RouteParameter.Optional } paramètre de votre règle "WithActionApi" car une fois que id est facultatif, une URL telle que "/ api/{part1}/{part2}" ne sera jamais placée dans "DefaultApi".

  3. Ajoutez une action nommée à votre "DefaultApi" pour indiquer au moteur de route quelle action entrer. Sinon, une fois que vous avez plusieurs actions dans votre contrôleur, le moteur ne saura pas laquelle utiliser et émet "Plusieurs actions correspondant à la requête: ... ont été trouvées. Ensuite, pour qu’elle corresponde à votre méthode Get, utilisez un ActionNameAttribute .

Donc, votre itinéraire devrait ressembler à ceci:

// Map this rule first
RouteTable.Routes.MapRoute(
     "WithActionApi",
     "api/{controller}/{action}/{id}"
 );

RouteTable.Routes.MapRoute(
    "DefaultApi",
    "api/{controller}/{id}",
    new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);

Et votre contrôleur:

[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
    return "object of id id";
}        

[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
    return new string[] { "byCategory1", "byCategory2" };
}
101
Chris Li

Vous pouvez résoudre votre problème avec l'aide de Routage d'attributs

Contrôleur

[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }

URI dans jQuery

api/category/1

Configuration de la route

using System.Web.Http;

namespace WebApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            // Other Web API configuration not shown.
        }
    }
}

et votre routage par défaut fonctionne comme routage par défaut

Contrôleur

public string Get(int id)
    {
        return "object of id id";
    }   

URI dans JQuery

/api/records/1 

Configuration de la route

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

        // Convention-based routing.
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Consultez l'article pour plus d'informations Routage d'attributs et routage basé sur des inventions ici & this

36
MSTdev

La raison possible peut également être que vous n’avez pas hérité de Controller d’ApiController. Arrivé avec moi a pris un certain temps pour comprendre la même chose.

0
Paritosh Tiwari

Essaye ça.

public class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        var json = config.Formatters.JsonFormatter;
        json.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional , Action =RouteParameter.Optional }

        );
    }
}
0
Amit

Pour différencier les itinéraires, essayez d’ajouter une contrainte dont id doit être numérique:

RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         constraints: new { id = @"\d+" }, // Only matches if "id" is one or more digits.
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );  
0
Derek Wade