Puis-je transmettre un type anonyme à ma vue ASP.NET MVC?

Je viens de commencer à travailler avec ASP.NET MVC maintenant qu’il est en bêta. Dans mon code, j’exécute une simple requête LINQ to SQL pour obtenir une liste de résultats et la transmettre à ma vue. Ce genre de chose:

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

Cependant, dans ma vue, je me suis rendu compte que je devais accéder au nom du client pour chaque commande. J’ai commencé à utiliser o.Customer.Name mais je suis o.Customer.Name certain que cela exécute une requête distincte pour chaque commande (à cause du chargement paresseux de LINQ).

La manière logique de réduire le nombre de requêtes serait de sélectionner le nom du client en même temps. Quelque chose comme:

 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); 

Sauf que maintenant ma variable “ords” est un IEnumerable de type anonyme.

Est-il possible de déclarer une vue ASP.NET MVC de manière à ce qu’elle accepte un IEnumerable comme vue, où T est défini par ce qui est passé par le contrôleur ou devrais-je définir un type concret à remplir à partir de ma requête? ?

Pouvez-vous le transmettre à la vue? Oui, mais votre vue ne sera pas fortement typée. Mais les assistants vont travailler. Par exemple:

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

Cette zone de texte devrait rendre “Hey, ça a marché!” comme valeur.

Alors pouvez-vous définir une vue où T est défini par ce qui lui est transmis par le contrôleur? Eh bien oui, mais pas à la compilation évidemment.

Pensez-y un instant. Lorsque vous déclarez un type de modèle pour une vue, vous obtenez l’intelligence de la vue. Cela signifie que le type doit être déterminé au moment de la compilation. Mais la question demande, peut-on déterminer le type de quelque chose qui lui a été donné au moment de l’exécution. Bien sûr, mais pas avec un fort typage préservé.

Comment obtiendriez-vous Intellisense pour un type que vous ne connaissez même pas encore? Le contrôleur pourrait finir par transmettre n’importe quel type à la vue pendant l’exécution. Nous ne pouvons même pas parsingr le code et deviner, car les filtres d’action pourraient changer l’object transmis à la vue pour tout ce que nous connaissons.

J’espère que cela clarifie la réponse sans la rendre plus obscure. 🙂

Vous pouvez transmettre des types anonymes à une vue, mais n’oubliez pas de convertir le modèle en dynamic.

Vous pouvez faire comme ça:

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

En haut de la vue, vous pouvez faire cela (en utilisant le razor ici)

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

Ou vous pouvez les lancer depuis le ViewData comme ceci:

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

Sur .NET 4.0, les types anonymes peuvent facilement être convertis en ExpandoObjects et tous les problèmes sont résolus avec la surcharge de la conversion elle-même. Découvrez ici

Pour ce que ça vaut, ce soir, j’ai découvert la classe DataLoadOptions et sa méthode LoadWith . J’ai été en mesure de dire à mon LINQ to SQL DataContext de toujours charger une ligne Customers à chaque fois qu’une ligne Orders est extraite, de sorte que la requête d’origine obtienne désormais tout ce dont j’ai besoin en un seul clic.

Voici un article expliquant comment transmettre le type anonyme aux vues et lier les données.

Merci

Cet article montre comment vous pouvez renvoyer un type anonyme à partir d’une méthode, mais cela ne vous convient pas.

Une autre option pourrait consister à convertir le type anonyme en JSON (JavaScriptSerializer le fera), puis à renvoyer ce JSON dans la vue, vous auriez alors besoin de jQuery etc. pour faire ce que vous voulez avec.

J’ai utilisé Linq pour «modeler» mes données dans un format JSON dont ma vue a besoin avec succès.

Vous pouvez écrire une classe avec les mêmes propriétés que votre type anonyme, et vous pouvez convertir votre type anonyme en votre type écrit à la main. L’inconvénient est que vous devez mettre à jour la classe lorsque vous effectuez des modifications de projection dans votre requête linq.

vous pourrez peut-être passer un object et utiliser la reflection pour obtenir les résultats souhaités. Jetez un oeil à ObjectDumper.cs (inclus dans csharpexamples.zip) pour un exemple de cela.

Si je ne me trompe pas, les types anonymes sont convertis en objects fortement typés au moment de la compilation. La question de savoir si l’object fortement typé est valide pour les données de vue est une autre question.

Je suis avec le même problème … après avoir réfléchi un peu, je suis arrivé à la conclusion que la solution la plus correcte et la plus évolutive, c’est de sérialiser ce type anonyme avant de l’envoyer à la vue. Ainsi, vous pouvez utiliser la même méthode pour remplir la page à l’aide du code View derrière et pour remplir votre page à l’aide de JSON

Rappelez-vous: les types anonymous sont internes, ce qui signifie que leurs propriétés ne peuvent pas être vues en dehors de leur assemblage de définition.

Vous feriez mieux de passer dynamic object dynamic (au lieu d’un object anonymous ) à votre View en convertissant le type anonymous en dynamic , en utilisant une méthode d’extension.

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

La méthode d’extension ressemblerait à ceci:

 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; } } 

Néanmoins, vous pouvez toujours passer un object anonymous , mais vous devrez le convertir en un object dynamic .

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

Vue:

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

@anonymousModel.email

@anonymousModel.roles

La méthode d’assistance ressemblerait à ceci:

 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); } }