<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Mike Nichols - Son Of Nun Technology : AutoMapper</title><link>http://devlicio.us/blogs/mike_nichols/archive/tags/AutoMapper/default.aspx</link><description>Tags: AutoMapper</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>ditto : with regard to AutoMapper</title><link>http://devlicio.us/blogs/mike_nichols/archive/2011/04/10/ditto-with-regard-to-automapper.aspx</link><pubDate>Sun, 10 Apr 2011 23:08:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:66862</guid><dc:creator>Michael Nichols</dc:creator><slash:comments>2</slash:comments><comments>http://devlicio.us/blogs/mike_nichols/archive/2011/04/10/ditto-with-regard-to-automapper.aspx#comments</comments><description>&lt;p&gt;A comparison of &lt;a href="http://github.com/mnichols/ditto"&gt;&lt;em&gt;ditto&lt;/em&gt;&lt;/a&gt; to &lt;a href="http://automapper.codeplex.com/"&gt;AutoMapper&lt;/a&gt; was suggested so I will try to be more specific for some problems &lt;em&gt;ditto&lt;/em&gt; has solved for me. Hopefully this help you decide if it is the right tool for your project.&lt;/p&gt;
&lt;h3&gt;hat tip&lt;/h3&gt;
&lt;p&gt;Before I &amp;#39;compare&amp;#39; AutoMapper, let me clearly state that I am not criticizing anyone&amp;#39;s work. I suspect AutoMapper has been a big helper to many projects and the community surrounding it seems pretty helpful. It just didn&amp;#39;t fit my needs. I tried to use AutoMapper correctly so if I state something in error here please let me know. &lt;/p&gt;
&lt;p&gt;I&amp;#39;d also like to highlight that &lt;em&gt;ditto&lt;/em&gt;&amp;#39;s best friend is &lt;a href="http://fasterflect.codeplex.com"&gt;Fasterflect&lt;/a&gt;. Alot of the reflection magic is handled by this excellent library. &lt;/p&gt;
&lt;h3&gt;&lt;em&gt;ditto&lt;/em&gt; doesn&amp;#39;t&lt;/h3&gt;
&lt;p&gt;First, let me point out a few limitations that &lt;em&gt;currently&lt;/em&gt; exist in &lt;em&gt;ditto&lt;/em&gt; when compared to AutoMapper. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dictionaries are not supported ( I believe they are in AutoMapper ). I don&amp;#39;t really need this, but it would just be an implementation of &lt;code&gt;IBinder&lt;/code&gt; registered on your container.&lt;/li&gt;
&lt;li style="text-decoration:line-through;"&gt;It is slower than AutoMapper. The benchmarking project I have in my project shows about a -2 sec difference in mapping 10,000 messages. To be honest I haven&amp;#39;t spent a ton of time optimizing &lt;em&gt;ditto&lt;/em&gt;. It&amp;#39;s fast enough for me right now though. &lt;/li&gt;
&lt;li&gt;UPDATE : I just pushed a small change that makes my benchmarks 1 second faster than AutoMapper now...My benchmarking tests are simple, so objections are welcome!&lt;/li&gt;
&lt;li&gt;Flattening / Unflattening assumptions. This could probably be easily extended into &lt;em&gt;ditto&lt;/em&gt; but I actually haven&amp;#39;t a need for it since the objects I am focused on are not behavioral.&lt;/li&gt;
&lt;li&gt;Conditional mapping . Actually, this &lt;em&gt;is&lt;/em&gt; supported but not in an explicit method call.&lt;/li&gt;
&lt;li&gt;I am sure there are others. Please comment and I will update this limitations list.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;em&gt;ditto&lt;/em&gt; gots-ta-have&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The primary attraction of AutoMapper for me was the little call to &lt;code&gt;.AssertConfigurationIsValid();&lt;/code&gt;. I knew if I was going to create a similar tool it &lt;em&gt;had&lt;/em&gt; to provide this kind of validation. &lt;/li&gt;
&lt;li&gt;Provide a &lt;code&gt;fluenty&lt;/code&gt; interface but don&amp;#39;t tie my hands with generic parameters when a simple &lt;code&gt;Type&lt;/code&gt; will do. &lt;/li&gt;
&lt;li&gt;No requirement to specify the superfluous generic parameter for the source object when calling &lt;code&gt;.Map()&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;em&gt;ditto&lt;/em&gt; intent&lt;/h3&gt;
&lt;p&gt;My  focus for &lt;em&gt;ditto&lt;/em&gt; is lightweight objects; that is, Data Transfer Objects that are commonly used at application boundaries. That&amp;#39;s not to say things like nested objects or collections are not supported (they are).&lt;/p&gt;
&lt;h3&gt;&lt;em&gt;ditto&lt;/em&gt; does&lt;/h3&gt;
&lt;p&gt;Okay, with that out of the way let&amp;#39;s see what &lt;em&gt;ditto&lt;/em&gt; DOES do. The hassle in any tool that meets this problem will be found in the configuration bits. Like you&amp;#39;d expect, &lt;em&gt;ditto&lt;/em&gt; assumes property names are the same between objects so gives you some help with setting up the mappings based on property name. That&amp;#39;s the easy stuff. &lt;em&gt;ditto&lt;/em&gt; is greedy so just does this automatically. &lt;/p&gt;
&lt;p&gt;The real work comes from &lt;em&gt;exceptions to the rule&lt;/em&gt;. Rather than treating the &lt;em&gt;association&lt;/em&gt; between two objects as the subject for mapping, I decided to simply treat the &lt;em&gt;destination types&lt;/em&gt; as subject and provide a facility for binding together all mappings together to create a validatable, executable whole. This is what I mean on the project when I state  the initial goal of &lt;em&gt;ditto&lt;/em&gt; was to aggregate data from multiple sources. This gives me the coding/typing freedom from having to specify &lt;em&gt;every&lt;/em&gt; property for &lt;em&gt;every&lt;/em&gt; source, but also gives me the freakin&amp;#39; cool ability to confirm that all my destination object properties have &lt;em&gt;some&lt;/em&gt; mapping configured. &lt;/p&gt;
&lt;p&gt;Let&amp;#39;s illustrate a lightweight example for what I mean by that. I have a service that receives messages (events) that each contribute bits to a single view model. Each view model has a Denormalizer class that implements an IDenormalize:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ProjectViewModelDenormalizer : Denormalize&amp;lt;ProjectViewModel&amp;gt;, 
    IDenormalize&amp;lt;ProjectCreatedEvent&amp;gt;,
    IDenormalize&amp;lt;ProjectSamplesAddedEvent&amp;gt;,
    IDenormalize&amp;lt;ProjectMixCodeDefinedEvent&amp;gt;

    /* implementations of these interfaces */
}

public class ProjectViewModel {
    public Guid ProjectId {get;set;}
    public string Name {get;set;}       
    public List&amp;lt;Guid&amp;gt; SampleIds {get;set;}      
    public string MixCode {get;set;}
    /* about 20 more properties, each coming from 10 different events */
}

public class ProjectCreatedEvent {
    public Guid Id {get;set;}
    public string Name {get;set;}
}

public class ProjectSamplesAddedEvent {
    public List&amp;lt;Guid&amp;gt; SampleIds {get;set;} 
}

public class ProjectMixCodeDefinedEvent {
    public string MixCode {get;set;}
}

/* 10 more events contributing to this view model*/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to achieve this in the current drop of AutoMapper and get validation checking I would have to map each property on &lt;code&gt;Project&lt;/code&gt; with an &lt;code&gt;.Ignore()&lt;/code&gt; call to the properties that each event does not cover. This is due to the AutoMapper signature that requires a &lt;code&gt;&amp;lt;TSource,TDestination&amp;gt;&lt;/code&gt; mapping. In order to avoid validation assertion failures, I&amp;#39;d have to zip up this configuration into a custom converter just for the &lt;code&gt;ProjectViewModel&lt;/code&gt; but then I lose validation checking which was the strongest feature in AutoMapper for me. Now, this is still workable, but since I have hundreds of these ViewModels it just became too much &lt;code&gt;.Ignore()&lt;/code&gt; ing for me. Without a Custom Converter, mapping AutoMapper would look something like this for just these :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ProjectViewModelProfile : Profile
{
    protected override void Configure() {
        CreateMap&amp;lt;ProjectCreatedEvent,ProjectViewModel&amp;gt;()
            .ForMember(m =&amp;gt; m.SampleIds, opt =&amp;gt; opt.Ignore() )
            .ForMember(m =&amp;gt; m.ProjectId, opt =&amp;gt; opt.MapFrom(its =&amp;gt; its.Id) )
            .ForMember(m =&amp;gt; m.MixCode, opt =&amp;gt; opt.Ignore() );

        CreateMap&amp;lt;ProjectSamplesAddedEvent, ProjectViewModel&amp;gt;()
            .ForMember(m =&amp;gt; m.Name, opt =&amp;gt; opt.Ignore() )
            .ForMember(m =&amp;gt; m.ProjectId, opt =&amp;gt; opt.Ignore() )
            .ForMember(m =&amp;gt; m.MixCode, opt =&amp;gt; opt.Ignore() );

        CreateMap&amp;lt;ProjectMixCodeDefinedEvent, ProjectViewModel&amp;gt;()
            .ForMember(m =&amp;gt; m.ProjectId, opt =&amp;gt; opt.Ignore() )
            .ForMember(m =&amp;gt; m.Name, opt =&amp;gt; opt.Ignore() )
            .ForMember(m =&amp;gt; m.SampleIds, opt =&amp;gt; opt.Ignore() );

        /* 10 more blocks like these repeating .Ignore() */
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;View Models are always changing out so adding properties or tweaking them slightly suddenly becomes very cumbersome due to the repetition of their definitions for each event type.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ditto&lt;/em&gt; takes a different approach and executes validation on its mappings after &lt;em&gt;everything&lt;/em&gt; has been configured and bound up.  It treats the &amp;#39;Destination&amp;#39; object as the one you are interested in and hollers if the sum of all your sources don&amp;#39;t affect one of its properties in some way. So the above model config would be written like this in &lt;em&gt;ditto&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ProjectViewModelConfig : AbstractMappingConfiguration {
    public override void Configure() [
        //Cfg is injected by your container...see the docs
        Cfg.Map&amp;lt;ProjectViewModel&amp;gt;().From(typeof(ProjectCreatedEvent),typeof(ProjectSamplesAddedEvent),typeof(ProjectMixCodeDefinedEvent),/*more events?*/)
            .Redirecting&amp;lt;ProjectCreatedEvent&amp;gt;(from =&amp;gt; from.Id, to =&amp;gt; to.ProjectId );
    }       
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I typically simplify this with a wee extension method for discovering the source types. &lt;/p&gt;
&lt;h3&gt;Concepts&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;ditto&lt;/em&gt; basically applies three concepts to execute mapping:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IPropertyCriterion : This is the selector for the destination property to match on a object; ie Naming Convention matching&lt;/li&gt;
&lt;li&gt;IResolveValue : This is the behavior of the resolution, given the source and destination (similar to what you see in AutoMapper). &lt;/li&gt;
&lt;li&gt;IConvertValue : This is the convention for certain types; ie, DateTime UTC standards&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Manually configured mappings take precedence of global conventions. So this means if you apply a convention to ignore all properties with names starting with  &amp;quot;System&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Conventions.AddResolver(new PrefixPropertyCriterion(&amp;quot;System&amp;quot;),new IgnoreResolver());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But you find later you have a model you &lt;em&gt;do&lt;/em&gt; want to participate in mapping execution. You can do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cfg.Map&amp;lt;MyViewModel&amp;gt;().From&amp;lt;MyEventWithSystemDetails&amp;gt;().Redirecting&amp;lt;MyEventWithSystemDetails&amp;gt;( from =&amp;gt; from.SystemOS, to =&amp;gt; to.OperatingSystem );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will use your special mapping in this one instance.    &lt;/p&gt;
&lt;p&gt;More info on setting up global conventions is at the project site README.&lt;/p&gt;
&lt;h3&gt;Container&lt;/h3&gt;
&lt;p&gt;Since &lt;em&gt;ditto&lt;/em&gt; relies heavily on IoC container to do its thing, it is dead simple to provide your own resolver implementations,organize your mapping files, or override its behavior it a pretty granular level. This means it&amp;#39;d be easy to provide custom ways for creating destination objects, etc.&lt;/p&gt;
&lt;h3&gt;Execution API&lt;/h3&gt;
&lt;p&gt;There isn&amp;#39;t a need to specify the source object in generic parameters to map your object. Just tell &lt;em&gt;ditto&lt;/em&gt; what destination type to map to and your done. Specifying the source type when I am already passing in the source object was more a pet peeve and made my code noisier than I prefer. Probably this could be relieved with a utility extension method AutoMapper though.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var viewModel = ditto.Map&amp;lt;MyViewModel&amp;gt;(message);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is getting pretty long now. I hope this sheds some light on &lt;em&gt;ditto&lt;/em&gt;&amp;#39;s purpose for being. If you have more questions either on the API or whether it&amp;#39;d be a good fit for you feel free to comment below or email me.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=66862" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/mike_nichols/archive/tags/ditto/default.aspx">ditto</category><category domain="http://devlicio.us/blogs/mike_nichols/archive/tags/mapper/default.aspx">mapper</category><category domain="http://devlicio.us/blogs/mike_nichols/archive/tags/AutoMapper/default.aspx">AutoMapper</category></item></channel></rss>