ASP.NET MVC Done Right: View Models - asp.net-mvc

I read this q/a Real example of TryUpdateModel, ASP .NET MVC 3 and was really interested on #ben-foster response.
I started doing a comment on that answer but got quite long, so started a new Question.
Having ViewModels for everything approach (which i like a lot) get me into some 'weird scenarios' that i want advice in how should I do.
Imagine this structure :
public class ProductListEditableViewModel {
List<ProductEditViewModel> products {get;set;}
}
public class ProductEditViewModel {
List<PriceViewModel> prices {get;set;}
}
public class PriceViewModel {
CurrencyViewModel currency {get;set;}
}
and so on ... ? do you really make one view model for each inner class? how then you map all that to the Model Object?
Also, that covers the Edit, but I have an Add, a send via email, and potentially more Views so more ViewModels!! should i end like something :
AddCurrencyViewModel
QuickAddCurrencyViewModel
EditCurrencyViewModel
ListCurrencyViewModel
DeleteCurrencyViewModel
ShareCurrencyViewModel
all having the 'almost same' properties ?
Should all those be packed into one file ?
Also do i need all this all viewModels or a inheritance approach might be better?
If you can, I´ll appreciate elaborate on complex scenarios
Also, I use a DTO approach to expose some of the model objects into web service / apis, so I already have some form of mapping already in place where this DTO are not exactly my ViewModels, should I remove one of them? what´s the suggestion in this scenario ?
I´m using entity framework but i think the question is (or should be) ORM agnostic.
Not using UoW pattern (will this helps?) as looks it´s gets more complicated as the depth of the object increases.
Thanks a lot!

We typically have a view model per view so yes, if you have lots of views you will have lots of view models.
In typical CRUD applications we often have very similar views, for example Add and Update. In these cases, yes we use inheritance rather than writing duplicate code - usually Add subclasses Update.
public class AddFoo : UpdateFoo {
public AddFoo() {
// set up defaults for new Foo
}
}
public class UpdateFoo {
public string Name { get; set; }
// etc.
}
We attempted to "share" view models between views in the past and normally ended up in a world of pain.
With regard to your "weird scenario" - this does look weird indeed, but perhaps because I don't understand your application.
The goal of your view model is to provide the information to the view that is needed and ideally to flatten any complex objects so they are easier to work with. You shouldn't split your view models up like your example unless it makes sense to do so.
Let's say I wanted to a create a view where the customer could change their contact details. Taking the following domain object:
public class Customer {
public string FirstName { get; set; }
public string LastName { get;set; }
public Address Address { get; set; }
}
I'd probably flatten this to a view model like so:
public class UpdateAddressModel {
public string FirstName { get; set; }
public string LastName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressCity { get; set; }
// etc.
}
Of course there will be occasions where it doesn't make sense to do this, for example a dashboard view in an online store where you have a list of products going out of stock and a list of recent orders - these two things are unrelated but are required by your view:
public class DashboardModel {
public List<Product> ProductsGoingOutOfStock { get; set; }
public List<Order> NewOrders { get; set; }
}
how then you map all that to the Model Object?
I'm assuming by Model Object you mean your data/domain model. The key takeaway here is that the view model you use to render your view is unlikely to be the same as the "models" you POST to the server and if they are, you're probably over-POSTing or you have some crazy enter-everything data capture screen that will make your eyes bleed.
I find it helps to think of what you send to your server as Commands and what you use to render your views as view models.
So the answer to your question - how do you map your complex view model to your data model? - Quite simply, you don't. You should send commands to the server that perform a specific task e.g. updating an address.
There's no hard and fast rule in how you structure your view models but generally go with what makes sense and if it starts to feel too complicated you're probably trying to do too much with one view.
I hope this helps. You'll find lots of posts relating to this matter on my blog.

I realize this is an old-ish question but I did want to address one of the questions posed by the OP that was not answered.
Should all those [ViewModels] be packed into one file ?
Most of the examples I see put each ViewModel in a separate file, so the dominant convention seems to be one file per viewmodel, but I found in practice that this seems to be overkill. Instead I put all viewmodels for a particular controller in one file with multiple viewmodels in it. So for example if User is my Controller and I have several viewmodels associated with this controller such as UserAddViewModel, UserEditViewModel, UserDeleteViewModel I put all of the viewmodels for User in one file called UserViewModels.cs

Related

Naming Convention for ViewModel Child Objects

I am building an ASP.Net MVC application using a ViewModel approach to keep my domain entities separate from the "models" used by my UI. I am using the following convention for naming my ViewModel classes. ViewModelName = ViewName + "ViewModel". For example:
Index + ViewModel = IndexViewModel
So far, so good, this is a fairly common pattern and there is a lot of guidance on this topic on StackOverflow and elsewhere. My question concerns child objects used by my ViewModels. If my ViewModel requires a class with properties identical to my a domain model object, I simply include the domain model within my ViewModel. For example:
public class PersonViewModel
{
public int PersonID { get; set; }
public Address Address { get; set; }
public string SomeOtherProperty { get; set; }
}
However, I am not sure what naming convention to use when I need a child object with different properties from my domain model. For example if Address needed a few additional properties besides what is in the Address domain model, what should I call it? I considered AddressViewModel like so:
public class PersonViewModel
{
public int PersonID { get; set; }
public AddressViewModel Address { get; set; }
public string SomeOtherProperty { get; set; }
}
but that just doesn't feel right to me. My gut instinct is that the ViewModel suffix should only be for the top level ViewModel.
I am looking for suggestions from other developers on what naming conventions they use in this scenario, specifically what would you call the child object in this case?
I'm going to put an answer on this just because no one else has! (I know I'm a little late to this party!)
I've pondered over this exact thing many times and tried different conventions over the years. The one thing I picked up on is that you are using a naming convention...
If your naming convention is to suffix your UI model classes with 'ViewModel' then the child models should have the same suffix otherwise you're breaking your own convention!
Also lets say you have an Address table (or whatever you have) and a Customer can have an address and a Company has an address and they both use the same table, then you may use the same child model for both parent models. It seems right to have an AddressViewModel. One day you might have a View/PartialView and it's model is IEnumerable<AddressViewModel>
I know there's no real right answer to this, but this is my answer :-)

Using an MVC Model as a filter in the repository

I have a details view that is typed to IEnumerable. The view with a bunch of drop downs that let you add filters to the list of records rendered.
All these dropdowns correspond to properties on the MVC model:
public class Record
{
public string CustomerNumber { get; set; }
public string CustomerName { get; set; }
public string LineOfBusiness{ get; set; }
public DateTime? Date { get; set; }
}
Now, I'm using my model as my dto to shuffle data between my controller and my repo. Since all my drop down filters represent the model properties, I pass my model to a repo retrieval method, check its properties and filter based on its values? In other words:
public IEnumerable<TradeSpendRecord> Get(TradeSpendRecord record)
{
IQueryable<tblTradeSpend> query = _context.tblRecords;
if (!String.IsNullOrEmpty(record.CustomerName))
query = query.Where(x => x.CustomerNumber == record.CustomerNumber);
if (!String.IsNullOrEmpty(record.LineOfBusiness))
query = query.Where(r => r.LOB == record.LineOfBusiness);
SNIP
Hope this isn't too subjective, but I'm wondering if anyone has any input about whether this is a good/bad practice. I haven't seen a whole lot of examples of dynamic filtering like I need to do, and am looking for some guidance.
Thanks,
Chris
If you're doing what I think you're doing, I'm not sure this is the best way of doing it.
Keep your 'Models' in your MVC/presentation layer (whether this is one physical assembly or not) dedicated to your presentation layer. The only things that should be touching them are your Views and your Controllers. You don't want what should be independent entities to be so tightly coupled to your View Models.
I'd suggest creating a separate TradeSpendFilter class, which, at its simplest, exposes the filterable properties of your domain entity (likely more than any given View Model). You'd then pass this into your "filtering service" or whatever it may be. This also means you can extend your filtering functionality independent of both your domain models and your MVC app. For example, if you suddenly want to filter multiple objects, you can simply change...
public class TradeSpendFilter
{
public string CustomerName { get; set; }
...
}
...to...
public class TradeSpendFilter
{
public IEnumerable<string> CustomerNames { get; set; }
...
}
... without causing all sorts of problems for your MVC app.
Additionally, it will also mean you can make use of your filtering functionality elsewhere, without tying further components to your MVC app and ending up in a bootstrapped mess.

Benefits of not passing entities to view

I usually see people telling that you should not pass entities to your View. They say you should use a DTO/VO/ViewModel/AnyOtherThingYouWant instead, as using an entity would increase the coupling.
Ignoring the moments where I do need some extra logic (or I don't need all the properties), I fail to see any benefits in doing this. For example, consider the following class:
public class Contact {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
I see lots of code that creates another class, like this:
public class ContactDTO {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
use it in the View and then do this:
someMapper.Map(contactDto).To<Contact>();
I can't see how better this is than simply using the Contact class, as your View would be coupled to a class that is coupled to the entity's class. So, every change in one should be replicated into the other. From my point of view, the 'middle' object is there just to add complexity, but not real value.
I know that there's no 'one size fits all' solution (as sometimes, using the middle object would make sense), but do we really need adding code like this? What are the real benefits?
Think of it this way: a view is a projection of your domain. It's a specific representation of your business model. So you need to use a view model which will represent this projection. It could be a subset of the domain model but it could also be an aggregation of multiple domain models if the view requires it. The example you provided is just a specific case where there is a 1:1 mapping between the domain model and the view model because of the requirements of this specific view. But that's only one specific view. I suppose that your application has many views and different representations of your domain entities.
There are many view specific things that make your domain models unsuitable and thus the need of view models. For example validation. A given domain model property could be required in some view and not required on another view (think of Id property in Create/Update views). If you don't use a view model but have your Create controller action directly take the domain model you will have a problem if your domain model Id property is decorated with the Required attribute.
There are many other examples. If I had one advice to give you when developing an ASP.NET MVC application it would be this: always define specific view models for your views and never pass/take domain models to/from views and this stands true even in cases where you have a 1:1 mapping between your domain model and the view model.
The cited approach is a kind of purism. If you do not need to transform (reduce, merge, whatever) your domain objects and they are directly usable in your view as they are, use them - you can introduce DTO via refactoring later, when necessary.
So you have to take into consideration what Darin Dimitrov said but keep in mind that DTOs and similar are here to make your work easier. I recall one project I worked on - more than 90% of DTOs were ono-to-one copies of the domain objects - this is totally useless and only adds to the maintenance cost.

Advice on structuring MVC ViewModel Classes (Parent with many children)

I'm writing a message board webpage. The page consists of a Topic item, then a list of Response and a form to add an additional response.
Im struggling to structure my page and viewdata classes in such a way that they are clean and allow me to take advantage for editor templates and validation attributes.
Currently I have one page to do all the above, and Im thinking my viewdata class will eventually look something like this:
public class TopicViewsData
{
[ValidateNonEmpty("Please enter some text")]
public string Title { get; set; }
[ValidateNonEmpty("Please enter some text")]
public string TopicBody { get; set; }
public IList<TopicResponseViewsData> Responses { get; set; }
public TopicResponseViewsData NewResponse { get; set; }
}
public class TopicResponseViewsData
{
[ValidateNonEmpty("Please enter some text")]
public string ResponseText{ get; set; }
}
My page is typed to a TopicViewsData, it just seems ugly that I have to have NewResponse property just so the page can have access to the validation attributes on TopicResponseViewsData. Is there a nicer way to do this?
Sounds like you are headed towards a massive and complex view, not to mention the issues you are already seeing with your model structuring. Rather than making trade offs to make what you have work I have a few recommendations on your overall view model design.
I tend to separate my models into ViewModels and FormModels. ViewModels are for displaying data and FormModels are for taking user input. Not only does this provide a clear designation of function it generally allows me to keep my FormModel properties typed to primitives, strings, and dates in addition to providing a single place for applying validation logic. While, in my ViewModels I am afforded the flexibility to use complex property types and do not have to worry about validation logic.
To make things even easier I follow Jimmy Bogard's suggestion that you should have only one view per model. By not mixing and matching models I have found my models stay focused and my views do not turn into spaghetti. To keep things tidy I name my models similarly to the Controller and View they are tied to. I might end up with a few extra models, but it is a small price to pay for a cleaner design.
I think that the Body property in the TopicViewsData model is redundant with the NewResponse property.
So your view is working with responses where each response has a body. So:
public class TopicResponseViewsData
{
[ValidateNonEmpty("Please enter some text")]
public string Body { get; set; }
}
So far so good. Next you said that you have a list of responses to show and a new response to add, so:
public class TopicViewsData
{
public IList<TopicResponseViewsData> Responses { get; set; }
public TopicResponseViewsData NewResponse { get; set; }
}
For the moment, given your description that's all I see necessary in the view model. At least model reflects your scenario description.

New to MVC | Data in a view from different sources

OK, So i have been watching some MVC vids and reading some bits.
I am new to the entire MVC pattern, and until now have been happily wrapped up in the web forms world!
Like with so many demos it all seems great and I'm sure I'll have lots I dont understand as I move along, but in the first instance...
I can see that you can have a strongly typed view, which gets data from the controller. What happens if I want data in a view from different object types?? Say i want to show a grid of cars and a grid of people, which are not related in anyway??
Thx
Steve
Setup your strongly typed ViewData class with two properties like this
public class MyViewData
{
public IEnumerable<Car> Cars { get; set; }
public IEnumerable<People> People { get; set; }
}
and then fill them in the controller,
Sorry for the duplicate. In good MVC spirit try to use interfaces where possible to make your code more generic
Instead of artificially grouping models together you could keep then separate (logically and physically) and then in the view pull the various pieces together.
Check out this post for the a great explanation of [link text][1].
[1]: http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/ partial-requests
You can either pass both objects inside the ViewData hashtable, or create a MyViewViewModel, add two properties, and set them both from your controller.
What I think would be best to do in this situation would be create a class in the Models folder to hold both of these types.
Example:
public class CarsPeopleModel
{
public List<Car> Cars { get; set; }
public List<Person> People { get; set; }
}
Then your view would be:
public partial class Index : ViewPage<MvcApplication1.Models.CarsPeopleModel>
{
}

Resources