Meme de hulk dando un taco. Se reemplaza a Hulk por el logo de .Net y el taco por un texto que dice "Model Binding"

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:

  1. Campos de formulario
  2. El cuerpo de la petición (dentro de un controlador que emplee el atributo [ApiController])
  3. Data de la ruta
  4. Parametros query string
  5. 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 👋🏼.

Sobre mí

Desarrollador full-stack .Net y JavaScript con más de tres años de experiencia utilizando la tecnología para resolver problemas del mundo real. Cuento con conocimientos en ASP.Net Core, Express.js y Nest.js para el desarrollo de APIs, así como en Angular, React y WPF para la creación de aplicaciones web y de escritorio intuitivas.

Este blog para mi es una suerte de apuntes que voy tomando a medida que realizo mi viaje por el mundo de la tecnología. Y quise compartir estos apuntes con el mundo por este medio, esperando que sean de utilidad a otros. Como no existen apuntes perfectos, cualquier sugerencia sobre algún tema de los que hablo acá será bien recibida, no dudes en contactarme a traves de alguno de los canales listado acá abajo.

Adicionalmente, actualmente me encuentro en abierto a oportunidades y roles, donde pueda contribuir activamente, con mi experiencia y conocimiento.

Contáctame

Email: 28enriqueperez@gmail.com