web-dev-qa-db-fra.com

Routage d'API Web avec plusieurs paramètres

J'essaie de savoir comment faire le routage pour le contrôleur d'API Web suivant:

public class MyController : ApiController
{
    // POST api/MyController/GetAllRows/userName/tableName
    [HttpPost]
    public List<MyRows> GetAllRows(string userName, string tableName)
    {
        ...
    }

    // POST api/MyController/GetRowsOfType/userName/tableName/rowType
    [HttpPost]
    public List<MyRows> GetRowsOfType(string userName, string tableName, string rowType)
    {
        ...
    }
}

Pour le moment, j'utilise ce routage pour les URL:

routes.MapHttpRoute("AllRows", "api/{controller}/{action}/{userName}/{tableName}",
                    new
                    {
                        userName= UrlParameter.Optional,
                        tableName = UrlParameter.Optional
                    });

routes.MapHttpRoute("RowsByType", "api/{controller}/{action}/{userName}/{tableName}/{rowType}",
                    new
                    {
                        userName= UrlParameter.Optional,
                        tableName = UrlParameter.Optional,
                        rowType= UrlParameter.Optional
                    });

mais seule la première méthode (avec 2 paramètres) fonctionne pour le moment. Suis-je sur les bonnes lignes, ou ai-je le format URL ou le routage complètement faux? Le routage me semble une magie noire ...

25
Mourndark

Le problème est votre api/MyController/GetRowsOfType/userName/tableName/rowType L'URL correspondra toujours à la première route afin que la seconde ne soit jamais atteinte.

Solution simple, enregistrez d'abord votre route RowsByType.

15
James

J'ai vu le WebApiConfig obtenir " hors de contrôle" avec des centaines de routes placées dedans.

Au lieu de cela, je préfère personnellement Routage des attributs

Vous le confondez avec POST et GET

[HttpPost]
public List<MyRows> GetAllRows(string userName, string tableName)
{
   ...
}

HttpPost ET GetAllRows ?

Pourquoi ne pas le faire à la place:

[Route("GetAllRows/{user}/{table}")]
public List<MyRows> GetAllRows(string userName, string tableName)
{
   ...
}

OU changez pour Route ("PostAllRows" et PostRows Je pense que vous faites vraiment une requête GET donc le code que je montre devrait fonctionner pour vous. Votre appel du client serait WHATEVER est dans la ROUTE, donc il TROUVERA VOTRE MÉTHODE avec GetAllRows , mais la méthode elle-même, ce nom PEUT ÊTRE tout ce que vous voulez, donc tant que l'appelant correspond à l'URL dans ROUTE, vous pouvez mettre GetMyStuff pour la méthode si vous le voulez vraiment.

Mise à jour:

En fait, je préfère être explicit avec le type de HTTP methods ET je préfère faire correspondre les paramètres de route aux paramètres de méthode

[HttpPost]
[Route("api/lead/{vendorNumber}/{recordLocator}")]
public IHttpActionResult GetLead(string vendorNumber, string recordLocator)
{ .... }

(la route lead n'a pas besoin de correspondre au nom de la méthode GetLead mais vous voudrez garder les mêmes noms sur les paramètres de la route et les paramètres de la méthode, même si vous pouvez changer l'ordre, par exemple, mettre recordLocator avant vendorNumber même si l'itinéraire est le contraire - je ne le fais pas, car pourquoi le rendre plus déroutant à regarder).

Bonus: vous pouvez désormais toujours utiliser l'expression régulière dans les itinéraires, par exemple

[Route("api/utilities/{vendorId:int}/{utilityType:regex(^(?i)(Gas)|(Electric)$)}/{accountType:regex(^(?i)(Residential)|(Business)$)}")]
public IHttpActionResult GetUtilityList(int vendorId, string utilityType, string accountType)
    {
50
Tom Stickel