views:

555

answers:

5

By picking MVC for developing our new site, I find myself in the midst of "best practices" being developed around me in apparent real time. Two weeks ago, NerdDinner was my guide but with the development of MVC 2, even it seems outdated. It's an thrilling experience and I feel privileged to be in close contact with intelligent programmers daily.

Right now I've stumbled upon an issue I can't seem to get a straight answer on - from all the blogs anyway - and I'd like to get some insight from the community. It's about Editing (read: Edit action). The bulk of material out there, tutorials and blogs, deal with creating and view the model. So while this question may not spell out a question, I hope to get some discussion going, contributing to my decision about the path of development I'm to take.

My model represents a user with several fields like name, address and email. All the names, in fact, on field each for first name, last name and middle name. The Details view displays all these fields but you can change only one set of fields at a time, for instance, your names. The user expands a form while the other fields are still visible above and below. So the form that is posted back contains a subset of the fields representing the model.

While this is appealing to us and our layout concerns, for various reasons, it is to be shunned by serious MVC-developers. I've been reading about some patterns and best practices and it seems that this is not in key with the paradigm of viewmodel == view. Or have I got it wrong?

Anyway, NerdDinner dictates using FormCollection och UpdateModel. All the null fields are happily ignored. Since then, the MVC-community has abandoned this approach to such a degree that a bug in MVC 2 was not discovered. UpdateModel does not work without a complete model in your formcollection.

The view model pattern receiving most praise seems to be Dedicated view model that contains a custom view model entity and is the only one that my design issue could be made compatible with. It entails a tedious amount of mapping, albeit lightened by the use of AutoMapper and the ideas of Jimmy Bogard, that may or may not be worthwhile. He also proposes a 1:1 relationship between view and view model.

In keeping with these design paradigms, I am to create a view and associated view for each of my expanding sets of fields. The view models would each be nearly identical, differing only in the fields which are read-only, the views also containing much repeated markup. This seems absurd to me. In future I may want to be able to display two, more or all sets of fields open simultaneously.

I will most attentively read the discussion I hope to spark. Many thanks in advance.

A: 

I met the UPDATE problem too.

When I try to update a subset of fileds, find some fileds that are not used in the form are set to the default value.

I don't know how to update an entity simply.


Sorry, I can not just add a comment to the main post, maybe I have not enough reputations?

C.T.
@C.T. look at the sample asp.net mvc application in the download of the http://valueinjecter.codeplex.com/, it demonstrates lots of ways of how to update your entities
Omu
A: 

I have the exact same problem, but I wouldn't be able to formulate it that well.

In my case, there would be tons of ViewModels, because different users would see different forms based on a set of roles. I think the 1:1 relation between ViewModel and View is very vague. What if I write an uber-View which pretty much simply uses EditorForModel and not much more? Now I have one, albeit highly degenerate, view for everything, so I also have only one ViewModel?

My idea was to write an EditorForModel that works not only based on reflection (that is, information known at compile time), but also on (domain specific) runtime rules, for example governed by the current user's role, the current time, etc. Consequently, one also needs to write a custom ModelBinder with validation as well as a custom mapping from Model to ViewModel. Still, this keeps me from writing stupid and thus error-prone code.

Since my Model (or DomainModel) contains a lot of logic, I don't want it to be modified via ModelBinding at all. Moreover, since it is impossible to know what fields will be present at compile time, providing an appropriate ViewModel is impossible. However, the 'full', i.e. maximal ViewModel is known. Mapping from the ViewModel to the Model again involves custom code, but as long as the rules can be formalized, that should work out.

Sorry my text is very confusing, but I am very confused right now myself, plus I gotta run. Like C.T., couldn't comment either.

mnemosyn
@mnemosyn use ValueInjecter http://valueinjecter.codeplex.com/ and map the FormCollection (or Request) to your entities (it's done automatically), there is a sample asp.net mvc application in the download that demonstrates this
Omu
+1  A: 

There have been a few posts recently around the issue of validating your models, resulting in this post from Brad Wilson "Input Validation vs. Model Validation in ASP.NET MVC".

The initial issue was to do with how ASP.NET MVC handled validating a posted model, and if there were elements of your model that you didn't want edited and didn't supply fields for in the view, but your controllers were working with the whole model, it's possible that someone could craft a POST to your controller with the additional fields.

Therefore using a View specific Model enables you to ensure that only the fields you want edited can be edited.

Zhaph - Ben Duguid
A: 

Check this out. This is the way to go with ASP.NET MVC 2.

        public void Update(MyModel model)
        {
            var myModelObject = MyRepository.GetInstance(model.Id);
            if(myModelObject != null)
            {
                ModelCopier.CopyModel(model, myModelObject);
            }
            MyRepository.Save(myModelObject);
        }

ModelCopier.CopyModel(obj from, obj to) is a new function in the latest MvcFutures. Also be sure to check out the Extensible Model Binder in MVC Futures 2.

mare
I will, thank you.
Martin
This isn't really using a view model though is it? Just seems to be a transient copy of the actual entity?
UpTheCreek
A: 

I am doing it like this (the mapping is done automatically inside modelBuilder with the ValueInjecter):

I have a sample asp.net-mvc application where I demonstrate the best practices of doing this in mvc, you can see it in the download of the valueinjecter

 public ActionResult Edit(long id)
 {
      return View(modelBuilder.BuildModel(personService.Get(id)));
 }

 [HttpPost]
 public ActionResult Edit(PersonViewModel model)
 {
    if (!ModelState.IsValid)
       return View(modelBuilder.RebuildModel(model));    
       personService.Save(modelBuilder.BuildEntity(model));
       return RedirectToAction("Index");
 }

a quick demo of the ValueInjecter:

//build viewmodel
    personViewModel.InjectFrom(person)
                   .InjectFrom<CountryToLookup>(person);

//build entity
    person.InjectFrom(personViewModel)
          .InjectFrom<LookupToCountry>(personViewModel);
Omu
What are the main differenes from Bogards AutoMapper would you say?
Martin
@Martin with the Automapper you have to create mappings for each possible pair of object to object mapping and show how to map each property in part (if they are not of the same names), and you have to set ignores if you don't need them, now with ValueInjecter you don't have to do all this stuff, also with ValueInjecter you can do flattening and unflattening (from one type to a different one using a your algorithm of setting the value) there are lots of examples in the download
Omu