Pourquoi devons-nous spécifier FromBody et FromUri?

157

Pourquoi les attributs FromBodyet sont-ils FromUrinécessaires dans l'API Web ASP.NET`?

Quelles sont les différences entre utiliser les attributs et ne pas les utiliser?

Rajneesh
la source
11
Juste pour donner un indice sur le moment où il pourrait être utile d'utiliser l'annotation [FromBody]: Il est par exemple peu pratique d'envoyer des informations d'identification statiques telles que nom d'utilisateur / mot de passe en tant que paramètres encodés dans l'URL. Même si le cryptage SSL peut empêcher un tiers d'accéder en lecture aux paramètres de l'URL, cela reste une mauvaise pratique, car ces informations d'identification peuvent être stockées dans les journaux du navigateur et égaux, ce qui n'est certainement pas souhaité. Dans un tel cas, on pourrait utiliser l'annotation [FromBody], pour forcer le stockage d'un paramètre dans le corps du message HTTP, en introduisant un high
Chris

Réponses:

193

Lorsque l'API Web ASP.NET appelle une méthode sur un contrôleur, elle doit définir des valeurs pour les paramètres, un processus appelé liaison de paramètres .

Par défaut, l'API Web utilise les règles suivantes pour lier les paramètres:

  • Si le paramètre est de type "simple" , l'API Web essaie d'obtenir la valeur de l'URI . Les types simples incluent les types primitifs .NET (int, bool, double, etc.), plus TimeSpan, DateTime, Guid, decimal et string, ainsi que tout type avec un convertisseur de type qui peut convertir à partir d'une chaîne.

  • Pour les types complexes , l'API Web tente de lire la valeur à partir du corps du message , à l'aide d'un formateur de type média.

Par conséquent, si vous souhaitez remplacer le comportement par défaut ci-dessus et forcer l'API Web à lire un type complexe à partir de l'URI, ajoutez l' [FromUri]attribut au paramètre. Pour forcer l'API Web à lire un type simple à partir du corps de la requête, ajoutez l' [FromBody]attribut au paramètre.

Donc, pour répondre à votre question, le besoin des attributs [FromBody]et [FromUri]dans l'API Web est simplement de remplacer, si nécessaire, le comportement par défaut décrit ci-dessus. Notez que vous pouvez utiliser les deux attributs pour une méthode de contrôleur, mais uniquement pour des paramètres différents, comme illustré ici .

Il y a beaucoup plus d' informations sur le Web si vous google "liaison de paramètre de l'API Web".

Djikay
la source
2
@ user3510527: Vous n'êtes pas obligé d'utiliser ces attributs si vous ne le souhaitez pas, tant que vous suivez le comportement par défaut. Si vous souhaitez modifier le comportement par défaut, vous devez les utiliser.
djikay
1
s'il fait son comportement par défaut, alors pourquoi nous devons passer outre et quels avantages nous obtiendrons si nous mentionnons cet attribut?
Rajneesh
1
@ user3510527 Vous n'avez pas besoin de remplacer. Vous pouvez simplement utiliser le comportement par défaut. Un exemple où quelqu'un pourrait vouloir remplacer est s'il veut fournir un entier simple dans le corps de la requête car, par défaut, il s'attend à le trouver dans l'URI. En gros, vous pouvez simplement laisser le comportement par défaut si vous le souhaitez ou vous pouvez le remplacer, c'est juste une option que vous avez. Je ne comprends pas quelle est la confusion.
djikay le
Je veux juste connaître le processus de travail interne si nous utilisons l'attribut form, donc directement il obtiendra la valeur et ne vérifiera aucun uri ou formbody ...
Rajneesh
7
Je me demande si on pourrait faire un attribut appelé JustGetItqui sert le même but d'ajouter plusieurs attributs comme [FromBody, FromQuery]etc
The Muffin Man
93

Le comportement par défaut est:

  1. Si le paramètre est une primitive de type ( int, bool, double, ...), l' API Web cherche à obtenir la valeur de l' URI de la requête HTTP.

  2. Pour les types complexes (votre propre objet, par exemple Person:), l'API Web essaie de lire la valeur à partir du corps de la requête HTTP.

Donc, si vous avez:

  • un type primitif dans l'URI, ou
  • un type complexe dans le corps

... alors vous n'avez pas à ajouter d'attributs (ni [FromBody]ni [FromUri]).

Mais, si vous avez un type primitif dans le corps , vous devez l'ajouter [FromBody]devant votre paramètre de type primitif dans votre méthode de contrôleur WebAPI. (Parce que, par défaut, WebAPI recherche des types primitifs dans l'URI de la requête HTTP.)

Ou, si vous avez un type complexe dans votre URI , vous devez ajouter [FromUri]. (Parce que, par défaut, WebAPI recherche par défaut des types complexes dans le corps de la requête HTTP.)

Types primitifs:

public class UsersController : ApiController
{
    // api/users
    public HttpResponseMessage Post([FromBody]int id)
    {

    }
    // api/users/id
    public HttpResponseMessage Post(int id)
    {

    }       
}

Types complexes:

public class UsersController : ApiController
{       
    // api/users
    public HttpResponseMessage Post(User user)
    {

    }

    // api/users/user
    public HttpResponseMessage Post([FromUri]User user)
    {

    }       
}

Cela fonctionne tant que vous n'envoyez qu'un seul paramètre dans votre requête HTTP. Lors de l'envoi de plusieurs , vous devez créer un modèle personnalisé qui a tous vos paramètres comme ceci:

public class MyModel
{
    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
}

[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
    // model.MyProperty;
    // model.MyProperty2;
}

À partir de la documentation de Microsoft pour la liaison de paramètres dans l'API Web ASP.NET :

Lorsqu'un paramètre a [FromBody], l'API Web utilise l'en-tête Content-Type pour sélectionner un formateur. Dans cet exemple, le type de contenu est "application / json" et le corps de la demande est une chaîne JSON brute (pas un objet JSON). Au plus un paramètre est autorisé à lire à partir du corps du message.

Cela devrait fonctionner:

public HttpResponseMessage Post([FromBody] string name) { ... }

Cela ne fonctionnera pas:

// Caution: This won't work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

La raison de cette règle est que le corps de la requête peut être stocké dans un flux non mis en mémoire tampon qui ne peut être lu qu'une seule fois.

Tadej
la source
5
"Au plus un paramètre est autorisé à lire à partir du corps du message" était une information particulièrement utile
Ryan
15

Juste un ajout aux réponses ci-dessus.

[FromUri] peut également être utilisé pour lier des types complexes à partir de paramètres uri au lieu de passer des paramètres depuis une chaîne de requête

Pour Ex ..

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
    [Route("{Latitude}/{Longitude}")]
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

Peut être appelé comme:

http://localhost/api/values/47.678558/-122.130989
Utkarsh Patel
la source
12

Lorsqu'un paramètre a [FromBody], l'API Web utilise l'en-tête Content-Type pour sélectionner un formateur. Dans cet exemple, le type de contenu est "application / json" et le corps de la demande est une chaîne JSON brute (pas un objet JSON).

Au plus un paramètre est autorisé à lire à partir du corps du message. Donc cela ne fonctionnera pas:

 // Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

La raison de cette règle est que le corps de la requête peut être stocké dans un flux non tamponné qui ne peut être lu qu'une seule fois

Veuillez consulter le site Web pour plus de détails: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

user5166729
la source