ASP.NET MVC: having one model for all views - asp.net-mvc

I like the way model binding in django works: you send stuff that you need in a Json-like way:
'param1': val,
'param2': val
In ASP.NET MVC you can't do it primarily because C# is a static language. You can use ViewData but it's ugly and not recommended.
So I had to create dozens of ViewModels for every view: IndexViewModel, AboutViewModel, etc. And today I got an idea: why not just create one Model class and have Visual Studio generate all necessary fields? It's almost like in django.
return View(new Model
{
Param1 = "asd",
Param2 = "sdf"
});
Param1 & Param2 are not members of the Model class, but Visual Studio will automatically generate them.
Now my question is, is it gonna work? The thing is that there will be a lot of fields in this Model class. And when we pass it to a view, only a small percentage of fields made for that view in particular will be used. Is it gonna be bad performance wise?
Thanks

If you have all these properties on your ViewModel which aren't used (i.e null or whatever) it isn't really going to impact performance. What it will impact however, is your design.
Generally speaking, one model to rule them all as you are proposing is a bit evil and goes against separation of concerns. ViewModel's should be very simple and should be tailored to the view. ViewModel's shouldn't really provide the view with more or less data than what the view needs in order to render.
Consider this....
You have a generic model with 15 properties on it and you only set a handful of them. Somebody else designs a new view and looks at the model, they may not know which of those properties are sent and under what conditions they are set. Consequently they may be attempting to display data that does not exist. This isn't a very clean approach.
I would stick to individual view models and where there is common functionality between views, create an abstraction or base ViewModel from which other view models can extend.
Edit: One other thing you could do is use the new MVC 3 (still in preview) syntax (dynamic) for setting ViewData properties directly as if they were properties.
So rather than doing
ViewData["FirstName"] = "Bob";
You can do
ViewModel.FirstName = "Bob";
This gives you dynamic variables automatically in MVC 3.

Have a look a Clay the 'malleable' object model being used by the Orchard Project.
http://weblogs.asp.net/bleroy/archive/2010/08/16/clay-malleable-c-dynamic-objects-part-1-why-we-need-it.aspx
http://weblogs.asp.net/bleroy/archive/2010/08/18/clay-malleable-c-dynamic-objects-part-2.aspx

There's no reason it shouldn't work.
You can even skip the Model class and create an anonymous type with just the members you need.
return View(new { Amount = 108, Message = "Hello" });
The problem using anonymous types is that you're giving up on auto-completion in the view since you won't be able to type the view according to the model.

Just use dynamic

Related

Should I always use a view model or is it ok to use ViewData?

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.

Shuould we perform LINQ directly in asp net mvc views

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.

ASP.NET MVC Model vs ViewModel

OK, I have been hearing discussion about "ViewModels" in regards to MS's ASP.NET MVC.
Now, that is intended to be a specific kind of Model, correct? Not a specific kind of View.
To my understanding, it's a kind of Model that has a specific purpose of interacting with the View? Or something like that?
Some clarification would be appreciated.
Essentially Model and View Model are both simple classes with attributes.
The main objective of these classes are to describe (to "Model") an object for their respective audiences that are respectively the controller and the view.
So you are completely right when you say
To my understanding, it's a kind of
Model that has a specific purpose of
interacting with the View
So, while Model classes are effectively Domain Entities that your application interact with, View Models are simple classes that your views interact with.
Hope it helps :)
Update:
Microsoft has developed a specialized version of the Presentation Pattern by Martin fowler largely based on the Model-View-Controller and called it Model-View-ViewModel (MVVM) for PF application. This pattern is targeted at modern UI development platforms where UI developers have different requirements based more on business logic than traditional developers. Have a look here for a bit of theory
In the simplest of terms, I like to think of the following:
Model: Strictly looks and feels like your data model. For all intents and purposes it is only a class representation of your data model. It has no knowledge of your View or any elements within your View. That said, it should not contain any attribute decorators (ie; Required, Length, etc.) that you would use for your View.
View Model: Serves as a data-binder between your View and your Model and in many cases, is also a wrapper for your Model. It would be rendered useless without the View, so it typically isn't reusable across multiple Views and Controllers like a standard Model is.
As an example, your Model may have the following properties, which are direct representations of your data source:
public string FirstName { get; set; }
public string LastName { get; set; }
Now, since your View Model is tied to your View, it may have the following property - which concatenates the Model's FirstName field and LastName field together as one string:
[Display(Name = "Customer Name")]
public string CustomerFullName { get { return String.Format("{0} {1}", myModel.FirstName, myModel.LastName) }}
I found this article a very useful resource for understanding how the "Domain Model" and "View Model" interact within an MVC application, particularly in regards to binding. Best of all includes examples instead of abstract descriptions.
"Since MVC has been released I have observed much confusion about how best to construct view models. Sometimes this confusion is not without good reason since there does not seem to be a ton of information out there on best practice recommendations. Additionally, there is not a “one size fits all” solution that acts as the silver bullet. In this post, I’ll describe a few of the main patterns that have emerged and the pros/cons of each. It is important to note that many of these patterns have emerged from people solving real-world issues."
http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
WikiPedia has a more complete description of Model vs. ModelView than you'll get in an SO answer: http://en.wikipedia.org/wiki/Model_View_ViewModel
I quote:
Model: as in the classic MVC pattern, the model refers to either (a) an object model that represents the real state content (an object-oriented approach), or (b) the data access layer that represents that content (a data-centric approach).
View: as in the classic MVC pattern, the view refers to all elements displayed by the GUI such as buttons, windows, graphics, and other controls.
ViewModel: the ViewModel is a “Model of the View” meaning it is an abstraction of the View that also serves in data binding between the View and the Model. It could be seen as a specialized aspect of what would be a Controller (in the MVC pattern) that acts as a data binder/converter that changes Model information into View information and passes commands from the View into the Model. The ViewModel exposes public properties, commands, and abstractions. The ViewModel has been likened to a conceptual state of the data as opposed to the real state of the data in the Model.
There is a notion of a ViewModel, but it is not generally associated with Asp.net MVC. MVC uses the Model View Controller patter, where the controller handles interactions, builds up data from the Model, and then passes that data to the View for display.
ViewModels (and the Model View ViewModel pattern) is more generally associated with Silverlight and WPF. Xaml is a bit different in that the views can do two-way binding to the ViewModels, so the technology is a little different. For example, if you bind a textbox to a field, as you type into that textbox, the value of the field is updated dynamically. This sort of interaction isn't really possible in web pages since web pages are stateless.
The similarity in the two patterns is that they are both trying to separate the logic from the display. The most common use/reason for this is testing: you want to be able to perform from code (via a testing framework) all the interactions that a user will invoke via the User Interface.

What to put in your ViewModel

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).

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