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.
ie
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
EDIT
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?
edit
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.
Related
I have a model class named Server, it contains many navigation properties and properties, which I want to prevent users from binding it. So I find two approaches of doing so to avoid over-posting attacks.
The first approach is to go to each model class and define an Exclude Bind list , with all the properties and navigating properties that should not be bind by users , as follow:-
[MetadataType(typeof(TMSServer_Validation))]
[Bind(Exclude = "Technology,IT360SiteID, VirtualMachines, TMSServer1,DataCenter,OperatingSystem,Rack,ServerModel,TechnologyBackUpStatu,TechnologyRole,TechnologyStatu ")]
public partial class Server {
}
}
The second approach is to create a view model class , with only the properties that can be modified by users as follow:-
public class ServerViewModel
{
public int ServerSize { get; set; }
[Required]
public String OperatingSystem { get; set; }
public String Commnet { get; set; }
}
I find that the first approach is faster to implement , as I only need to define the Exclude list, while the second approach will require me to create view-model class for each of the domain classes. So which approach is recommended to use and why ?
Thanks
Over-posting occurs due to the default model binder not knowing which fields you actually included in the form.
It will try to map all values in the request to object. Attackers can use your form to add additional fields to
query strings/form post data and add properties as part of the request. The default model binder won't
know the difference. Your Server class will deactivate once the mapping is complete and the update is processed.
To prevent over-posting, set the annotation to include fields in the binding, or create a ViewModel like you mentioned in your code.
So which approach is recommended to use and why ?
Both annotation and ViewModel allow binding only on specified fields, but when you use ViewModel you will not bind against business objects or entities, and you will only have properties available for the input you expected.
Once the model is validated, you can then move values from the input model to the object you used in the next layer.
k. Soctt Allen has a good article about which approach is better, you can take a look at by the following link:
http://odetocode.com/blogs/scott/archive/2012/03/11/complete-guide-to-mass-assignment-in-asp-net-mvc.aspx
It's difficult to tell without seeing the rest of your code, but in general I'd say using the ViewModel is probably a better approach for the following reasons:
You separate your view from your business logic
It is safer. If in the future someone adds a property on Server and forgets the Bind-exclude, you're exposed to over-binding without knowing it. If you use the ViewModel-approach you have to explicity add new properties
Maybe this question is a little bit ambiguous because the answers are going to be based on opinions or something. But I'll try to answer it the best I can and indeed is kind of my opinion. So this is the way I see it:
First approach (Bind attribute): Is faster to implement because you only need to add on your class the name of the property you don't want to expose, but the problems comes when you want your class to exclude some properties for one feature and other properties for another feature, and you can't add fields and sometimes in MVC, the views need more fields that the ones provided by the model class and then you're gonna need to use ViewBag or something else. This approach is very handy for fast and smalls projects, but I still don't like to use ViewBag (For aesthetics reasons)
Second approach (ViewModels): Is more work, and more time but at the end (again in my opinion) you get a cleaner and ordered code and you don't need to use the ViewBag, because you can have the perfect object to send to the view depending on what this View needs, so if you a have an object with different views, again depending on the needs, they could share the same ViewModel or they could have a ViewModel for each one. If you have a solution or a big web project, this approach is going to be very handy to keep an ordered code.
Let me know.
I am newbie in asp.net mvc.
I created an asp.net mvc4 empty application and added an entity model to it.
I have a layout page which I want to display menu categories,header,footer vb.But how can I send the data contains one more entity object(last posts,categories,tags) to layout page ?
Thanks
If you want to pass data (coming from database I assume) to the layout view you are facing a scenario where you have data that is passed to every page in your application. So what I would do is create a base controller from which all your controllers will inherit:
public class BaseController : Controller
{
public LayoutModel model;
public BaseController()
{
// Here you will use some business logic to populate your Layout Model
// You might also consider placing this model into the cache to prevent constant fetching of data from the database on each page request.
model = _service.Populate();
ViewBag.LayoutModel = model;
}
}
As you can see I used the constructor of the base controller to fetch the data needed for your layout view. I made a property named model and used some business logic method called Populate (you need to write this yourself) to populate the model variable. Then I place the model into the ViewBag.
Once I have this set up then every controller I make in my solution needs to inherit from the base controller:
public class HomeController : BaseController
{
// Controller code here...
}
which means that every controller can now access the model property from the base controller.
From here you can use the ViewBag.LayoutModel on each view like this (declare a local variable at the top of the view and cast it into the underlying type):
#{
LayoutModel MenuModel = ViewBag.LayoutModel;
}
and then use it like this:
#MenuModel.SomeProperty
This is just one of the ways to do it but there are other less/more complex ways. You need to do some research on your own and see which technique fits you the best...
In an mvc project, could someone explain to me the difference between a model and a view model?
My understanding is that a view model reperesents the data for view eg. cshml, but a model represents the data for a partial view. Would this be correct. I have seen the names used in different situations which confuses me so looking for direction on this.
Models are your domain. For example we might have a customer model. We can use this customer in our domain. We can place orders for this customer. We can update the customers contact details, and so forth.
// Domain object, encapsulates state.
class Customer
{
public void PlaceOrder() {...}
public void UpdateContactDetails() { ... }
}
View Models are a way of presenting the data in an easy way. For example, we might have a customer view model. This would be a simple DTO (Data Transfer Object) which allows us to expose the customer to a view. Often view models are created from models - some form of conversion often takes place.
// DTO - exposes state - no domain logic
class CustomerViewModel
{
public string Name { get; set; }
public int Id { get; set; }
}
The benefit of using a view model rather than using your domain objects in your views is that you don't have to expose the innards of your domain to ease presentation logic. I should add that view models are a way of controlling model binding, e.g. if you expose a database record you probably don't want the whole record to be bindable. Using a view model means only those parameters on the model will be bound. Therefore using view models is important from a security point of view. The alternative here is to use whitelists to control what is used during the model binding process - naturally this is tedious and prone to error.
In terms of ASP.NET MVC - the word model is used somewhat interchangeably. In a "real world" project, your domain is likely complex and will not reside inside a Web App, chances are you'll include some other dependency. Therefore the "models" you'll use will be View Models.
In general, in the ASP.NET world, when people refer to models to refer to 'domain models' which are often a 1-1 mapping between say a database table and a C# class.
When referring to view models, these are convenience classes which aid the passing of data between the view (.cshtml) and controller.
The view models should contain data relevant to the view, which may contain aggregation data of the domain model (e.g. a property called 'FullName' which is the combination of 'FirstName' and 'LastName') or things like paging info etc.
Personally I prefer to use view models to present data in simple forms to the view, and I make the controller actions take instances of a view model, construct domain models and act on them, either directly or through a service layer.
I'd say that is general a view model holds the data for a specific view/screen/partial view and a model is rather the object representing the business object or entity.
Please look into the following posting, your question was successfully answered:
ASP.NET MVC Model vs ViewModel
Hope this helps
I've found this text in Prism documentation. I'm starting on MVVM and I'm at lost. Can (should) I bind model properties in the view or I must create a viewmodel with a proxy property for every property in the model?
The model classes typically provide
property and collection change
notification events through the
INotifyPropertyChanged and
INotifyCollectionChanged interfaces.
This allows them to be easily data
bound in the view. Model classes that
represent collections of objects
typically derive from the
ObservableCollection class.
EDIT: Here is some extra info to help. I'm building a personal project from the ground up (so I'm designing the models too), this is the first time that I use MVVM and I want to learn properly.
My model is very hieraquical, having classes with list of more class with more list inside, building a complex tree of information. I was trying the "standard" MVVM approach, build the model with POCO and no notifications, and using List. Then building the ViewModel with proper notifications and using ObservableCollections.
The problem is, the way it is going, I'm almost reconstructing my whole model as a ViewModel AND having to keep the data synched between the to (the ObservableCollection to the List). Then I read that on the Prism docs and wondered if I should have all that trouble or just create a root ViewModel for logic and bind all the rest to the model itself.
It depends really, if your model already implements INotifyPropertyChanged and/or IError info you might want to bind right to the model property. However if you want to do special validation and other stuff that the model knows nothing about you add the property wrappers in your view model.
This article gives a good example of a hybrid: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Often my MV properties look like this and thats quite normal:
public string Symbol
{
get { return Model.Symbol; }
set { Model.Symbol = value; this.NotifyOfPropertyChange(() => this.Symbol); }
}
I often do NOT implement INotifyPropertyChanged in the model and thus often I have to write the wrappers.
EDIT: In response to your additional information: It can be a bit tricky to to keep the collections and lists in sync. In your case what I would do is to create a view model for each model class, but NOT wrap all the properties just access them like this: {Bindng Customer.Name}. But of course you have to create a wrapper for the collections which contain view models. The Prism documentation is, as they say themselves, just guidance, if your scenario needs a different approach then this is fine.
Take a look at this code. I only wrap the collections and the properties I will access through the model. This gives you the best of both worlds. Then IF you need a special property that does not belong into you model you can add it to the view model (see the CustomerViewModel), or if you need special notification for a certain properties.
class CompanyViewModel{
public CopanyViewModel(Company c){
foreach(var customer in c.Customers)
Customers.Add(new CustomerViewModel(customer);
}
public Company Company {get;set;}
public ObservableCollection<CustomerViewModel> Customers {get;set;}
}
class CustomerViewModel{
public CustomerViewModel(Customer c){
Customer = c;
}
public Customer Customer {get;set;}
public Brush CustomerBackground{
get{
if(Customer.Active)
return Brush.Greeen;
else
return Brush.Red;
}
}
}
(This code might not work, I just typed it in here.)
Now, if you need changed notification for all models and all properties you have to either implement it in you model or in wrap all properties in a view model.
I know that view model can be used for rendering a view, but if a page needs different models, how can I pass them to the view? And how do I use them?
If you need to pass multiple models then create an all-encompassing model that has the smaller models hanging off as properties.
For instance, let's say you are going to display a page for managing groups of users for your app. You would probably need to pass an IEnumerable<UserDisplayModel> and also an IEnumerable<GroupDisplayModel> to the view. Create a new display model like this:
class GroupManagementDisplayModel
{
public IEnumerable<UserDisplayModel> Users { get; set; }
public IEnumerable<GroupDisplayModel> Groups { get; set; }
}
Pass instances of this model to your view instead.
If you find that you want to do this a lot and that you don't much care for creating lots of small types, then you can use .NET 4's dynamic type:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
In your action, pass an anonymous type to your view:
return View(new { Users, Groups });
The reference them in your view as you would otherwise.
You lose intellisense and strong typing this way, but unless you're compiling your views (which requires manually editing your .csproj file and makes the build much slower) then you don't have compile time checking on your views anyway.