I've also tested injecting the services directly into the AutoMapper
profiles. You can actually get round the hard dependency on your
service locator by injecting in a Func<YourService>. However, an
additional downside of this approach is when you simply return the
view when modelstate is invalid (as we need to rebind any select
lists).
I quickly found that using the AutoMapView result doesn't really work
for our read models. Specifically, if we have a "list" model, it's
unlikely we will bind our view directly to the list. We tend to have
models like:
public class ProductListModel {
public IList<ProductModel> Products {get;set;}
public Customer CurrentCustomer {get;set;}
public class ProductListModel.ProductModel {
public string Name {get;set;}
}
}
So we can't simply do return AutoMapView<Product,
ProductListModel>(...);
instead we end up with something like:
var model = new ProductListModel {
Products = Mapper.Map<...>,
Customer = context.CurrentCustomer
};
But for Create/Edit models I think the AutoMapView is a nice approach.
After a few days of using it, I'm quite happy with my IModelEnricher
approach.
So let's say we have a model like:
public class Product {
public string Name {get;set;}
public string Category {get;set;}
}
public class ProductEditModel {
public string Name {get;set;}
public string Category {get;set;}
public IEnumerable<SelectList> Categories {get;set;}
}
When we call AutoMapView<Product, ProductEditModel> AutoMapper will
map our Name and Category properties. But we need to also pass our
list of categories.
To do this we just create a model enricher:
public interface IModelEnricher<TModel> {
TModel Enrich(TModel model);
}
public class ProductEditModelEnricher :
IModelEnricher<ProductEditModel> {
public ProductEditModel Enrich(ProductEditModel model) {
model.Categories = from c in categoryService.GetCategories()
select new SelectListItem { Text = c.Title, Value = c.Title }
}
}
The nice thing about this approach is we typically need to perform
this "enriching" both on the initial GET and on a failure (when
ModelState is invalid). By adapting our AutoMapView and our FormView
slightly we can enrich our model before passing it on:
var enricher = ObjectFactory.TryGetInstance<IModelEnricher<T>>();
if (enricher != null) {
form = enricher.Enrich(form);
}
You'll need to call this before returning your FailureResult within
FormViewResult and just before returning your View in
AutoMapViewResult.
I don't particularly love that I'm directly calling ObjectFactory, but
I prefer it to having to doing this within my controller action.
Perhaps there's a way of injecting dependencies into an ActionResult
which will make this approach a bit cleaner?
> > On Wed, Jul 6, 2011 at 9:18 AM, Mathias Stenbom <
math...@stenbom.com>wrote:
>
> >> EDIT:
>
> >> Im also very curious as to how others are solving these situations. To me
> >> this is common to any scenario where you have more than one source mapping
> >> to a single destination. Iv tried a few different approaches, and to be
> >> honest *none which im really satisfied with*. Ill post em to see what you
> >> think anyway!
>
> >> One way of doing it is to create a class that contains all the data you
> >> need. Following your example, it might look like this:
> >> class MappingSource {
> >> Product Product;
> >> IEnumerable<Category> Categories;
> >> }
> >> And then create a map like so: CreateMap<MappingSource, ViewModel>()...
> >> In the controller you can then create your class and fill it with data
> >> from your services, and then map from that object.
>
> >> But then the next step might be to create a maps like these aswell:
> >> CreateMap<Product, MappingSource>().. and
> >> CreateMap<Product, ViewModel>()...
> >> And then I end up with a 2 step mapping.
>
> >> Also, the 3rd step might even be to let your MappingSource have some
> >> required services (the category service in this case) as dependencies and
> >> let your ioc container resolve that for you.
>
> >> Samples here are far from complete, but I hope you understand what I mean
> >> =)
>
> >> On Wed, Jul 6, 2011 at 4:17 PM, Mathias Stenbom <
math...@stenbom.com>wrote:
>
> >>> Im also very curious as to how others are solving these situations. To me
> >>> this is common to any scenario where you have more than one source mapping
> >>> to a single destination. Iv tried a few different approaches, and to be
> >>> honest *none which im really satisfied with*. Ill post em to see what