Perché dobbiamo specificare FromBody e FromUri?


157

Perché gli attributi FromBodye sono FromUrinecessari nell'API Web ASP.NET`?

Quali sono le differenze tra usare gli attributi e non usarli?


11
Solo per dare un suggerimento su quando potrebbe essere utile utilizzare l'annotazione [FromBody]: è ad esempio una cattiva pratica inviare credenziali statiche come nome utente / password come parametri codificati all'interno dell'URL. Anche se la crittografia SSL potrebbe impedire a terzi di ottenere l'accesso in lettura ai parametri all'interno dell'URL, rimane comunque una pratica poco pratica, poiché queste credenziali potrebbero essere archiviate nei registri del browser e uguali, il che non è sicuramente desiderato. In tal caso, si potrebbe usare l'annotazione [FromBody], per forzare l'archiviazione di un parametro all'interno del corpo del messaggio HTTP, introducendo un massimo
Chris

Risposte:


193

Quando l'API Web ASP.NET chiama un metodo su un controller, deve impostare i valori per i parametri, un processo chiamato binding dei parametri .

Per impostazione predefinita, l'API Web utilizza le seguenti regole per associare i parametri:

  • Se il parametro è di tipo "semplice" , l'API Web tenta di ottenere il valore dall'URI . I tipi semplici includono i tipi primitivi .NET (int, bool, double e così via), più TimeSpan, DateTime, Guid, decimale e stringa, oltre a qualsiasi tipo con un convertitore di tipi che può convertire da una stringa.

  • Per tipi complessi , l'API Web tenta di leggere il valore dal corpo del messaggio , utilizzando un formattatore di tipo multimediale.

Pertanto, se si desidera sovrascrivere il comportamento predefinito sopra riportato e forzare l'API Web a leggere un tipo complesso dall'URI, aggiungere l' [FromUri]attributo al parametro. Per forzare l'API Web a leggere un tipo semplice dal corpo della richiesta, aggiungere l' [FromBody]attributo al parametro.

Quindi, per rispondere alla tua domanda, la necessità degli attributi [FromBody]e [FromUri]nell'API Web è semplicemente quella di sovrascrivere, se necessario, il comportamento predefinito come descritto sopra. Si noti che è possibile utilizzare entrambi gli attributi per un metodo controller, ma solo per parametri diversi, come dimostrato qui .

Ci sono molte più informazioni sul web se si google "associazione parametri web api".


2
@ user3510527: non è necessario utilizzare questi attributi se non si desidera, purché si segua il comportamento predefinito. Se si desidera modificare il comportamento predefinito, è necessario utilizzarli.
djikay,

1
se sta facendo il suo comportamento predefinito, allora perché dobbiamo ovverare e quali benefici otterremo se menzionassimo questo attributo?
Rajneesh,

1
@ user3510527 Non è necessario eseguire l'override. Puoi semplicemente usare il comportamento predefinito. Un esempio in cui qualcuno potrebbe voler eseguire l'override è se desidera fornire un numero intero semplice nel corpo della richiesta perché, per impostazione predefinita, si aspetterà di trovarlo nell'URI. Fondamentalmente, puoi semplicemente lasciare il comportamento predefinito se vuoi o puoi sovrascrivere, è solo un'opzione che hai. Non capisco quale sia la confusione.
djikay,

voglio solo conoscere il processo di lavoro interno se utilizziamo l'attributo form, quindi direttamente otterrà il valore e non controllerà alcun uri o formbody ...
Rajneesh

7
Mi chiedo se si potrebbe creare un attributo chiamato JustGetItche serve allo stesso scopo di aggiungere più attributi come [FromBody, FromQuery]ecc.
The Muffin Man

93

Il comportamento predefinito è:

  1. Se il parametro è un primitivo tipo ( int, bool, double, ...), cerca Web API per ottenere il valore dal URI della richiesta HTTP.

  2. Per tipi complessi (il tuo oggetto, ad esempio:) Person, l'API Web tenta di leggere il valore dal corpo della richiesta HTTP.

Quindi, se hai:

  • un tipo primitivo nell'URI o
  • un tipo complesso nel corpo

... quindi non è necessario aggiungere alcun attributo (né [FromBody]né né [FromUri]).

Ma se hai un tipo primitivo nel corpo , devi aggiungere [FromBody]davanti al parametro del tipo primitivo nel metodo del controller WebAPI. (Perché, per impostazione predefinita, WebAPI è alla ricerca di tipi primitivi nell'URI della richiesta HTTP.)

Oppure, se hai un tipo complesso nel tuo URI , devi aggiungere [FromUri]. (Perché, per impostazione predefinita, WebAPI è alla ricerca di tipi complessi nel corpo della richiesta HTTP per impostazione predefinita.)

Tipi primitivi:

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

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

    }       
}

Tipi complessi:

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

    }

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

    }       
}

Funziona finché si invia un solo parametro nella richiesta HTTP. Quando si inviano più , è necessario creare un modello personalizzato con tutti i parametri come questo:

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;
}

Dalla documentazione di Microsoft per l' associazione dei parametri nell'API Web ASP.NET :

Quando un parametro ha [FromBody], l'API Web utilizza l'intestazione Content-Type per selezionare un formattatore. In questo esempio, il tipo di contenuto è "application / json" e il corpo della richiesta è una stringa JSON non elaborata (non un oggetto JSON). Al massimo un parametro può leggere dal corpo del messaggio.

Questo dovrebbe funzionare:

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

Questo non funzionerà:

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

Il motivo di questa regola è che il corpo della richiesta potrebbe essere archiviato in un flusso senza buffer che può essere letto solo una volta.


5
"È consentito leggere al massimo un parametro dal corpo del messaggio" informazioni particolarmente utili
Ryan,

15

Solo aggiunta alle risposte sopra ..

[FromUri] può anche essere usato per legare tipi complessi da parametri uri invece di passare parametri da querystring

Per 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) { ... }
}

Può essere chiamato come:

http://localhost/api/values/47.678558/-122.130989

12

Quando un parametro ha [FromBody], l'API Web utilizza l'intestazione Content-Type per selezionare un formattatore. In questo esempio, il tipo di contenuto è "application / json" e il corpo della richiesta è una stringa JSON non elaborata (non un oggetto JSON).

Al massimo un parametro può leggere dal corpo del messaggio. Quindi questo non funzionerà:

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

Il motivo di questa regola è che il corpo della richiesta potrebbe essere archiviato in un flusso senza buffer che può essere letto solo una volta

Per ulteriori dettagli, visitare il sito Web: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.