AutoMapper 5.0 Beta released

This week marks a huge milestone in AutoMapper-land, the beta release of the 5.0 work we’ve been doing over the last many, many months.

In the previous release, 4.2.1, I obsoleted much of the dynamic configuration API in favor of an explicit configuration step. That means you only get to use “Mapper.Initialize” or “new MapperConfiguration”. You can still use a static Mapper.Map call, or create a new Mapper object “new Mapper(configuration)”. The last 4.x release really paved the way to have a static and instance API that were lockstep with each other.

In previous versions of AutoMapper, you could call “Mapper.CreateMap” anywhere in your code. This made two things difficult: performance optimization and dependent configuration. You could get all sorts of weird bugs if you called the configuration in the “wrong” order.

But that’s gone. In AutoMapper 5.0, the configuration is broken into two steps:

  1. Gather configuration
  2. Apply configuration in the correct order

By applying the configuration in the correct order, we can ensure that there’s no order dependency in your configuration, we handle all of that for you. It seems silly in hindsight, but at this point the API inside of AutoMapper is strictly segregated between “DSL API”, “Configuration” and “Execution”. By separating all of these into individual steps, we were able to do something rather interesting.

With AutoMapper 5.0, we are able to build execution plans based on type map configuration to explicitly map based on exactly your configuration. In previous versions, we would have to re-assess decisions every single time we mapped, resulting in huge performance hits. Things like “do you have a condition configured” and so on.

A strict separation meant we could overhaul the entire execution engine, so that each map is a precisely built expression tree only containing the mapping logic you’ve configured. The end result is a 10X performance boost in speed, but without sacrificing all of the runtime exception logic that makes AutoMapper so useful.

One problem with raw expression trees is that if there’s an exception, you’re left with no stack trace. When we built up our execution plan in an expression tree, we made sure to keep those good parts of capturing context when there’s a problem so that you know exactly which property in exactly which point in the mapping had a problem.

Along with the performance issues, we tightened up quite a bit of the API, making configuration consistent throughout. Additionally, a couple of added benefits moving to expressions:

  • ITypeConverter and IValueResolver are both generic, making it very straightforward to build custom resolvers
  • Supporting open generic type converters with one or two parameters

Overall, it’s been a release full of things I’ve wanted to tackle for years but never quite got the design right. Special thanks to TylerCarlson1 and lbargaoanu, both of whom passed the 100 commit mark to AutoMapper.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in AutoMapper. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Sweeeeet!!!! So are you removing obsolete static methods? What is the reason for major version increase?

    • jbogard

      I removed the obsolete static API methods. And there were other minor API changes, but that was the big one.

  • Ivan

    Will there be a documentation with examples on how to use the new API?

    • jbogard

      I’ve updated all of the wiki to reflect the new API. There’s not too many changes, though.

  • Sergio Rykov

    Hi! I’ve tried 5.0 beta. It’s really improved performance here! It increased in my tests only 5X, but it’s impressive too! I used BenchmarkDotNet.

    Have you considered using core from such mappers like TinyMapper, ExpressMapper? They are performant, but has not so many features and flexibility as AutoMapper has. Their performance is near “handwritten” mappings.

    • jbogard

      Thanks! And “only” 5X lol.

      Still working on perf, but it would be tough to use the core of their mappers, they still don’t have nearly the number of features or support for exotic scenarios that AutoMapper does.

      • Sergio Rykov

        You can run tests yourself :)
        https://github.com/sergiorykov/dotnet-objmap-benchmark

        I admit I can do it wrong way.

        Type=NestedBenchmark Mode=Throughput Platform=X64
        Framework=V461 LaunchCount=1 WarmupCount=1 TargetCount=5

        Method Median StdDev Scaled
        4.2.1
        AutoMapper 44,274.9274 ns 474.6270 ns 1,448.96
        ExpressMapper 1,451.7358 ns 11.4851 ns 47.51
        TinyMapper 584.2919 ns 3.3097 ns 19.12
        Handwritten 30.5564 ns 0.3962 ns 1.00

        5.0-beta1
        AutoMapper 8,907.5355 ns 324.5264 ns 303.47
        ExpressMapper 1,405.5467 ns 13.5414 ns 47.89
        TinyMapper 581.8164 ns 3.6540 ns 19.82
        Handwritten 29.3521 ns 0.5676 ns 1.00

        I’ve not dived into AutoMapper internals yet (though actually we use it in most of our products, what a shame on me :( ).

        TinyMapper generates IL code the same way as compiler will do for your handwritten mapping (simplest cases but it can be extended, and I think it worth it. Incredible performance when you need plain mappings).

        ExpressMapper wich compiles ExpressionTree’s propose perf (on their XXL test) only ~1.5X worse then handwritten (I’ve ported it too and got ~50X worse then handwritten – can’t figure out why), but ExpressMapper still much faster 3X-10X then 5.0b1.

        • jbogard

          Not too bad actually! One last tradeoff I’m not too willing to make is AutoMapper captures context as it goes, so that you can debug when something goes wrong. I think I can capture it a different way, but still want it because you get zero hints on a single expression. It’s completely opaque.

          • Sergio Rykov

            Wow, profiler for AutoMapper – sounds cool!

        • Sergio Rykov

          Same test. But for 5.0.2

          5.0.2 vs 5.0-beta1 3X improvement!
          5.0.2 vs 4.2.1 15X improvement!

          Amazing!

          AutoMapper | 3,628.2839 ns | 9.5984 ns | 127.00 |
          ExpressMapper | 1,483.5823 ns | 4.7204 ns | 51.93 |
          Handwritten | 28.5701 ns | 0.2710 ns | 1.00 |
          TinyMapper | 623.1476 ns | 19.2186 ns | 21.81 |

  • Cole

    I’ve probably spent 15 hours trying to convert the old static methods. At this point I’m just going to undo changes and go back to the static version. Not seeing a path to migrate without other structural changes to my code.

    • jbogard

      Mapper.Initialize and Mapper.Map are perfectly fine and supported. There’s no reason to migrate (unless you are using Mapper.CreateMap, which is never coming back).

      • Cole

        That is exactly what is being used all over the place in code that I inherited that was written in 2011. Even 2.* to 4 had some runtime issues for me.

        • jbogard

          Ah, so not a simple migration, it’ll probably take you a couple of hours then to move all those CreateMap calls into Profiles. At least that’s how long it took me to migrate the AutoMapper tests, and there were over 1K maps.

  • Yuriy Anisimov

    Great Job @jbogard:disqus ! Finally AutoMapper becomes great again! :)