Does a ViewModel have its own logic? - asp.net-mvc

When assigning ViewModel fields, should the domain objects be passed directly to the ViewModel objects which will then determine how to present the data, or should another class like a service be assigning data from the Model to the ViewModel?
also:
EDIT:is there any sense in dividing a viewmodel into receiver and presenter? (instead of binding only certain fields on update?)

Usually the Controller Action takes the business objects and puts whatever is needed by the viewmodel.
If you have a business object that contains the fields Name, Address, Id and the View should only display the Name, then the ViewModel only has a field "Name", and the controller action populates it. The ViewModel should know nothing about your Business Classes, it should only know about the stuff that it needs to display.
The main/only logic is then "Display Logic", that is stuff like "if TotalAmount is negative, display it with CSS Class negativeNumber".

For the sake of SoC if that logic relates to View they safe to be in ViewModel or even in View itself but if they relate to Business or Program put them on Model and Controller respectively.

In my experience I've used services to map the Model to the ViewModel. I don't put logic in my ViewModels.
As an aside, it's probably worth your while to check out AutoMapper to assist you with the mapping. Definitely helps cut down on writing repetitive mapping logic.

Related

MVC where to put code that configures my viewmodel?

I have a viewmodel that needs to be populated with data from an entity
I call this method within my controller
public AssessmentResponseVM ConfigureAssessmentViewModel(AssessmentResponseVM model)
{
if (model.AssessmentID != null)
{
model.Questions = getQuestionAndAnswerList(model.AssessmentID);
}else
{
model.Questions = getQuestionAndAnswerList(null);
}
return model;
}
It basically retrieves a list of questions and answers for the supplied assessment and assigns them to a property of the viewmodel. Where should this ConfigureAssessmentViewModel method live? At the moment it is sat in my controller but i'm not sure I like it there. Should it sit in the viewmodel class or elsewhere?
In this case you should just keep this logic in your controller and return an Enumerable of questions:
var questionsAndAnswersList = getQuestionAndAnswerList(model.AssessmentID);
Also note that you are checking for a null AssessmentID but then passing null into getQuestionAndAnswerList anyway.
then your View should use
#model IEnumerable<Question>
You may also want another view here that knows how to display only questions. See this other question on display/editor templates.
getQuestionsAndAnswerList most likely belongs in a Service/Business logic class that knows how to access the data and translate it into something the controller knows how to use. How you separate your ViewModel classes and Service classes really depends on the size of your application and preference.
A good answer would be quite exhaustive, but basically what you have here is what is part of an object mapping layer. I've seen lots of different architectures that handle this differently. Usually the best thing is to be consistent.
For me, because my business models and view models are two different structures, and view models are tailored highly to a view, or sometimes a handful of views in a controllers, then the controller is responsible for populating the view model from the business model. This is because my approach usually involves a data access layer, business layer, and view layer(consisting of controller, view model, view).
There is no business logic in my controllers, and so they are very thin, and all they are really responsible for is calling into the business layer, retrieving business models, and then populating view models with data from the business layer.
The controller is sort of a glue between the UI and the business layer.
Therefore, in this case if I had a function like this that did something as simple as setting some data on the ViewModel, and it for some reason needed to be reused by multiple controller actions, then I'd just make it a private function of the Controller.
If you were working with a different architecture, that might not be appropriate. I've seen cases where the business layer returned ViewModels instead of business models, and so that mapping occurred in the business model.
If you were working with an existing architecture, I would put that code as a private function in the same class that creates the view model initially, i.e. the class containing new AssessmentResponseVM(...

MVC programming best practise

Team,
I am new to MVC and need some suggestion, well I have come across a situation where in I have to put multiple objects on a same view e.g. display employee, dept, etc details on same page for this I have appropriate models and since single model object is passed from controller to view I have created a view model which contain instance of the all the model my first query is
Below viewmodel EmpVM - Is this the right approach for passing object from controller to view this class will be instantiated in controller of particular view.
In case I have multiple entries of a entity i.e. address(shipping and billing) in address table is it fine to declare two instance of object in viewmodel or declare a single list and iterate in view to populeate one in grid and another in controls.
**
public class EmpVM
{
List<Address> multiAddObj{get;set}
Address singAddobj{get;set;}
}
**
Any suggestion/help on this will be of gr8 help.
Thanks in advance.
HSR.
It is perfectly OK to have a ViewModel object which encapsulates multiple model objects. You did right.
It depends on what's logically "correct" to your applications. For some purposes you should create an IEnumerable object and iterate it in the view, while in other cases it would make more sense to simply have to model objects in the ViewModel.

Intermediate layer between DataEntities and Controller

I was reading this tutorial for MVC3 with Linq to Entities using Model First.
http://msdn.microsoft.com/en-us/data/gg685489.aspx
A quote from the article states
Our controllers will use the BlogDataEntities to retrieve data for us.
In a more advanced application, you should separate logic further and
would not be working with the BlogDataEntities directly from the
controller.
What is the general structure of this other layer between the entities and Controller in an MVC application? What is the purpose?
I usually have a bastardized ViewModel (see http://en.wikipedia.org/wiki/Model_View_ViewModel) which contains the business logic, can fetch/save from EF and is what the view is bound to. The controller doesn't do much but instantiate the viewmodel and depending on the controller action, call a method within the view model.
Some people might break that up even further and have a full blown ViewModel which has no logic in it,just data. A business layer with all of the logic and the ability to move data from EF to the ViewModel and vice-versa.
In the article "BlogDataEntities" is not the name for some specific entity classes (what the name suggests) but the name of the DbContext.
I guess it means that you would try to hide that you work with EF by not instantiating the DbContext, but by using a repository-implementation like this
http://msdn.microsoft.com/en-us/data/ff707264#_Toc261428890

Is it okay to hit the database from a custom model binder?

Say I have an object that gets some data from HttpPost and some from the database. I think I want to allow the ModelBinder to go to the database/repository for the that data missing from the post. In practice, is this a good or bad idea?
I've decided to edit my original answer given my thinking on these types of things has evolved since early 2010.
In my original answer, I basically expressed that, while my instincts told me you shouldn't do this, I was uncomfortable saying we shouldn't without being able to articulate why.
Now, I'd recommend against this on the grounds that the responsibility of a Model Binder is to translate a user request into a Request Model and that retrieving data outside of what can be derived from the request goes beyond this scope of responsibility.
I would say a bad idea. The idea of the model binder is that it takes the parameters from the request and creates your model from those. If your model binder, behind the scenes, fills in some of the details from the database this breaks the paradigm. I'd much rather expose the database call in my controller by explicitly fetching the required extra data from the database directly. Note that this could be refactored into a method if used frequently.
I think this is perfectly fine and use this technique all the time.
The only arguments against are very pedantic and amount to arguing over philosophy. IMHO you can put "fill in missing posted data" code into you MVC app as a method in your base controller vs. method in you ActionFilter vs method in you ModelBinder. It all depends on who get what responsibility. To me the model binder can do a lot more than simply wire up some properties from posted values.
The reason I love doing database calls in my modelbinder is because it helps clean up your action methods.
//logic not in modelbinder
public ActionResult Edit( KittyCat cat )
{
DoSomeOrthagonalDatabaseCall( cat );
return View( new MODEL() );
}
vs.
//logic in model binder
public ActionResult Add( KittyCat cat )
{
return View( new MODEL() );
}
It violates the way MVC is supposed to work. ModelBinder is for binging Models from the data that comes from the view. Populating missing info from the database is something that is supposed to be handled by the controller. Ideally, it would have same data layer/repository class that it uses to do this.
The reason it should be in the controller is because this code is business logic. The business rules dictate that some data may be missing and thus it must be handled by the brains of the operation, the controller.
Take it a step further, say you want to log in the DB what info the user isn't posting, or catch an exception when getting the missing data and email admins about it. You have to put these in your model binder this way and it gets more and more ugly with the ModelBinder becoming more and more warped from its original purpose.
Basically you want everything but the controller to be as dumb and as specialized as possible, only knowing out how to carry out its specific area of expertise which is purely to assist the controller.
I would say, no.
Here's why: It would create a dependency on your database for testing your controller actions that would not be easy to abstract out.
I would say it is ok. The argument that creates dependency to database is a false argument for 2 reasons:
1- Database access should be abstracted via repository interfaces. Repository interfaces are part of the domain model and their implementation is part of the infrastructure/data access layer. So there is no dependency to the database.
2- Model Binders and Controllers are both part of presentation layer implemented using ASP.NET MVC Framework. If Controllers are allowed to access database using repository interfaces, how come Model Binders are not allowed?
Also, there are situations that you'd "better" fill the missing data in your model from Model Binders. Consider the scenario where you have a drop-down list on your view. The first time the view is loaded, the drop-down list is populated. The user submits the form but the validation fails. So you'll need to return the form again. At this stage, you'll have to re-populate the list in the Model for the drop-down list. Doing this in Controller looks ugly:
public ActionResult Save(DocumentViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Categories = _repository.GetAll();
return View(viewModel);
}
}
I believe the initialization of Categories here is ugly and like a code smell. What if you had a few properties that needed to be filled out from database? What if you had more than 1 action that had DocumentViewModel as an argument? You'd have to repeat this ugly step over and over. A better approach is to fill all the properties of the model using the Model Binder and pass it to the Controller. So the object that is passed to the controller is in a "consistent" state.

ModelFactory in ASP.NET MVC to solve 'RenderPartial' issue

The 'RenderPartial()' method in ASP.NET MVC offeres a very low level of functionality. It does not provide, nor attempt to provide a true 'sub-controller' model *.
I have an increasing number of controls being rendered via 'RenderPartial()'. They fall into 3 main categories :
1) Controls that are direct
descendants of a specific page that
use that page's model
2) Controls that are direct
descendants of a specific page that
use that page's model with an
additional key of some type.
Think implementation of
'DataRepeater'.
3) Controls that represent unrelated
functionality to the page they appear
on. This could be anything from a
banner rotator, to a feedback form,
store locator, mailing list signup.
The key point being it doesn't care
what page it is put on.
Because of the way the ViewData model works there only exists one model object per request - thats to say anything the subcontrols need must be present in the page model.
Ultimately the MVC team will hopefully come out with a true 'subcontroller' model, but until then I'm just adding anything to the main page model that the child controls also need.
In the case of (3) above this means my model for 'ProductModel' may have to contain a field for 'MailingListSignup' model. Obviously that is not ideal, but i've accepted this at the best compromise with the current framework - and least likely to 'close any doors' to a future subcontroller model.
The controller should be responsible for getting the data for a model because the model should really just be a dumb data structure that doesn't know where it gets its data from. But I don't want the controller to have to create the model in several different places.
What I have begun doing is creating a factory to create me the model. This factory is called by the controller (the model doesn't know about the factory).
public static class JoinMailingListModelFactory {
public static JoinMailingListModel CreateJoinMailingListModel() {
return new JoinMailingListModel()
{
MailingLists = MailingListCache.GetPartnerMailingLists();
};
}
}
So my actual question is how are other people with this same issue actually creating the models. What is going to be the best approach for future compatibility with new MVC features?
NB: There are issues with RenderAction() that I won't go into here - not least that its only in MVCContrib and not going to be in the RTM version of ASP.NET-MVC. Other issues caused sufficent problems that I elected not to use it. So lets pretend for now that only RenderPartial() exists - or at least that thats what I've decided to use.
Instead of adding things like MailingListSignup as a property of your ProductModel, encapsulate both at the same level in a class like ProductViewModel that looks like:
public class ProductViewModel() {
public ProductModel productModel;
public MailingListSignup signup;
}
Then get your View to be strongly-typed to the ProductViewModel class. You can access the ProductModel by calling Model.productModel, and you can access the signup class using Model.signup.
This is a loose interpretation of Fowler's 'Presentation Model' (http://martinfowler.com/eaaDev/PresentationModel.html), but I've seen it used by some Microsoft devs, such as Rob Conery and Stephen Walther.
One approach I've seen for this scenario is to use an action-filter to populate the data for the partial view - i.e. subclass ActionFilterAttribute. In the OnActionExecuting, add the data into the ViewData. Then you just have to decorate the different actions that use that partial view with the filter.
There's a RenderPartial overload I use that let's you specify a new ViewData and Model:
RenderPartial code
If you look at the previous link of the MVC source code, as well as the following (look for RenderPartialInternal method):
RenderPartialInternal code
you can see that if basically copies the viewdata you pass creating a new Dictionary and sets the Model to be used in the control. So the page can have a Model, but then pass a different Model to the sub-control.
If the sub-controls aren't referred directly from the main View Model, you could do the trick Marc Gravell mentions to add your custom logic.
One method I tried was to use a strongly typed partial view with an interface. In most situations an agregated ViewModel is the better way, but I still want to share this.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>
The Viewmodel implements the interface
public class ProductViewModel:IMailingListSignup
Thats not perfect at all but solves some issues: You can still easily map properties from your route to the model. I am not shure if you can have a route parameter map to the properties of MailingListSignup otherwise.
You still have the problem of filling the Model. If its not to late I prefer to do it in OnActionExecuted. I dont see how you can fill a Model in OnActionExecuting.

Resources