
Model Binding en ASP.Net Core
- ASP.Net Core
Cuando trabajamos con aplicaciones web en ASP.Net Core, una de los requerimientos más comunes es recibir datos desde una solicitud HTTP y convertirlos en objetos que podamos usar en el código de nuestra aplicación.
ASP.Net Core te facilita mucho este proceso mediante un proceso llamado Model Binding. En este post explicaré brevemente cuales son las partes fundamentales de dicho proceso y cuándo es necesario que le des una mano 🫱 a ASP.Net Core para que tus datos sean asignados correctamente a tus objetos.
Esencialmente, el sistema de model binding:
- Recopila la data de varias fuentes como rutas, campos de formulario, entre otras. Hablaremos más de las fuentes más adelante.
- Convierte la data que, como sabemos, viene como string a tipos .Net.
- Provee dicha data a los objetivos del model binding, es decir, a controladores o a páginas Razor, específicamente en parámetros de métodos o propiedades públicas de estos. También puede actualizar propiedades de tipos complejos.
De la documentación de ASP.Net Core sobre Model Binding traemos el siguiente ejemplo:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
La aplicación recibe la siguiente petición HTTP
https://contoso.com/api/pets/2?DogsOnly=true
El model binding realiza entonces los siguientes pasos
- Encuentra el primer parámetro de GetById, un entero llamado id.
- Revisa las fuentes disponibles en la solicitud HTTP y encuentra id = "2" en los datos de la ruta.
- Convierte la cadena "2" en el entero 2.
- Encuentra el siguiente parámetro de GetById, un booleano llamado dogsOnly.
- Busca en las fuentes y encuentra "DogsOnly=true" en la cadena de consulta. (La coincidencia de nombres no distingue entre mayúsculas y minúsculas)
- Convierte la cadena "true" en el booleano true.
Seguidamente el framework llama al método GetById, pasando 2 y true como los argumentos para los parámetros id y dogsOnly, respectivamente.
Componentes del Model Binding
Ahora que conocemos el proceso, vamos a analizar qué componentes juegan en el proceso de model binding
Objetivos o destinos
La data recopilada durante el proceso de model binding tiene los siguientes destinos:
- Parámetros del método de acción al cual la petición ha sido enrutada en un controlador.
- Parámetros del método handler al cual la petición ha sido enrutada en una página Razor.
- Propiedades públicas de un controlador o una clase PageModel si así es especificado mediante atributos ([BindProperty], [BindProperties])
Fuentes
Por defecto, las fuentes que utiliza el proceso de Model Binding para obtener información en una petición HTTP son las siguientes:
- Campos de formulario
- El cuerpo de la petición (dentro de un controlador que emplee el atributo [ApiController])
- Data de la ruta
- Parametros query string
- Archivos cargados
Estas fuentes son escaneadas en el orden en que están listadas.
Pero, al principio del post dije que había veces donde debíamos darle una mano 🫱 a ASP.Net Core en este proceso verdad? Pues sí y tiene mucho que ver con las fuentes, ya que estas tienen algunas excepciones a tener en cuenta.
La data de la ruta y los valores query string son usados solamente para tipos simples. Para poder recibir tipos complejos debemos especificarselo a ASP.Net Core usando el atributo [FromQuery]
Los archivos cargados serán asignados a objetivos que implementen las interfaces IFormFile o IEnumerable<IFormFile> por lo que debemos recordar esto al escribir nuestro código.
Si queremos leer el body, también debemos ayudar a ASP.Net Core. Como se menciona arriba, el body será utilizado como fuente sólo en controladores que empleen el atributo [ApiController]. Adicionalmente, si trabajamos con este atributo nos compete tomar en consideración como su uso modifica un poco las fuentes por defecto:
- [FromBody] se infiere para parámetros de tipo complejo (si estos no están registrados en el contenedor de inyección de dependencias, de lo contrario se infiere [FromService]).
- [FromBody] no se infiere para parámetros de tipo simple, por lo tanto, de así desearlo, debemos agregarlo nosotros explícitamente.
- [FromForm] se infiere para parametros de tipo IFormFile y IFormCollection
- [FromRoute] se infiere para los parámetros cuyo nombre haga match con un dato o parámetro de la plantilla de ruta.
- [FromQuery] se infiere para cualquier otro parámetro.
Y con eso finalizamos este post. El tema del model binding es bastante extenso, sin mencionar que existen maneras de personalizar este proceso, nuestro post no alcanzaría a cubrirlo todo, pero te invito a que leas la documentación de ASP.Net Core donde se explora a profundidad este mecanismo y se cubren diversos casos de uso.
Esperando que esto te sea de utilidad, me despido, nos vemos en futuros posts 👋🏼.