Paramètres facultatifs dans le routage d'attributs de l'API Web

89

Je veux gérer le POST de l'appel API suivant:

/v1/location/deviceid/appid

Des paramètres supplémentaires proviennent du post-corps.

Tout cela fonctionne bien pour moi. Maintenant, je veux étendre mon code en autorisant "deviceid" et / ou "appid" et / ou BodyData à être null:

/v1/location/deviceid
/v1/location/appid
/v1/location/

Ces 3 URL doivent répondre par la même route.

Ma première approche (BodyData requis):

[Route("v1/location/{deviceid}/{appid}", Name = "AddNewLocation")]
public location_fromuser Post(string deviceid = null, string appid = null, [FromBody] location_fromuser BodyData)
{
    return repository.AddNewLocation(deviceid, appid, BodyData);
}

Cela ne fonctionne pas et renvoie une erreur de compilation:

"Les paramètres facultatifs doivent être à la fin"

Prochain essai:

[Route("v1/location/{deviceid}/{appid}", Name = "AddNewLocation")]
public location_fromuser Post([FromBody] location_fromuser BodyData, string deviceid = null, string appid = null)

Maintenant, ma fonction AddNewLocation () obtient toujours un BodyData=null- même si l'appel envoie le Body.

Enfin, j'ai mis les 3 paramètres en option:

[Route("v1/location/{deviceid}/{appid}", Name = "AddNewLocation")]
public location_fromuser Post(string deviceid = null, string appid = null, [FromBody location_fromuser BodyData = null)

Ne fonctionne pas:

Le paramètre facultatif BodyDatan'est pas pris en charge par FormatterParameterBinding.

Pourquoi est-ce que je veux une solution avec des paramètres facultatifs? Mon contrôleur ne gère que "l'ajout d'un nouvel emplacement" via un POST.

Je veux envoyer sur de mauvaises données mes propres exceptions ou messages d'erreur. Même si l'appel a des valeurs manquantes. Dans ce cas, je veux pouvoir décider de lever une exception ou de définir les valeurs par défaut par mon code.

Oliver Apel
la source

Réponses:

174

Pour une requête entrante comme /v1/location/1234, comme vous pouvez l'imaginer, il serait difficile pour l'API Web de déterminer automatiquement si la valeur du segment correspondant à '1234' est liée à appidet non à deviceid.

Je pense que vous devriez changer votre modèle de route pour qu'il ressemble [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")], puis analyser le deiveOrAppidpour déterminer le type d'identifiant.

Vous devez également rendre les segments dans le modèle d'itinéraire lui-même facultatifs, sinon les segments sont considérés comme obligatoires. Notez le ?caractère dans ce cas. Par exemple: [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]

Kiran Challa
la source
55
?à l'intérieur du modèle d'itinéraire est ce que je recherchais. +1
Kal_Torak
4
Je ne dirais pas que "deviceOrAppId" est le meilleur choix de conception. Je pense que l'API devrait toujours savoir par définition ce qu'elle recevra si possible.
Niels Brinch
13
Juste pour information - Lorsque nous marquons un paramètre comme facultatif dans l'URI d'action en utilisant un ?caractère, nous devons fournir des valeurs par défaut aux paramètres dans la signature de la méthode, par exemple MyMethod (string name = "someDefaultValue", int? Id = null).
RBT
@RBT vous êtes un vrai MVP, je suis resté perplexe pendant une minute. Je vous remercie!
sm
1
Cool. Heureux que cela vous ait aidé @sm J'ai converti mon commentaire en réponse pour une meilleure visibilité car cela semble utile. Ce sera un complément au message de Kiran.
RBT
45

Une autre information: si vous voulez utiliser une contrainte de route , imaginez que vous voulez forcer ce paramètre à un type de données int , alors vous devez utiliser cette syntaxe:

[Route("v1/location/**{deviceOrAppid:int?}**", Name = "AddNewLocation")]

Le ? le caractère est toujours placé avant le dernier caractère }

Pour plus d'informations, voir: Paramètres d'URI facultatifs et valeurs par défaut

Tiago Ferreira
la source
18

Convertir mon commentaire en réponse pour compléter la réponse de @Kiran Chala car cela semble utile pour le public-

Lorsque nous marquons un paramètre comme facultatif dans l'URI d'action à l'aide de ?character, nous devons fournir des valeurs par défaut aux paramètres de la signature de la méthode, comme indiqué ci-dessous:

MyMethod(string name = "someDefaultValue", int? Id = null)

RBT
la source
J'étais sur le point de commenter la même chose.
Jnr le