En este post vamos a tratar de explicar como pasar varios modelos a una vista de MVC. Para ello utilizaremos una carecteristica de .Net Framework, el modelo dinámico con el objeto expando.

¿Se pueden pasar múltiples modelos a una vista?

La respuesta es sí, aunque MVC esté preparado para pasar un único modelo a la vista, podemos pasar otros modelos de varias formas:

  1. Creando una nueva clase view model, dicha clase tendrá dos propiedades que referenciaran los dos modelos con los que necesitemos trabajar. Con este modelo personalizado podremos añadir y trabajar con ambos modelos en la vista.
  1. Otra opción sería pasár el modelo con un ViewBag, la desventaja es que al pasar un modelo por ViewBag (o ViewData) no será parte del modelo de la vista.
ViewbagModelo.png
  1. La tercera opción sería de lo que trata este post, un modelo dinámico con el ExpandoObject.
ListaAnonima.png

Como se observa en la imagen, en esa consulta estamos devolviendo un tipo anónimo y aunque la consulta funcionaria sin problemas, no se permite pasar tipos anónimos las vistas MVC. Una solución a este problema es al igual que en la primera opción, crearse un nuevo modelo personalizado y pasarle dicho modelo a la vista. Pero si no queremos crear tantos modelos podemos recurrir al objeto expando.

La palabra clave dynamic se puede usar para mantener un objeto donde podamos definir las propiedades, sin tener que definir primero la clase. Lo que no podemos hacer con un objeto dinámico es agregarle propiedades después de que el objeto se haya inicializado. Para esto C# viene con una solución: el ExpandoObject.

¿Qué es el objeto Expando?

El objeto Expando(perteneciente a System.Dynamic) es una clase que se agregó a .Net Framework 4.0, esta clase nos permite agregar y eliminar dinámicamente propiedades en un objeto en tiempo de ejecución. Al usar el objeto Expando, podemos agregar nuestras clases de modelo en un objeto Expando creado dinámicamente.

VariableDinamica.png

El código de la imagen anterior crea un objeto expando y le asigna propiedades que en este caso almacenaran en una lista los modelos con los que trabajamos.

Declaramos la variable de tipo dinámico a pesar de que la instanciamos como ExpandoObject, la razón para esto es que si la declaramos como objeto expando, el compilador la comprueba y falla al echar en falta las propiedades que estamos inventando.

VariableExpandoError.png

Esto se evita poniendo la variable de tipo dinámica ya que evita que el compilador verifique la existencia de las propiedades. El objeto expando también puede tener propiedades que a su vez son ExpandoObject, lo que permite crear tipos complejos sobre la marcha.

VariableDinamicaCompleja.png

Cuando pasemos el modelo a la vista, recuperaremos el contenido de la siguente forma:

ModeloDinamicoVista.png

Como se observa en la imagen el tipo de modelo es dynamic aunque en este caso no haría falta ponerlo ya que Razor tiene el valor dynamic como predeterminado.

Con un bucle foreach podemos sacar el contenido del modelo buscando en cada una de sus propiedades. Hay que tener en cuenta que, una de las desventajas de este tipo de modelos es, que no tiene un intellisense funcional, por lo que hay que tener mucho cuidado al escribir los nombres de las propiedades para no equivocarnos o provocara una excepción.

Almacenar objetos anónimos en un objeto de Expando

Anteriormente hemos visto como almacenar objetos de un modelo ya creado en un objeto expando, ahora veremos cómo almacenar un objeto anónimo.

Primero creamos un objeto anónimo con varias propiedades, luego lo pasaremos por un método que lo convertirá a un objeto de tipo IDictionary<string,object>.

CrearObjAnonimoConPropiedades.png

Dicho método creara un ExpandoObject, pero lo captara como el IDictionary mencionado antes, después, un bucle foreach recorrerá las propiedades del objeto anónimo que le hayamos pasado. Esto lo hará usando las clases PropertyDescriptor y TypeDescriptor de System.ComponentModel. Estas clases permiten obtener información adicional sobre las características de un objeto.

MetodoIDictionary.png

Todas las propiedades del objeto se transfieren al objeto expando que hemos creado anteriormente. Finalmente al acabar el bucle devolvemos el objeto expando con todas las propiedades añadidas.

La forma de mostrar los datos en la vista es exactamente como vimos antes.

IDictionaryVista.png

Esto funcionaria si solo queremos convertir un único objeto anónimo, pero, ¿y si deseáramos convertir toda una colección de objetos anónimos?

El código sería como el anterior pero devolveremos una lista de objetos de tipo ExpandoObject a la que pasaremos un parámetro de tipo IQueryable<object>. Este tipo permite evaluar consultas con respecto a un origen de datos concreto en el que se conoce el tipo de datos.

MetodoListExpando.png

Cada “itemExpando” contiene datos que pertenecen a un único objeto anónimo.

En el controlador crearemos una variable dinámica de tipo ExpandoObejct, a la que iremos añadiendo las propiedades que necesitemos, pasandolas primero por el método creado anteriormente.

ColeccionExpando_Controller.png

Los datos se recuperan en la vista de la siguiente forma:

ListaExpandoVista.png

Como se puede comprobar, con esta fórmula hemos podido capturar datos de dos modelos diferentes sin necesidad de crear un modelo extra que contuviera los otros dos.

EjecucionVistaListaExpando.png

Resumen

El tipo ExpandoObejct permite definir objetos sobre la marcha para posteriormente agregarle propiedades cuando lo desees. Al ser un tipo dinámico hereda las ventajas y desventajas de estos tipos.

Puede cambiar el tipo de la variable fácilmente asignándole un nuevo valor y de no ser el mismo tipo, automáticamente este cambiara al nuevo. El compilador no verifica las variables dinámicas lo que permite acceder a propiedades que pueden estar o no presentes, esto lo hace flexible pero vulnerable a los errores.

Existen limitaciones cuando se usa un modelo dinámico, como la falta de soporte inteligente, falta de verificación de errores en tiempo de compilación y también falta de soporte para usarlo con expresiones Lambda.

La mayoría de las veces, decoramos las propiedades de nuestros modelos con atributos, que tampoco es posible cuando se usa un modelo dinámico. Pero hay una solución alternativa en lo que respecta a los atributos para la validación del lado del cliente. Los atributos en la propiedad de un modelo se traducen finalmente en atributos html en los campos de entrada. Podemos crear nuestra propia extensión de control y agregar exactamente los atributos HTML que se agregan por los atributos en las propiedades. La validación de JavaScript analizará esto y activará la validación requerida.

En definitiva, usar modelos dinámicos puede ser útil para ocasiones en las que no nos quede otro remedio o no queramos hacer modelos personalizados, pero lo más recomendable y seguro es crear el modelo personalizado(ViewModel).

Autor: Alberto Mingo Hernández.

Curso: Microsoft MCSA Web Applications + Microsoft MCSD App Builder +
Xamarin.

Centro: Tajamar.

Año académico: 2019-2020.

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.