I learning MVC model. I looking for some important information. I know that divide program into 3 parts: Model View Controller. In model have we only Class with fields? I still think where to put for example a method:
public List<GrowerPickingList> getPalletDetailsDataByGrowerAndPickDate(string grower, DateTime pickDate)
{
var linqData = from p in this.GrowerPickingList where p.PickDate == pickDate && p.Grower == grower select p;
return linqData.ToList();
}
Should it rather be in Controller or in Model?
Controller is to interact with View but Controller should take data from Model?
I've read some information about it. Some indicates that put into Controller but some to the model. I want to be sure that I understand. Thank you.
Model-View-Controller is a UI technology. All the Model is supposed to do is carry data from Controller to View and vice versa.
What you show is business logic, which should be in its own layer. Your controller talks to the business layer and translates the returned business models to viewmodels.
Related
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(...
In an MVC application where should the database entities be restricted to. They should obviously be used in the data layer, but should they be used/returned in the business/service layer too? What about ViewModels? Where should their use be restricted to? Are there any other models that should have their scope restricted?
Based on my understanding, it depends on the scope of your application. You can return the entities to the business layer if you have a simple usage, say you are using all the properties of the entity class in the view.
Suppose, if you have a complex model where you want a combination of different entities that you are going to use in the view, then you use view models. In the latter case you save all the data into view model in data-access layer and return the view model to business layer or you can get the models into business layer and save them into view model at this level and return to the controller action method. But the controller action method should finally get the view model.
Looking through the project we are working on (ASP MVC 3.0), I have seen this part of code in one of my ASPX views:
var groups = Model.GroupBy(t => new { t.OrganizationUnitName, t.OrganizationUnitId, t.ServiceTermDate }).OrderBy(m =>m.Key.ServiceTermDate).ThenBy(m => m.Key. OrganizationUnitId);
foreach (var group in groups){
var data = group.Select(t => new
{
t.PersonFullName,
t.ServiceTermStatusName,
t.VisitTypeName,
SubType = ControllerHelper.LocalizedPersonSubType(t.PersonSubTypeName),
t.MedicalServiceName,
t.PersonId,
t.ServiceTermId,
t.Phone,
CountryName = t.Name,
PersonUniqueNumber = t.GetUniqueIdentifyingNumber(),
}).OrderBy(m => m.HoursFromMinutesFrom);
foreach(var item in data){%>
...............
//render table and table rows, for sample
<tr>
<td><%= item.PersonFullName%></td>
</tr>
..............
<%}%>
<%}%>
<%}%>
I am not sure this is best coding practice, shouldn't LINQ statement be placed in controller helper (or somewhere else) instead in view directly? And if I'm right, how that could be done utilizing best coding practices?
Thank you in advance
It seems that LINQ which is performed directly in the view is not only at the wrong place but also it raise another interesting question: if we place it into service layer or controller or controller helper, then how it would be passed in this case - anonymous type IGrouping to strongly typed view?
Personally, I wouldn't use LINQ in the view. Do this in the controller for unit testing purposes.
If there is logic being performed, in a larger application I'd even move it out to a services assembly which would contain all of your LINQ queries.
Your view should be as basic as possible. Any ordering, grouping or sorting should be done in your controller (preferably with the help of a helper method which is re-usable for different actions across the application).
The philosophy of ASP.NET MVC (and I'd say of the MVC paradigm in general) is:
Put as little code as possible in the view. Ideally, you should just
reference data in the model class, perhaps with some loops or
conditional statements.
Do not put complex application logic in the controller methods.
Ideally, these methods should just collect the input data from the user
(if any), perform all the appropriate security and data validations, then pass the data to an application logic (or business logic)
class, then redirect to the appropriate view with the new model data
obtained from the logic class. (I once read that a controller method should have no more than 10 lines of code; maybe this is a bit exagerated but you get the point)
So I would say: not only the view should be LINQ free; the controller should be like this too.
Yes you can do it on View but i prefer to use Business logic work done through
controller rather than on View.
View is just used to display the GUI that must be as basic and simple to reduce the complexity of the GUI.
To make application code consistent, maintainable and reusable put these type of logic on Business Logic Classes except writing on Controller or view.
MVC is about abstraction of concerns.
The code you have posted above is breaking the most important rule of MVC. The view is the view, it has no business logic or data access code. It simply displays data that it is given to it in a nice way that can allow for presentation and user interaction. Think of the view as something you could give to a designer who knows nothing of asp.net.
The problem you have above is a perfect candidate for a ViewModel. The "Model" variable that is being used here is wrong, since you are taking it and then changing it to display something different. If the domain model doesn't fit then the controller should create a ViewModel that looks exactly as the view expects. There are a few ways of doing this. But one way is for example:
public ActionResult DoSomething()
{
List<DomainModel> modelCollection = getListOfDomainModels();
// Perform ViewModel projection
var viewModelList = modelCollection
.GroupBy(t => new { t.OrganizationUnitName, t.OrganizationUnitId, t.ServiceTermDate })
.OrderBy(m =>m.Key.ServiceTermDate)
.ThenBy(m => m.Key. OrganizationUnitId)
.Select(p => new MyViewModel()
{
FullName = t.PersonFullName,
StatusName = t.ServiceTermStatusName,
// etc ...
});
return View("DoSomethingView", viewModelList);
}
Now your Model variable will contain the correct model for the view.
Depending on your project's size and requirements you can make this alot better by performing the whole query in another layer outside of the controller and then projecting to a ViewModel inside your controller.
You should not be doing it in either the View or the Controller. Thus without giving you to much to chew at a a time you will want to have Separation of concerns (SOC) and keep it DRY (Don't repeat yourself) otherwise it becomes a maintenance nightmare.
If you put that code in the view (which is the worst place for it). 1. What happens if you want to use same or similar code elsewhere? 2. How will you step through debugging your code in this manner?
This is the equivalent of placing sql queries in a ASP.NET webforms .aspx file, not even in the code behind .aspx.cs file. Not using your model or a repository pattern and putting the code in the controller is another bad idea as a controller ActionResult has a Single Responsibility (SRP) of handling request, by smothering it with this code you have introduced an anti-pattern. Keep the code clean in organized areas. Don't be afraid to add class library projects. Look up the Repository pattern and eventually get to the point of doing unit testing and using DI (Dependency Injection) not just for unit test, but for a loosely coupled / highly cohesive application.
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.
Imagine a blog engine in ASP.NET MVC where I want strongly-typed Views. I have a Model for BlogPost and a Model for Comments. A typical page would display a blog post and all of that post's comments. What object should I pass to the View()? Should I create a Presentation Model? Maybe I'm using that term incorrectly, but by that I mean should I create a composite model just for a View(), something like BlogAndComments? Should my controller create an instance of BlogAndComments and pas that?
Or, should I somehow pass both a BlogPost and Comments object to the View?
I think you're on the right track with your understanding of Presentation Models. As to when you should create a View Model, the answer is probably 'it depends'. In your example, you can probably get away with passing the BlogPost and Comments in the ViewData object. It's not gorgeous, but hey, it gets the job done.
When and if that starts to feel ugly or unwieldy, then I would start thinking about making a View Model. I usually end up with the notion of some sort of 'Page', which includes the page title, common data, and then specific stuff for a particular page. In your case, that might end up as a BlogViewPage, which includes Title, BlogPost and List comments.
The nice thing about that approach is that you can then test that controller by making a request and testing the BlogViewPage to ensure that it contains the expected data.
In my opinion comments belong to the view as much as the post itself.
Make a BL class for your comments like:
class CommentBO
{
Guid UserID;
string Text;
}
Then you have a BO for your post.
class PostBO
{
Guid UserID;
List<CommentBO> Comments;
}
Then your model can be really simple.
class BlogModel
{
string AuthorName;
string BlogTitle;
List<PostBO> Posts;
}
Pass it to the view and render it.
You may be tempted to omit all BO and just fill the model directly from the database. It is an option, but not exactly the right one. A model is just a package of things for a view to display. These things however should be prepared somewhere else, namely at the business logics level with just a nominal participation of the controller.
I always use strongly typed views and create a presentation model class for each view or view user control. The advantage is that by looking at the presentation model class alone I know exactly what are the values that the view uses. If I were passing domain models then that would not be obvious because domain models may contain many properties that the view does not use. I would have to look at the view's markup to figure out what values it needs. Plus the presentation model usually adds certain properties that are not available in the domain model. It seems a bit tedious but I think it saves time and makes the code better in the long run.
In my opinion if comments belong to a blog post why not create a collection of comments on the blog post model? That makes perfect sense from a domain modeling stand-point and chances are whatever ORM you are using would support lazy-loading that collection which simplifies your controller logic as well.