In my Controller I have a ProductInfo class from my Domain Model and I need some of its information to populate my View Model ProductStatsVM.
How do you populate the View Model? I heard three possible ways:
Populate the View Model directly from the Controller (not good, I want to keep my Controller slim)
By using a View Model constructor and pass the domain model as parameter. (I have to create a constructor for each domain model class I want to use)
By using a Fill() method. (I saw it on the web, no idea how it works I guess this way the ViewModel should be aware of the Service Layer and creates coupling).
I know there are tools like AutoMapper, which I am going to use indeed, but before I want to understand the logic on how to fill a View Model from the Controller without using any additional tool.
The idea is that your controller action queries some repository to fetch a domain model. Then it passes this domain model to a mapping layer which is responsible to convert it to a view model and finally it passes the view model to the view:
public ActionResult Index(int id)
{
ProductInfo product = repository.GetProductInfo(id);
ProductViewModel viewModel = Mapper.Map<ProductInfo, ProductViewModel>(product);
return View(viewModel);
}
and you could even make your controller slimmer by introducing a custom action filter that will automatically intercept the Model in the OnActionExecuted event and call into the mapping layer to substitute it with the corresponding view model so that your controller action now becomes:
[AutoMapTo(typeof(ProductViewModel))]
public ActionResult Index(int id)
{
ProductInfo product = repository.GetProductInfo(id);
return View(product);
}
and of course now the view is strongly typed to ProductViewModel:
#model ProductViewModel
...
Up to you to implement the Mapper.Map<TSource, TDest> method. And if you don't want to implement it yourself you could download AutoMapper which already has this method for you.
The mapping layer is something that is part of the MVC application. It must be aware of both the domain models coming from your service layer and the view models defined in your MVC application in order to be able to perform the mapping.
Don't use constructors (other than the default parameterless one) in your view models. The default model binder will choke if the view model doesn't have a parameterless constructor in your POST actions and you will have to implement custom model binders.
Since viewmodels are needed to populate UI, it should be good idea to get them populated via controllers. You still may keep them slim by using Automapper.
Related
In my web application a product is defined by N number of product options and a product object. To display a full product I need to create a view model that will hold the product object, a list of product options and for each product option a list of possible values. My question is what is best practice? Where should I construct this object?
In my mvc application I have a service layer, should I do it in the service layer and have something like productservice.getproduct(id) return the view model ready for the view...or in my controller do I use a combination of...
Productservice.getProduct(Id) and productoptionService.getProductoptions(productId)
And then inside the controller construct the view Model?
My guess is to go with the first option, any ideas?
Your question is a bit complicated because what one developer means by a service is something else to another.
So how do we continue?
Well we know it is the responsibility of the Controller to mediate between the View and the ViewModel.
Mapping from the request to the ViewModel
Choosing the appropriate View
And delivering the ViewModel to the View
Keeping in mind that one ViewModel to one View is generally a good practice.
So what about your Domain model?
Well it's best to keep that seperate don't allow it to leak into your controller, this is to prevent any sort of UI specific information from accidentily making its way onto your Domain model.
Personally I practise the following, I have a slim layer (call it a manager or service) that returns a ViewModel, and receives a ViewModel when talking to the controller. But when talking to my internals talks with my Domain model.
So Controller -> Manager -> Service
Manager maps between Domain model and ViewModel.
For example:
public class MemberManager
{
public MemberService MemberService {get;set;}
public MemberViewModel GetMember(int id)
{
var domainModel = MemberService.GetMember(id);
return new MemberViewModel { FullName = domainModel.FullName };
}
public bool UpdateMember(MemberViewModel viewModel)
{
MemberService.Update(new MemberDomainModel { Id = viewModel.Id, FullName = viewModel.FullName });
return true; // all good.
}
}
And your controller.
public class MemberController
{
public MemberManager MemberManager {get;set;}
public ActionResult View(int id)
{
var viewModel = MemberManager.Get(id);
return View(viewModel);
}
}
From my understanding of DDD and MVC's view-model, the one you mentioned return from productservice.getproduct(id) is belong to domain model and the view model is just used for
pass data to view for display purpose. So in my opinion, you should have a view-model which is a combination of Productservice.getProduct(Id), productoptionService.getProductoptions(productId)
and you should construct your view-model in your controller by calling these 2 methods.
I've come across an interesting question during my development. Right now, I use a database-agnostic unit of work layer to abstract the access of data from the actual database dependencies in my ASP MVC 4 web application.
Each individual database project which implements the unit of work interfaces are aware of my business models (models that go directly to/from the database). I'm not too sure how I feel about this approach, but that's not the question I am going to ask.
Should I be using a solution like AutoMapper to convert my business models to/from domain models - models that are passed to the view and used for any work that shouldn't have access to database fields (i.e., IDs)?
For example, consider inside my BusinessModels project, I have the following classes
BusinessModels
/UserAccounts/
User.cs
- ID
- Username
- HashedPassword
- Salt
UserSettings.cs
- IsSubscribedToNewsletter
- AllowDirectEmails
Would it make any sense to bind these User, and UserSettings models into a single model using AutoMapper like so
MyProject
/DomainModels/
User.cs
- Username
- HashedPassword
- Salt
- IsSubscribedToNewsletter
- AllowDirectEmails
for the purpose of views?
This question also extends to non-MVC projects but I feel seeing as I am working on an MVC project it would make more sense to ask it in that tag.
TLDR is there any point in mapping business models/entities to view models or does that provide an unnecessary layer of abstraction? And if so, would the Repositories contain business models, or view models (which map automatically to business models under-the-hood)?
You can use view models for two different things:
rendering a new view (GET action), passing the view model object as the model for the view
receiving data back from the view, in a Post Action (POST action), using the view model as parameter
(I know, the second is arguable. But it's not strange to use the view models for this)
The model for the GET action needs all the properties neccessary to render the View:
the values of the entity you're showing/editing
extra values needed to render the view (for example SelectLists for drop down lists)
Suppose that you have a User which can belong to one UserGroup.
In this case, if you want to edit the user, the model needs:
the User data
a list of UserGroups
I'd use a model like this:
public class EditUserModel
{
public User User {get;set;}
public SelectList UserGroups {get;set;}
}
As you can see, I directly add the User as a property. But I don't add the list of categories as a property, because I don't need the whole list of categories, with all their properties in the view. Besides, if you unit test the controller you can verify that the SelectList is as expected (that couldn't be done if you created the User Groups list in the view)
But, what if you don't need all the properties of the user in the View? Is it worth removing the User property, and add individual properties for Name, Email, JoinedData, Active... ? I think the anser is NO. Imagine you add/remove or rename some of the User entity properties. If you had individual properties in the view model, you'd have to change them as well, before updating the View. And, if you rely on automatic mapping (auto mapper, value injecter) you would't even realized if you make some mistake.
I also said that the view model can be used for posting back data to the controller. So you could do this:
[HttpPost]
public ActionResult Edit(EditUserModel userModel)
If you do so, the model binder will populate the userModel with the values in the form controls. So you'lll get back a half empty model. In this case, the UserGroups list would be null, and, depending on how many of the User's properties you edit, the User could also have many null/non-initialized properties.
To avoid making errors, in some occasions is advisable to create a different model (and probably auxiliary classes) to make it clear what is expected to be posted to the model.
For example, if you have an action to show the whole user data, but which only allows to change its password, you could create a class with two properties: Password, and PasswordConfirmation.
In this case, the view model for the POST could only have the Password and PasswordConfirmation. And derive a model for the GET which has this inherited properties, and also the list of User Groups and the User.
Why inheriting and not using independent classes? Simply beacuse when you use something like Html.TextBoxFor(m => m.User.Name), the Model Binder will be able to set the Name property of the User property, only if the parameter for the post action has the same structure. I.e. if the view model for the get has this structure:
public ChangePasswordModel
{
public string Password {get;set;}
public string PasswordConfirmation {get;set;}
// extra properties, like the list of user groups, the user data...
}
And the model for the post has this structure:
public PostedChanegPasswordModel
{
public User User {get;set;}
}
The content of the input rendered by Html.TextBoxFor(m => m.EditedUser.Name) won't be bound to the User.Name of the PostedEditViewModel.
But if you make this:
public EditUserModel : PostedEditUserModel
{
// extra properties, like the list of user groups
}
the data will be bound without any problem.
In general you have to be careful with the models you use for posting and getting. And I recommend using as many different view models as neccesary.
When to use automatic property mapping to completely new view and different models?
You must have a very strong reason to have different view models. This could be a result of starting the application from outside in (i.e. design first) or because a team is developing the UI before or while the business logie is being implemented.
In this case you can find that the classes for the view models, and the views themselves are already defined, and are quite similart to your entities, but not exactly equal. This is one case when I think it can be good to use mappers.
The other reason to use different classes would be to decouple the interface from the logic. But this usually only happens in the previous case.
Regards viewmodels I treat them like a summary of the data you wish to work with.
So taking from your example, your viewmodel would contain data from both the User and UserSettings classes. Let's say you had a view named UserData.cshtml then I would code it up like so:
public class UserDataViewModel
{
public string Username { get; set; }
public bool AllowDirectEmails { get; set; }
// etc ...
}
public ActionResult UserData()
{
var viewModel = new UserDataViewModel();
viewModel.UserName = "Whatever";
viewModel.AllowDirectEmails = false;
// Or however you get the data for the user.....
return View(viewModel)
}
Hopefully you get the idea. So you are on the right track with merging information from externals classes into one viewmodel class. Bascially tie everything together in the viewmodel class.
I name the viewmodel class the same as the view that it's going to be used for. This can help documentation, as well as make it easier for devs new to the code to follow.
I am having a hard time understanding the way MVC behaves. In my Controller class I created a model and initialized it the main ActionMethod. After that I call another controller method and it turns out that the model is null. Why is that?
Now it seems I can only use them once for passing database info to the views. Is it necessary to always modify/query the database? I know in most cases it makes sense to do it, but I would like to keep these parts separate.
Edit:
Here's some code:
public class TestController : Controller {
TestModel model;
public ActionResult Index() {
model = new TestModel();
return View(model);
}
public ActionResult OtherMethod {
// Here I would like to access/modify the previously created model, but it is null
return View();
}
}
You should use Html helpers to bind properties of your model in view
or simply use #Html.EditorForModel() helper. It will create UI and binding for entire model
the default lifetime of controller is "per request" this means that a new instance of your TestController is created on every HttpRequest.
you could change this behavior by creating a custom controller factory but i would not recommend that, i suggest u use the TempData collection instead.
see http://msdn.microsoft.com/en-us/library/dd394711(v=vs.100).aspx
I have written a bit of code today which smells somewhat.
public class SomeController : GenericController<SomeViewModel, SomeModel>
Here is a Generic Controller constrained to a particular Model and ViewModel; now what smells is the fact that I am defining the relationship between the Model and the ViewModel I don't mind that the Controller knows about the ViewModel that's fine. What I wish this to do is have the Controller ask the View Model somehow because that's where the coupling should be in my view.
The only way I can think of is in the controller factory. That could inspect the supplied ViewModel and create and instance of the Controller with the Model defined at runtime.
so the above would just become
public class SomeController : GenericController<SomeViewModel, TModel> where TModel : Model
And only be typed at runtime.
any ideas on how to do this? reflection? generics? attributes?
or is this just a really bad idea?
============Edit===========
the reason for the use of generics is there is a lot of shared code throughout the controllers
the controllers use services which intern use repositories.
the services and repositories depend on the type of domain object.
the methods such as public ViewResultBase Add(TViewModel viewModel) in the Generic Controller uses a generic mapper which converts the ViewModel to a Model and passes this to the service -> repository.
============Edit===========
heres a snippet from the base class showing some shared code utilising the generic arguments
[HttpGet]
public virtual PartialViewResult List(int id)
{
var model = BuildListDetails(id);
return PartialView(model);
}
[Dependency]
public IService<TDomainObject> Service { get; set; }
protected IEnumerable<TViewModel> BuildListDetails(int id)
{
var nodes = Service.GetData(UserState.Current.User.UserID, id);
if (nodes == null) return null;
return nodes.Select(n => ModelMapperFactory<TDomainObject, TViewModel>.Instance.Create(n)).AsEnumerable();
}
cheers,
Darin is right (as always). Controllers can work with different models and different views and different view models. Typing your controller to one specific view model and model is just pointless, unless you know for a fact that you will always use just that one view model and just that one model.
There is an association between view models and models. This association is handled in the controller. That's one of its purposes. Don't spend a lot of effort trying to genericize controllers, they typically only contain very specifc code related to its use, and have few options for reuse. When you do need more options, consider using aspects or base clases that just abstract the reusable part (some people authentication logic in a base class, which I don't agree with.. but it's a choice.. other people add their own custom IPrincipal, or other kinds of common features. In most cases, this would not require using generics).
I am Learning ASP.NET MVC and downloaded a couple of sample apps. MusicStore etc...
I am coming from a wpf background where we had the MVVM Pattern.
I have noticed that they used the concept of model and ViewModel.
In MVVM is pretty clear that you bind the view to the ViewModel injecting the model into the viewModel.
In MVC you have a controller but I am not sure and confused how the all ties together,as I cannot see the model injected into the ViewModel
I have the following structure
MyCompany.Entities.dll (All the models go here) EG Product
MyCompany.Dal.dll (All the repositories go here)
MyCompany.Services.dll (called by MyCompany.WebUI.Controller calls MyCompany.Dal)
MyCompany.WebUI.MyApp
MyCompany.Tests
From some of the examples I have seen your Model acts as a ViewModel.Am I correct?
Let's take a controller i have something like
public class ProductController
{
public ProductController(IProductRepository productRepository)
{
//omitted as not relevant
}
}
public class ProductVM
{
public ProductVM()
{
// Shouldn't we inject the model here RG Product
}
}
Is there some N-tier examples out there I can refer to?
Is the concept of ViewModel a valid one in MVC?
What is the standard?
Thanks for any suggestions.
Use ViewModels to simplify the View.
For instance, you might have a deep object graph with Products, Order, Customers, etc - and some information from each of these objects are required on a particular View.
A ViewModel provides a way to aggregate the information required for a View into a single object.
ViewModels also allow for things like data annotations and validation - which does not belong on your model, as your model should stay "domain-specific".
But in reality, ViewModels are nothing more than a simple wrapper for your domain objects.
Use a tool like AutoMapper to map back and forth between your ViewModels and domain models with ease.
Personally I always bind to ViewModels in my Views, never to the domain models, even if it's a single object. Why? Well I like to decorate my ViewModels with UIHints, validation, data annotations. Just the same way your domain models are enriched with domain-specific rules and business logic, so should your ViewModels be enriched with UI-specific logic.
If you simply have a object with a 1-1 representation of your domain model, you are missing the point of ViewModels.
Add to the ViewModels only, and nothing more, what is required for a particular View.
Example controller action
public ActionResult CustomerInfo(int customerId)
{
// Fetch the customer from the Repository.
var customer = _repository.FindById(customerId);
// Map domain to ViewModel.
var model = Mapper.Map<Customer,CustomerViewModel>(customer);
// Return strongly-typed view.
return View(model);
}
The difference between MVC and MVVM is that MVC has one set of classes for the data entities. In MVVM you have 2 - one set for binding to your views, and one set for managing the data persistence (which could be in a separate WCF service for example).
The benefits of MVVM are that the model bound to the views is relevant to the UI and completely independant from the persistence Model.
Which to use? Well it depends on how closely the data structure required by your Views maps to the structure of the database. When it is similar - it is possible to bind the DataEntities from your DAL directly to your view - this is the classic MVC pattern. However, you gain much with a separate ViewModel as you can extend these classes with View specific behaviour (e.g. Validation) that your DAL should not be concerned with.
For all but the most simple applications, I would recommend use of a separate ViewModel.
Extremely simple,
ViewModel can be the combination of multiple Model classes, to display or transforming the data to and from within the Network, may be via API calls.
However, Model class is nothing but just be specific to any particular entity, Object or strict to a particular Table.
Ex- For "EmployeeViewModel" can be the combinations of Multiple Model Classes i.e. EmpBasicDetails + EmpAddressDetails +EmpExperienceSummary.
Whereas, "EmpBasicDetails" - is specific Model class which contains the Employee Details specifically.
~Cheers,