¿Puedo pasar un tipo anónimo a mi vista ASP.NET MVC?

Empecé a trabajar con ASP.NET MVC ahora que está en versión beta. En mi código, estoy ejecutando una consulta LINQ a SQL simple para obtener una lista de resultados y pasar eso a mi vista. Este tipo de cosas:

var ords = from o in db.Orders where o.OrderDate == DateTime.Today select o; return View(ords); 

Sin embargo, en mi opinión, me di cuenta de que necesitaría acceder al nombre del cliente para cada pedido. Empecé a usar o.Customer.Name pero estoy bastante seguro de que esto está ejecutando una consulta separada para cada orden (debido a la carga diferida de LINQ).

La forma lógica de reducir el número de consultas sería seleccionar el nombre del cliente al mismo tiempo. Algo como:

 var ords = from o in db.Orders from c in db.Customers where o.OrderDate == DateTime.Today and o.CustomerID == c.CustomerID select new { o.OrderID, /* ... */, c.CustomerName }; return View(ords); 

Excepto que ahora mi variable “ords” es un IEnumerable de tipo anónimo.

¿Es posible declarar una Vista ASP.NET MVC de tal manera que acepte un IEnumerable como su vista de datos donde T se define por lo que pasa desde el controlador, o tendré que definir un tipo concreto para completar desde mi consulta ?

¿Puedes pasarlo a la vista? Sí, pero su vista no estará fuertemente tipada. Pero los ayudantes funcionarán. Por ejemplo:

 public ActionResult Foo() { return View(new {Something="Hey, it worked!"}); } //Using a normal ViewPage <%= Html.TextBox("Something") %> 

Ese cuadro de texto debería mostrar “¡Oye, funcionó!” como el valor.

Entonces, ¿puede definir una vista donde T se define por lo que le pasa desde el controlador? Bueno, sí, pero obviamente no en comstackción.

Piensa un momento en ello. Cuando declaras un tipo de modelo para una vista, obtienes inteligencia para la vista. Eso significa que el tipo debe determinarse en el momento de la comstackción. Pero la pregunta es: ¿podemos determinar el tipo de algo que se le da en el tiempo de ejecución? Claro, pero no con fuerte tipeado preservado.

¿Cómo conseguirías Intellisense para un tipo que ni siquiera conoces? El controlador podría terminar pasando cualquier tipo a la vista mientras está en tiempo de ejecución. Ni siquiera podemos analizar el código y adivinar, porque los filtros de acción podrían cambiar el objeto pasado a la vista por todo lo que sabemos.

Espero que aclare la respuesta sin ofuscarla más. 🙂

Puede pasar tipos anónimos a una vista, solo recuerde lanzar el modelo a una dinámica.

Puedes hacer así:

 return View(new { MyItem = "Hello", SomethingElse = 42, Third = new MyClass(42, "Yes") }) 

En la parte superior de la vista, puedes hacer esto (usando la afeitadora aquí)

 @{ string myItem = (dynamic)Model.MyItem; int somethingElse = (dynamic)Model.SomethingElse; MyClass third = (dynamic)Model.Third; } 

O puede lanzarlos desde ViewData de esta manera:

 @{ var myItem = ViewData.Eval("MyItem") as string var somethingElse = ViewData.Eval("SomethingElse") as int? var third = ViewData.Eval("Third") as MyClass } 

En .NET 4.0, los tipos anónimos se pueden convertir fácilmente a ExpandoObjects y, por lo tanto, todos los problemas se solucionan con la sobrecarga de la conversión. Mira aquí

Por lo que vale, esta noche descubrí la clase DataLoadOptions y su método LoadWith . Pude decirle a mi LINQ to SQL DataContext que siempre cargue una fila de clientes cada vez que se recupera una fila de pedidos, por lo que la consulta original ahora obtiene todo lo que necesito en un solo golpe.

Aquí hay un artículo explicando sobre pasar el tipo Anónimo a Vistas y vinculando los datos.

Gracias

Esta publicación muestra cómo puede devolver un tipo anónimo desde un método, pero no va a satisfacer sus requisitos.

Otra opción puede ser convertir el tipo anónimo en JSON (JavaScriptSerializer lo hará) y luego devolver ese JSON a la vista, entonces necesitaría algo de jQuery, etc. para hacer lo que quiera con él.

He estado utilizando Linq para “dar forma” a mis datos en un formato JSON que mi vista necesita con gran éxito.

Puede escribir una clase con las mismas propiedades de su tipo anónimo, y puede convertir su tipo anónimo en su tipo escrito a mano. El inconveniente es que tiene que actualizar la clase cuando realiza cambios de proyección en su consulta de linq.

es posible que pueda pasar un Objeto y usar la reflexión para obtener los resultados deseados. Eche un vistazo a ObjectDumper.cs (incluido en csharpexamples.zip) para ver un ejemplo de esto.

Si no me equivoco, los tipos anónimos se convierten en objetos fuertemente tipificados en tiempo de comstackción. Sin embargo, si el objeto fuertemente tipado es válido para ver datos es otra pregunta.

Estoy con el mismo problema … después de pensar un poco, llegué a la conclusión de que la solución más correcta y escalable es serializar este tipo anónimo antes de enviarlo a la Vista. Por lo tanto, puede usar el mismo método para llenar la página usando el código Ver detrás y llenar su página usando JSON

Recuerde: anonymous tipos anonymous son internos, lo que significa que sus propiedades no se pueden ver fuera de su ensamblado de definición.

Será mejor que pase dynamic objeto dynamic (en lugar de uno anonymous ) a su View convirtiendo el tipo anonymous en dynamic , utilizando un método de extensión.

 public class AwesomeController : Controller { // Other actions omitted... public ActionResult SlotCreationSucceeded(string email, string roles) { return View("SlotCreationSucceeded", new { email, roles }.ToDynamic()); } } 

El método de extensión sería así:

 public static class DynamicExtensions { public static dynamic ToDynamic(this object value) { IDictionary expando = new ExpandoObject(); foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) expando.Add(property.Name, property.GetValue(value)); return (ExpandoObject) expando; } } 

Sin embargo, aún puede pasar un objeto anonymous , pero tendrá que convertirlo en uno dynamic .

 public class AwesomeController : Controller { // Other actions omitted... public ActionResult SlotCreationSucceeded(string email, string roles) { return View("SlotCreationSucceeded", new { email, roles }); } } 

Ver:

 @{ var anonymousModel = DynamicUtil.ToAnonymous(Model, new { email = default(string), roles = default(string) }); } 

@anonymousModel.email

@anonymousModel.roles

El método de ayuda se vería así:

 public class DynamicUtil { public static T ToAnonymous(ExpandoObject source, T sample) where T : class { var dict = (IDictionary) source; var ctor = sample.GetType().GetConstructors().Single(); var parameters = ctor.GetParameters(); var parameterValues = parameters.Select(p => dict[p.Name]).ToArray(); return (T) ctor.Invoke(parameterValues); } }