Por que precisamos especificar FromBody e FromUri?

157

Por que os atributos FromBodye FromUrisão necessários na API da Web do ASP.NET?

Quais são as diferenças entre usar os atributos e não usá-los?

Rajneesh
fonte
11
Apenas para dar uma dica de quando pode ser útil usar a anotação [FromBody]: Por exemplo, é uma prática inadequada enviar credenciais estáticas, como nome de usuário / senha, como parâmetros codificados no URL. Embora a criptografia SSL possa impedir que terceiros obtenham acesso de leitura aos parâmetros na URL, ainda é uma prática inadequada, pois essas credenciais podem ser armazenadas nos logs do navegador e iguais, o que definitivamente não é desejado. Nesse caso, pode-se usar a anotação [FromBody], para forçar o armazenamento de um parâmetro no corpo da mensagem HTTP, introduzindo um valor alto.
Chris

Respostas:

193

Quando a API da Web do ASP.NET chama um método em um controlador, deve definir valores para os parâmetros, um processo chamado ligação de parâmetro .

Por padrão, a API da Web usa as seguintes regras para ligar parâmetros:

  • Se o parâmetro for do tipo "simples" , a API da Web tentará obter o valor do URI . Tipos simples incluem os tipos primitivos do .NET (int, bool, double e assim por diante), além de TimeSpan, DateTime, Guid, decimal e string, além de qualquer tipo com um conversor de tipo que possa converter de uma string.

  • Para tipos complexos , a API da Web tenta ler o valor do corpo da mensagem , usando um formatador de tipo de mídia.

Portanto, se você deseja substituir o comportamento padrão acima e forçar a API da Web a ler um tipo complexo a partir do URI, adicione o [FromUri]atributo ao parâmetro Para forçar a API da Web a ler um tipo simples do corpo da solicitação, adicione o [FromBody]atributo ao parâmetro

Portanto, para responder sua pergunta, a necessidade dos atributos [FromBody]e [FromUri]na API da Web é simplesmente substituir, se necessário, o comportamento padrão conforme descrito acima. Observe que você pode usar os dois atributos para um método do controlador, mas apenas para parâmetros diferentes, conforme demonstrado aqui .

muito mais informações na web se você pesquisar no Google "vinculação de parâmetros da API da Web".

djikay
fonte
2
@ user3510527: Você não precisa usar esses atributos se não quiser, desde que siga o comportamento padrão. Se você quiser alterar o comportamento padrão, precisará usá-los.
djikay
1
se está fazendo seu comportamento padrão, por que precisamos prevalecer e que benefícios obteremos se mencionarmos esse atributo?
Rajneesh
1
@ user3510527 Você não precisa substituir. Você pode apenas usar o comportamento padrão. Um exemplo em que alguém pode querer substituir é se deseja fornecer um número inteiro simples no corpo da solicitação porque, por padrão, ele espera encontrá-lo no URI. Basicamente, você pode simplesmente deixar o comportamento padrão, se quiser ou pode substituir, é apenas uma opção que você possui. Não entendo qual é a confusão.
djikay
Eu só quero saber o processo de trabalho interno, se usarmos o atributo forma, tão diretamente que irá receber o valor e não verificar qualquer uri ou formbody ...
Rajneesh
7
Gostaria de saber se alguém poderia fazer um atributo chamado JustGetItque serve a mesma finalidade de adicionar vários atributos como [FromBody, FromQuery]etc
The Muffin Man
93

O comportamento padrão é:

  1. Se o parâmetro é um primitivo tipo ( int, bool, double, ...), tentativas Web API para obter o valor do URI da solicitação HTTP.

  2. Para tipos complexos (seu próprio objeto, por exemplo Person:), a API da Web tenta ler o valor do corpo da solicitação HTTP.

Então, se você tem:

  • um tipo primitivo no URI, ou
  • um tipo complexo no corpo

... então você não precisa adicionar nenhum atributo (nem [FromBody]nem [FromUri]).

Mas, se você tiver um tipo primitivo no corpo , precisará adicionar [FromBody]na frente do seu parâmetro de tipo primitivo no método do controlador WebAPI. (Como, por padrão, o WebAPI está procurando tipos primitivos no URI da solicitação HTTP).

Ou, se você tiver um tipo complexo em seu URI , deverá adicionar [FromUri]. (Como, por padrão, o WebAPI está procurando tipos complexos no corpo da solicitação HTTP, por padrão).

Tipos primitivos:

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

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

    }       
}

Tipos complexos:

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

    }

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

    }       
}

Isso funciona desde que você envie apenas um parâmetro na sua solicitação HTTP. Ao enviar vários , você precisa criar um modelo personalizado com todos os seus parâmetros como este:

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

Na documentação da Microsoft para ligação de parâmetros na API da Web do ASP.NET :

Quando um parâmetro possui [FromBody], a API da Web usa o cabeçalho Content-Type para selecionar um formatador. Neste exemplo, o tipo de conteúdo é "application / json" e o corpo da solicitação é uma sequência JSON bruta (não um objeto JSON). No máximo, um parâmetro pode ler do corpo da mensagem.

Isso deve funcionar:

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

Isso não vai funcionar:

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

O motivo dessa regra é que o corpo da solicitação pode ser armazenado em um fluxo sem buffer que pode ser lido apenas uma vez.

Tadej
fonte
5
"No máximo, um parâmetro pode ser lido no corpo da mensagem" foi uma informação especialmente útil
Ryan
15

Apenas adição às respostas acima ..

[FromUri] também pode ser usado para vincular tipos complexos a partir de parâmetros uri em vez de passar parâmetros da querystring

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

Pode ser chamado como:

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

Quando um parâmetro possui [FromBody], a API da Web usa o cabeçalho Content-Type para selecionar um formatador. Neste exemplo, o tipo de conteúdo é "application / json" e o corpo da solicitação é uma sequência JSON bruta (não um objeto JSON).

No máximo, um parâmetro pode ler do corpo da mensagem. Portanto, isso não vai funcionar:

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

O motivo dessa regra é que o corpo da solicitação pode ser armazenado em um fluxo sem buffer que pode ser lido apenas uma vez

Visite o site para obter mais detalhes: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

user5166729
fonte