Tutorial :Multiple models sent to a single view instance


My terminology is probably way off here but basically I'm trying to pass multiple data models to a view. To help put the question in context, take this example:

Say I was making a blog. When I log in I want the home screen to display a list of all new unapproved comments, as well as a list of recently registered users, and a list of the most recently submitted blog posts.

Most discussions I've seen suggest strongly-typing the view page so it can be called with something like "return View(RecentComments)" and iterate through the comments in the view, or to cast the data model like "var NewUsers = (MembershipUserCollection) ViewData.Model". What I'm ideally after is the 'right', or at least a 'right-enough', way of passing multiple models while still maintaining appropriate logic separation.


One way is to create a new type that encapsulates both pieces of model data:

public class MyBigViewData {      public SubData1 SubData1 { get; set; }      public SubData2 SubData2 { get; set; }  }    public class SubData1 {      ... more properties here ...  }    public class SubData2 {      ... more properties here ...  }  

Another way is to store the "main" model data as the strongly-typed data and store other data in the view data as dictionary items:

ViewData["username"] = "joe"; // "other" data  ViewData["something"] = "whatever"; // "other" data  ViewData["subdata1"] = new SubData1(...);  return View(myRealModelData);  

The advantage of the second approach is that you don't need to do anything special at all: It works right out of the box.


What I've done in the past is written a class that contained instances of both the classes I will need on the view.


public class City{  public Mall TheMall;  public School TheSchool;  }  

Then your view will be strongly typed as City, and you will use Model.TheMall.Property and Model.TheSchool.Property to access what you need


This is an example of what other posters mean by creating an object with both objects as fields/properties


Sadly, the only way to accomplish passing multiple objects is either by creating an object with both objects as fields/properties, or by using a weakly typed array.


The way to pass multiple models to a view is to create what we call a Form View Model which has your other models within it.

Then in your view you can pass the individual models contained in your Form View Model to the Partial Views responsible for rendering the data in said models.

Makes sense?


btw: a form view model is simply a class. it's not a special type as may have been suggested by my answer.


In addition to my other answer, another way to do this would be not to strongly-type the view and master pages in the page directive, but instead make use of the generic type-based ViewData extensions from MVC Contrib. These extensions basically use the fully-qualified type name as the ViewData dictionary key. Effectively, the typing benefits are the same as the strongly-typed page approach, with less class overhead in terms of the number of view model classes required. Then in your actions you do

ViewData.Add<Car>(car);  ViewData.Add<LayoutAData>(layoutAData);  

and in the views you do

<%= ViewData.Get<Car>().Color %>  

and in the master page you do

<%= ViewData.Get<LayoutAData>().Username %>  

You could cache these Get<> calls inline in the views to mitigate the cost of casting multiple times.


After working on a large ASP.NET MVC app, I found the approach that was most productive while minimizing runtime casting was based on using generics to mimic the nested structure of views. Essentially views get their own data type. Typically these are either domain objects, or collections of domain objects that include metadata. Generic versions of these types are available across all possible master pages, taking a type parameter that defines data relevant to the master page.

public class Car {    // can be used as a model  }     public class CarCollection: Collection<Car> {    public BodyTypes BodyType {get;set;}    public Colors Color {get;set;}    // can also be used as a model  }    public interface ILayoutModel<TLayout> {    TLayout LayoutModel {get;set;}  }    public class CarView<TLayout>: Car, ILayoutModel<TLayout>  {    // model that can be used with strongly-typed master page  }    public class CarCollection<TLayout> : CarCollection, ILayoutModel<TLayout> {    // model that can be used with strongly-typed master page  }    public class LayoutAData {    // model for LayoutA.master  }    public class LayoutBData {    // model for LayoutB.master  }  

It's also possible to invert the generic-ness, but since the view dictates the layout, the view data should dominate over the layout data in my opinion. LayoutA.master would derive from ViewMasterPage<ILayoutModel<LayoutAData>> and LayoutB.master would derive from ViewMasterPage<ILayoutModel<LayoutBData>>. This keeps the view data and the layout data separate, in a consistent, strongly-typed and flexible way.


Creating an object that can encapsulate your other objects is the best way to go. Otherwise you're stuck with a bunch of ugly ViewData tags in the controller and the view.


One thing no one seems to have mentioned is that in the original questioners example, it might make sense to create the view out of a series of child actions that handle their own area of functionality rather than making a mega view model. That way the components such as unnapproved messages etc can be reused.

This also gives better encapsulation.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »