12

I am new to ASP.NET MVC 3.0 and trying to build an application using the MVC ViewModel design..

I was wondering what the best practices are regrading controllers for ViewModels and have a few questions below.. This is my understanding so far (which might be wrong)..

  • We create Models.
  • Create ViewModels by making a new class and declairing attributes with the same name and type as the base model classes (including ID fields of the base models you want to update later.. and the classes are not linked in any way).
  • Create a Repository for each of the base models (to find and save data ect.).
  • Create a Controller action for each of the ViewModels (which access the repositories of the base classes to retrieve values and put these values into the ViewModel, then pass the ViewModel to the ViewModels View).
  • Create Views from the ViewModels (ViewModel Views)
  • In the ViewModel controller Update (POST) method recieve the updated ViewModel object and convert it into base model objects (Maybe use Automapper?) and next save the base model objects back using their repositories and apply binding like this? "TryUpdate<'IPerson>(person)", "TryUpdate<'IPlace>(place);" (this looks wrong, the aim is to put the values back into the base classes from the ViewModel, apply binding, save base models back using the repositories!.. This doesnt appear to use the repositories.. Instead of TryUpdate<'IPerson>(person); I would expect to see something like this: person.Save(IPerson).. where "person contains the values", ".Save is the repository", and "IPerson contains the binding attributes to use for binding"?.. Not sure if this is right..

So far I have created ViewModels by making a new class and adding attributes from different base models using the same names. At this point i have the following questions:

Q1: Does each ViewModel have its own controller and access each of the base models repository classes to get its values?

Q2: in the ViewModel should you include the ID field of all of the base models that you are using attributes from, considering that you might want to POST an Update back through the ViewModels Controller to the base Models repository (needing the ID values)?

Q3: How would you bind attributes using an interface for binding the model in the controller using the repository to save.

I have been unable to find a tutorial or resource that explains everything in a step by step example, A complete answer would be the following example:

  • 2x simple models, 1x simple viewModel, 1x interface for binding, 1x simple controller using an interface class for binding on update, 1x repository.. i.e.

//Model1

public class Person
{
  int PersonID {get;set;}
  string FirstName {get;set;}
  string LastName {get;set;}
  DateTime DOB {get;set}
}

//Model2

public class Place
{
  int PlaceID {get;set;}
  string Description {get;set;}
  string AreaType {get;set;}
  string PostCode {get;set;}
}

//ViewModel (containing attributes from models)

publc class ViewModel
{
  //Person attributes
  int PersonID {get;set;}
  string FirstName {get;set;}
  string LastName {get;set;}

  //Place attributes
  int PlaceID {get;set;}
  string Description {get;set;}
  string AreaType {get;set;}

  //other attributes
  string someOtherAttributeForDisplay {get;set}
}

//Model1 interface (for binding on model)

public interface IPerson
{
  string FirstName {get;set;}
}

//Model2 interface (for binding on model)

public interface IPlace
{
  string Description {get;set;}
  string AreaType {get;set}
}

//ViewModelController?

{
  //What goes here?
}

//Repository?

{
  //what goes here?
}
HonourCode
  • 318
  • 1
  • 3
  • 14
  • Hi Mitch, I have been looking into using NuGet to add Unity and EntLib to my projects, I'm not quite sure of their purposes yet tho.. – HonourCode Oct 27 '11 at 11:28

1 Answers1

5

I think you may have overcomplicated a very simple concept.

First off some general rules:

  • Don't use TryUpdateModel. Just don't.
  • For the same reasons, don't use any "auto" mapping mappers to map from your view model to your entities. Auto mapping the other way round (from entity to view model) is fine.

Your use of interfaces is unnecessary.

View models are supposed to be very simple classes that contain just the information you need for your view. If your view POSTs different information from what it displays, then just create a different view model for POST.

We use a naming convention of {Controller}{Action}Model for our view models. So for an action named "List" on a "Post" controller we will have a model called "PostListModel".

Finally, check out my response here Real example of TryUpdateModel, ASP .NET MVC 3

Community
  • 1
  • 1
Ben Foster
  • 34,340
  • 40
  • 176
  • 285
  • Thankyou for your reply.. Are you aware that you can bind values on the TryUpdate method by including an interface followed by the model? i.e. TryUpdate<'IPerson>(person) I found some information here that i have been following but changed slightly in my version to allow properties to be displayed in the view and bound later in the controller (thats the concept): http://codetunnel.com/blog/post/79/aspnet-mvc-model-binding-security.. do you think this guy is onto something or off his rocker? :) – HonourCode Oct 27 '11 at 10:44
  • It seems to me that using interfaces in this way is only to address the shortcomings of using TryUpdateModel (to limit the properties that are updated), something that can be achieved just through simple left-right mapping. – Ben Foster Oct 27 '11 at 10:59
  • The advantage is supposidly that you can use an automapper to map the properties so that you can reduce code by not having to do left-right mapping, instead you can just pass objects round.. And if Fiddler changes attributes then it doesnt matter because binding wont allow the values to be saved in the TryUpdate<'IModel>(model) the same way left-right mapping works.. I was wondering, Which Controller would a ViewModel need?.. It's own or would it use the base class controllers? :S.. – HonourCode Oct 27 '11 at 11:03
  • I can't see that you're saving any code considering you will have to write an interface for every viewmodel. A viewmodel doesn't have any reference to the controller. You should have a viewmodel for each action method within your controller (like in my example). – Ben Foster Oct 27 '11 at 11:06
  • I can see your point!.. :) lol.. Only advantage is that it reduces code in the controller then but i'll have to consider if it's worth it then :S.. Which controller would you recommend for my example of a ViewModel that uses values from a Person model and Place model and other attributes.. i.e. the PersonController or PlaceController to place the ActionMethod. – HonourCode Oct 27 '11 at 11:19
  • You don't have to have a controller per entity type. Name your controller and actions based on their responsibility. For example if I was assigning a person to a place, then I might have a `AssignPersonToPlace` action on my PlaceController. If I was assigning a place to a person I might have a `AssignPlaceToPerson` action on my PersonController. There is no hard and fast rule. Best thing is to read out loud what "business" process you are performing and name your controllers, actions, methods, whatever, accordingly. – Ben Foster Oct 27 '11 at 13:00
  • **"don't use any "auto" mapping mappers to map from your view model to your entities"** - really? So you do left to right boilerplate code in all your `[HttpPost]` actions? I think your underestimating how intelligent and extensible something like AutoMapper is. – RPM1984 Oct 27 '11 at 22:50
  • @RPM1984 - yes I do. I think you will find that much of the AutoMapper community share this opinion. I know Jimmy Bogard does, and that's enough for me. I'm not underestimating how powerful AM is, I use it almost every web application for denormalizing my domain objects into view models. – Ben Foster Oct 27 '11 at 23:56
  • Automapper isn't the only tool here. Jimmy shares that opinion seemingly because automapper wasn't designed for it because their pattern doesnt call for it. They use a different pattern than most seem to use for mvc looking at projects on the net. not that its wrong, its just something else. If you want to map from an entity back, feel free. See ValueInjecter as well as they provide a bit more functionality for going back to an entity. If I flatten out, no reason I cant hydrate back. @Rpm1984 I tend to agree with you on going both ways with entities here. It makes sense to me to map back. – Adam Tuliper Feb 17 '12 at 21:53
  • @AdamTuliper - funny thing is, 5 months on from my above comment, i only map from domain -> VM's now, and i left-to-right between VM -> domain in my controller. This is for a few reasons (mainly EF4). Funny how opinions change over time. – RPM1984 Feb 17 '12 at 23:13
  • @RPM1984 why with EF4? because of the fake 'modified' state it leaves it in? it is unfortunate, although you can detach/mark as modified to work around that. – Adam Tuliper Feb 18 '12 at 16:51
  • @AdamTuliper - yep, because of the way it handles the entity state. Don't want to change now anyway, next time i'll change it will be to get rid of EF4 altogether, but that's another story. :) – RPM1984 Feb 18 '12 at 23:48
  • @RPM1984 ha I just did an EF 4.3 session today in FL trying to push EF : ) 4.3 has some nice new features (code migrations are quite sweet, especially the "Update-Database -Script" package manager option) I'll delete this msg shortly as it doesnt belong here anyways – Adam Tuliper Feb 19 '12 at 06:49
  • @AdamTuliper - bottom line is that the queries it generates are poor. I know, i've optimized the queries as much as i can, but it's not good enough. Lack of filtering when eager loading, etc the list goes on. I started out with all EF queries, now basically every call in my app is a stored procedure. – RPM1984 Feb 19 '12 at 08:52
  • "Don't use TryUpdateModel. Just don't." Can you expand on that point more? – Ciaran Gallagher Nov 13 '18 at 10:04