¿Por qué tenemos que especificar FromBody y FromUri?

157

¿Por qué son necesarios los atributos FromBodyy FromUrien ASP.NET Web API`?

¿Cuáles son las diferencias entre usar los atributos y no usarlos?

Rajneesh
fuente
11
Solo para dar una pista sobre cuándo podría ser útil usar la anotación [FromBody]: por ejemplo, es una mala práctica enviar credenciales estáticas como nombre de usuario / contraseña como parámetros codificados dentro de la URL. Aunque el cifrado SSL podría evitar que un tercero pueda obtener acceso de lectura a los parámetros dentro de la URL, sigue siendo una mala práctica, ya que estas credenciales pueden almacenarse en registros e iguales del navegador, lo que definitivamente no es deseable. En tal caso, uno podría usar la anotación [FromBody], para forzar el almacenamiento de un parámetro dentro del cuerpo del mensaje HTTP, introduciendo un alto
Chris

Respuestas:

193

Cuando la API web ASP.NET llama a un método en un controlador, debe establecer valores para los parámetros, un proceso llamado enlace de parámetros .

De forma predeterminada, la API web utiliza las siguientes reglas para enlazar parámetros:

  • Si el parámetro es de tipo "simple" , la API web intenta obtener el valor del URI . Los tipos simples incluyen los tipos primitivos .NET (int, bool, double, etc.), más TimeSpan, DateTime, Guid, decimal y string, más cualquier tipo con un convertidor de tipos que se pueda convertir de una cadena.

  • Para los tipos complejos , la API web intenta leer el valor del cuerpo del mensaje , utilizando un formateador de tipo multimedia.

Por lo tanto, si desea anular el comportamiento predeterminado anterior y obligar a la API web a leer un tipo complejo del URI, agregue el [FromUri]atributo al parámetro. Para obligar a la API web a leer un tipo simple del cuerpo de la solicitud, agregue el [FromBody]atributo al parámetro.

Entonces, para responder a su pregunta, la necesidad de los atributos [FromBody]y [FromUri]en la API web es simplemente anular, si es necesario, el comportamiento predeterminado como se describió anteriormente. Tenga en cuenta que puede usar ambos atributos para un método de controlador, pero solo para diferentes parámetros, como se demuestra aquí .

Hay mucha más información en la web si buscas en Google "enlace de parámetros de API web".

djikay
fuente
2
@ user3510527: no tiene que usar estos atributos si no lo desea, siempre que siga el comportamiento predeterminado. Si desea cambiar el comportamiento predeterminado, debe usarlos.
djikay
1
si está haciendo su comportamiento predeterminado, entonces ¿por qué necesitamos anular y qué beneficios obtendremos si mencionamos este atributo?
Rajneesh
1
@ user3510527 No necesita anular. Simplemente puede usar el comportamiento predeterminado. Un ejemplo en el que alguien podría querer anular es si desea proporcionar un número entero simple en el cuerpo de la solicitud porque, por defecto, esperará encontrarlo en el URI. Básicamente, puede dejar el comportamiento predeterminado si lo desea o puede anular, es solo una opción que tiene. No entiendo cuál es la confusión.
djikay
Solo quiero saber el proceso de trabajo interno si utilizamos el atributo de formulario, por lo que directamente obtendrá el valor y no comprobará ningún uri o cuerpo ...
Rajneesh
77
Me pregunto si uno podría hacer un atributo llamado JustGetItque tenga el mismo propósito de agregar múltiples atributos como [FromBody, FromQuery]etc.
The Muffin Man
93

El comportamiento predeterminado es:

  1. Si el parámetro es un primitivo tipo ( int, bool, double, ...), intentos de API Web para obtener el valor de la URI de la petición HTTP.

  2. Para los tipos complejos (su propio objeto, por ejemplo:) Person, la API web intenta leer el valor del cuerpo de la solicitud HTTP.

Entonces, si tienes:

  • un tipo primitivo en el URI, o
  • un tipo complejo en el cuerpo

... entonces no tiene que agregar ningún atributo (ni [FromBody]tampoco [FromUri]).

Pero, si tiene un tipo primitivo en el cuerpo , entonces debe agregar [FromBody]delante de su parámetro de tipo primitivo en su método de controlador WebAPI. (Porque, de forma predeterminada, WebAPI está buscando tipos primitivos en el URI de la solicitud HTTP).

O, si tiene un tipo complejo en su URI , entonces debe agregar [FromUri]. (Porque, de forma predeterminada, WebAPI está buscando tipos complejos en el cuerpo de la solicitud HTTP de forma predeterminada).

Tipos primitivos:

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

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

    }       
}

Tipos complejos:

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

    }

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

    }       
}

Esto funciona siempre que envíe solo un parámetro en su solicitud HTTP. Al enviar múltiples , debe crear un modelo personalizado que tenga todos sus 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;
}

De la documentación de Microsoft para el enlace de parámetros en la API web ASP.NET :

Cuando un parámetro tiene [FromBody], la API web usa el encabezado Content-Type para seleccionar un formateador. En este ejemplo, el tipo de contenido es "application / json" y el cuerpo de la solicitud es una cadena JSON sin formato (no un objeto JSON). Como máximo, se permite leer un parámetro del cuerpo del mensaje.

Esto debería funcionar:

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

Esto no funcionará:

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

El motivo de esta regla es que el cuerpo de la solicitud puede almacenarse en una secuencia no almacenada en el búfer que solo se puede leer una vez.

Tadej
fuente
55
"Como máximo se permite leer un parámetro del cuerpo del mensaje" fue información especialmente útil
Ryan
15

Solo adición a las respuestas anteriores.

[FromUri] también se puede usar para enlazar tipos complejos a partir de parámetros uri en lugar de pasar parámetros desde la cadena de consulta

Por ej.

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

Se puede llamar como:

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

Cuando un parámetro tiene [FromBody], la API web usa el encabezado Content-Type para seleccionar un formateador. En este ejemplo, el tipo de contenido es "application / json" y el cuerpo de la solicitud es una cadena JSON sin formato (no un objeto JSON).

Como máximo, se permite leer un parámetro del cuerpo del mensaje. Entonces esto no funcionará:

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

La razón de esta regla es que el cuerpo de la solicitud puede almacenarse en una secuencia no almacenada en el búfer que solo se puede leer una vez

Visite el sitio web para obtener más detalles: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

usuario5166729
fuente