AutoMapper is pretty cool. It spares you all of the right-hand, left-hand stuff of manually mapping properties of domain objects to view models. I wish I understood it better. We aim to use it more substantially in our app. I was asking Rafael some questions about it yesterday and he reinforced some of what I blogged of here.
- typically Global.asax.cs references BootStrapper.cs
- BootStrapper.cs initializes various profiles
- typically an app will have one profile per project
- a profile governs a particular concern (mapping POCOs to view models, mapping view models back to POCOs)
- a profile will contain mapping rules if one cannot rely on naming convention for automapping (and one should try to do so)
- a formatter manages simple formatting rules
- a resolver requires a specific value and typically has more logic and dependencies to it
A example of what one might find in a profile:
Mapper.CreateMap<Account, AccountDetailViewModel>()
.ForMember(x => x.AccountTypeName, y => y.MapFrom(z =>
z.Division.AccountType.Name))
.ForMember(x => x.DivisionName, y => y.MapFrom(z => z.Division.Name))
.ForMember(x => x.ParentAccountName, y => y.MapFrom(z => z.ParentAccount
!= null ? z.ParentAccount.Name : string.Empty));
A example of coloring an action with an attribute: (a Foo is prepped in the action but a Bar is ultimately handed to the view at binding)
[AutoMap(typeof(Foo), typeof(Bar))]
public PartialViewResult Whatever(Guid id)
{
var foo = FooRepository.GetById(id);
foo.SomethingErOther = "this thing";
return View("whatever", foo);
}
The attribute:
using System;
using System.Web.Mvc;
using AutoMapper;
namespace OurApp.Web.UI.ActionFilters
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class AutoMapAttribute : ActionFilterAttribute
{
private readonly Type _sourceType;
private readonly Type _destType;
public AutoMapAttribute(Type sourceType, Type destType)
{
_sourceType = sourceType;
_destType = destType;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var model = filterContext.Controller.ViewData.Model;
var viewModel = Mapper.Map(model, _sourceType, _destType);
filterContext.Controller.ViewData.Model = viewModel;
}
public Type SourceType
{
get { return _sourceType; }
}
public Type DestType
{
get { return _destType; }
}
}
}
A whiteboarding by Rafael:
At the left, an example of automapping:
var program = AutoMap.Map<SaveProgram, Program>(saveProgram);
Here we take an instance of SaveProgram called saveProgram and cast it to a Program called program.
At the right, showing how an object with a POCO getsetter may be flattened with its child into one simple view model without any getsetters that are not simple types.
No comments:
Post a Comment