Showing posts with label Stackoverflow. Show all posts
Showing posts with label Stackoverflow. Show all posts

Friday, September 28, 2012

Sunday, June 3, 2012

Using AutoMapper to copy Metadata from Entities to ViewModels


On my crusade to eliminate common mistakes causing bugs in my projects I found was that my metadata on my entities didn’t always match my viewmodels.  I wrote 2 fairly simple providers to copy the metadata from the entity to the ViewModel at runtime which leverages my AutoMapper configuration so it supports field names that are renamed.


I use the approach below to automatically copy data annotations from my entities to my view model. This ensures that things like StringLength and Required values are always the same for entity/viewmodel.

It works using the Automapper configuration, so works if the properties are named differently on the viewmodel as long as AutoMapper is setup correctly.

You need to create a custom ModelValidatorProvider and custom ModelMetadataProvider to get this to work. My memory on why is a little foggy, but I believe it's so both server and client side validation work, as well as any other formatting you do based on the metadata (eg an asterix next to required fields).

Note: I have simplified my code slightly as I added it below, so there may be a few small issues.

Metadata Provider

Validator Provivder

Helper Method Referenced in above 2 classes

Other Notes
If you're using dependency injection, make sure your container isn't already replacing the built in metadata provider or validator provider. In my case I was using the Ninject.MVC3 package which bound one of them after creating the kernel, I then had to rebind it afterwards so my class was actually used. I was getting exceptions about Required only being allowed to be added once, took most of a day to track it down.


My StackOverflow Post: http://stackoverflow.com/questions/9989785/technique-for-carrying-metadata-to-view-models-with-automapper/10100042#10100042

Dependency Injection for RouteConstraints


Often I've wanted to check whether something exists in the database in a route constraint, unfortunately MVC doesn't support dependency injection for RouteConstraints out of the box, and due to them being alive for the entire life of the application it isn't that easy. If the scope of the dependency is in request scope, for example, then it will work for the first request then not for every request after that.

You can get around this by using a very simple DI wrapper for your route constraints.

then create your routes like this
 

My StackOverflow Post

Updating collections using AutoMapper


By default AutoMapper replaces child lists with a completely new instance only containing the items in the original list.  Because of the way EF works you need to change the existing items in the list for it to track changes as updates instead of adds.  This method also means deletes can be tracked succesfully.
Basic steps were
Ensure the destination collection is loaded from db and attached to the object graph for change tracking
    .ForMember(dest => dest.Categories, opt => opt.UseDestinationValue())
Then create a custom IObjectMapper for mapping IList<> to IList<T> where T : Entity
The custom IObject mapper used some code from http://groups.google.com/group/automapper-users/browse_thread/thread/8c7896fbc3f72514
Finally one last piece of logic to check all Id's in targetCollection exist in sourceCollection and delete them if they don't.
It wasn't all that much code in the end and is reusable in other actions.

My Stackoverflow Post: http://stackoverflow.com/questions/9739568/when-using-dtos-automapper-nhibernate-reflecting-changes-in-child-collections/9856360#9856360
Recently found a library that does just this - https://github.com/TylerCarlson1/Automapper.Collection