And what do you put in your View?
A recent blog from Scott Hanselman about using a special model binder for easier testing led me to think about the following:
What do you put in your controller logic building the view model, and what should be put in the view? what he does is this:
var viewModel = new DinnerFormViewModel {
Dinner = dinner,
Countries = new SelectList(PhoneValidator.Countries, dinner.Country)
};
return View(viewModel);
Now, I use the same way of passing data to my view, but I am unsure about how he deals with the Countries property. You could argue both sides:
Wrapping the Countries list in the SelectList prepares the data for the view, much like you create a viewmodel DTO to pass your data.
On the other hand, it somehow feels like you're specifically manipulating the data to be used in a dropdown list, limiting the way the view deals with your data from the controller.
I feel this is a bit of a gray area on the separation of concerns between the view and the controller, and I can't really decide which way to go. Are there any best practices for this?
PS: To keep it simple, let's assume the default ASP.NET MVC context, so basically your out of the box project. Default view engine and all that jazz.
In MVC (at least this flavor of it), one of the controller's responsibilities is to prepare the data for the view. So I think it is perfectly acceptable to prepare a specific model for the views consumption that implies it will be used in a drop-down. In this case the controller is just making it easier for the view and in fact prevents awkward code from having to otherwise be trickling into the view. It also keeps one from having those magic strings in the ViewData like VieData["Countries"].
So to sum up, while it may seem that there is some gray area in terms of responsibilities, ultimately that is the job of the controller: to interact with the view and to transform the domain model into other models that are easier to consume by the view.
Some suggest that having one all-encompassing view model per view is ideal (dubbed Thunderdome Principle).
Related
when do you think is it better to use ViewData over a view model?
I have the same exact partial view in a couple of main views. I'd like to control how a partial view is rendered but I'd also prefer the partial view to accept only a view model which is a collection of records, just a pure IEnumerable<> object. I'd rather avoid to send the full view model object from a main view because it also contains a lot of different properties, objects, that control paging, sorting, filtering etc.
Therefore the question is if I should create another view model for the partial view or is it ok to use ViewData? I've read soemwhere that using ViewData is a very bad practice.
With View Data, I could simply pass require details like this:
#{
ViewDataDictionary vd = new ViewDataDictionary
{
new KeyValuePair<string,object>("WithDelete", Model.WithDelete),
new KeyValuePair<string,object>("WithRadarCode", Model.WithCode)
};
}
// ...
#if (Model != null) {
Html.RenderPartial("_ListOfRecordingsToRender", Model.recordingViewModel, vd);
}
At the moment, it would be sorted out.
My worry is that currently this *.recordingViewModel has plenty of different variations in my project, because of different models for creating / editting, listing, shoing details of a record etc. I feel like it may start to be too messy in my project if I make view model for each action.
What do you think. Please could you advice on that particular problem. Thanks
I think you should stick to using a ViewModel, your ViewModel is the class that defines your requirements for the view.
My reason behind this is that in the long run, it will be a lot more maintainable. When using ViewBag it's a dynamic class so in your views you should be checking if the ViewBag property exists (And can lead to silly mistakes like typo's) e.g.:
if(ViewBag.PropertyName != null)
{
// ViewBag.PropertyName is a different property to ViewBag.propertyName
}
This type of code can make your View's quite messy. If you use a strongly typed model, you should be able to put most of the logic in your controllers and keep the View as clean as possible which is a massive plus in my books.
You also will also end up (if you use ViewBag) attempting to maintain it at some point and struggle. You are removing one great thing about C#, it's a strongly typed language! ViewBag is not strongly typed, you may think you are passing in a List<T> but you could just be passing a string.
One last point, you also will lose out on any intellisense features in Visual Studio.
I feel like it may start to be too messy in my project if I make view model for each action.
Wont it just be as messy in your controllers assigning everything to a ViewBag? If it was a ViewModel you could send it off to a 'Mapping' class to map your DTO to your View.
Instead of this:
// ViewModel
var model = new CustomViewModel()
{
PropertyOne = result.FirstResult,
PropertyTwo = result.SecondResult,
}
//ViewBag
ViewBag.PropertyOne = result.FirstResult;
ViewBag.PropertyTwo = result.SecondResult;
You could do this:
var mapper = new Map();
var model = mapper.MapToViewModel(result);
*You would obviously need to provide an implimentation to the mapping class, look at something like Automapper
I'd also prefer the partial view to accept only a view model which is a collection of records, just a pure IEnumerable<> object. I'd rather avoid to send the full view model object from a main view because it also contains a lot of different properties, objects, that control paging, sorting, filtering etc.
That is fine, just create a view model that has a property of IEnumerable<T>. In my opinion you should try and use a strongly typed ViewModel in all of your scenarios.
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.
I'm starting to develop a new ASP.NET MVC application, and I'd like to make sure that my understanding about the way of developing applications under MVC pattern is correct.
Question 1: Suppose that I have some main views (MainView1, MainView2, ...) with some partial views in it (PartialView1, PartialView2, PartialView3, ...). From what I have understood about MVC, I should define a Model for each view. e.g. I have to define PartialModel, PartialModel2, ... and also define my main models which are containers of the partial models which have been used in them:
public class MainModel1
{
public PartialModel1 Partial1 {get;set}
public PartialModel2 Partial2 {get;set}
public PartialModel3 Partial3 {get;set}
}
This way when I want to redirect to MainView, I can initialize the models used in that view by using this Model. Is my understanding of MVC correct? Or should communication between Views and Models be in another form in MVC?
Question 2: If the above is correct, Then suppose I have a partial view in some of my main view pages. This partial view has a submit button which calls an action method. This action method should somehow return the main page's view with the right viewmodels for views. Is there any recommendation about how to get/set viewmodels of other views in a partial view's action?
Thanks.
You understanding is correct. Each view (no matter whether it is main or partial) should have a corresponding view model (unless in the very rare case where this view contains only static html of course). And following this logic a main view that has to render other partial views will have a view model which itself will have reference (maybe as properties) to view models that are required by those partial views.
There is another technique which is using the Html.Action helper. In this case the partial is rendered through another controller/action than the main one. So you don't need to reference the partial view model in the main view model. They will be completely distinct. Take a look at the following blog post to learn more about Html.Action.
Your understanding is perfectly fine. This is what you can also refer to ViewModel in Asp.net MVC.
So, What basically is an Asp.net MVC ViewModel ?
In ASP.NET MVC, ViewModels allow you to shape multiple entities from one or more data models or sources into a single object, optimized for consumption and rendering by the view. The below image illustrates the concept of a ViewModel:
The purpose of a ViewModel is for the view to have a single object to render, alleviating the need for UI logic code in the view that would otherwise be necessary. This means the only responsibility, or concern, of the view is to render that single ViewModel object, aiding in a cleaner separation of concerns (SoC). Concerns are distinct aspects of the application that have a particular purpose (i.e., concern), and keeping these aspects apart means your application is more organized, and the code more focused. Putting data manipulation code in its own location away from the view and controller, enforces SoC.
Using ViewModels in MVC for finer granularity and better SoC leads to more easily maintainable and testable code. Remember, unit testing is about testing small units.
Along with better coding practices, there are many business reasons demonstrating why you might consider using ViewModels:
Incorporating dropdown lists of lookup data into a related entity
Master-detail records view
Pagination: combining actual data and paging information
Components like a shopping cart or user profile widget
Dashboards, with multiple sources of disparate data
Reports, often with aggregate data
My MVC application contains a parent model, which will contain 1 or more child models.
I have set up the main view to display properties from the parent model, and then loop through a collection of my child models (of various types, but all inheriting from the same base type). Each of the child models have a corresponding partial view.
My "parent" view iterates over the child models like this:
foreach (ChildBase child in ViewData.Model.Children)
{
Html.RenderPartial("Partials/"+child.ChildType.ToString()+"Child",
section);
}
My application has the appropriate /Partials/ChildType1.ascx, ChildType2.ascx, etc. Everything works great.
Is this an appropriate way to use Partial Views? It feels slightly off-kilter due to the dynamic names, but I don't know another way to perform dynamic selection of the proper view without resorting to a big switch statement.
Is it advisable to use the same view for multiple "modes" of the same model? I would like to use the same .ascx for displaying the "read only" view of the model, as well as an edit form, based on which Controller Action is used to return the view.
Iconic,
It's difficult to answer the questions without knowing exactly what you're trying to achieve.
I'll have a go though:
If you're familiar with web forms, think of your partial view as a webforms usercontrol for the moment and think of the part of your model that is relevant to your partial views as a 'fragment of information' that want to pass across to the partial view.
Natural choices for using a partial view would be for elements used in many views across your site.
So ... in answer:
1.Although what you are doing is valid, it doesn't seem quite correct. An example of a partial view I have used might be a row in a grid of data where you'd call the partial view passing in the row object as its model:
foreach (MyObject o in Model.objects)
{
Html.RenderPartial("Shared/gridRowForObject.ascx", o, ViewData);
}
You can strongly type your views also to expect a specific type to be passed through as the Model object.
Again another use might be a login box or a 'contact me form' etc.
2._Ultimately this is a personal design decision but I'd go for the option that requires the least application/presentation logic and the cleanest code in your view. I'd tend to avoid writing to many conditional calls in your view for example and by inferring a base type to pass across to all of your partial views as in your example, may well tie you down.
When learning the MVC framework I found the Oxite code to be useful.
I hope that helps.
On the main page of my site, I would like to show several views which rely on their own controllers for data retrieval. I do not want to retrieve anything from the DAL in my Home controller.
For example, I want to show view listing top 5 news, a view with random quote from the database, another view with the users shopping cart contents, etc.
After Googling around, I found RenderAction method which is almost perfect, but it's not available in RC1, only in Futures, and apparently, it has some issues.
I found RenderPartial as well, but that relies on the main controller to pass data to the view.
Additional clarification:
The main reason I do not want data access logic in the Home controller is to avoid repeating the code and logic. I will use top 5 news view in several pages/controllers. I do not want to repeat data retrieval in every one of them. I already did separate a lot of logic and validation to business layer. The solution I'm after is RenderAction or UserControls as in classic ASP. I know i can use them in MVC as well, but... whats the point? I mean, if what i'm asking is too complicated or too absurd (reusable UI components), then MVC is definitely not for me, and I'd consider it seriously inferior to classic ASP.NET, because this requirement is really simple.
What you're asking is to basically not perform data access in the HomeController, this seems like a dogmatic approach. I would consider either using RenderAction from the Futures assembly (not sure what's wrong with it, I use it in a number of projects) or SubControllers from MvcContrib.
While I can understand the desire not to replicate functionality in multiple controllers, I don't understand the reluctance to have your Home controller interact with the DAL. I think the partial view is definitely the way to go. My solution to not replicating the functionality would be to push the code that generates the data for the various views into your business or data layer. You could then reference it from each of the required controller actions that use the partial views. Putting it in the business layer could isolate the controller from your data layer, if that's what you desire, but I still think it's the proper job of the controller action to obtain and provide the data to the view.
Another potential solution would be to populate the view generated by your Home controller via Ajax callbacks to the various controller actions that generate the required view components. The drawback to this is that it doesn't fail gracefully in the absence of javascript in the browser.
EDIT
Based on your clarification, I would suggest implementing a base controller that fills the ViewData for the shared controls in ActionExecuted (so that it's done only when the action succeeds). Derive your other controllers from the base controller when you want to inherit this behavior.
If you really don't want to use RenderAction, then the only other option you have is to load the necessary data pieces with action filters. Your home controller could then look like this:
public class HomeController : Controller
{
[RequireNews]
[RequireQuotes]
[RequireCart]
public ActionResult Index()
{
return View();
}
}
These action filters could be re-used where they are needed. You might also choose to place these on the controller class itself.