You are on page 1of 13

8/27/2020 Removing the static API from AutoMapper · Los Techies

Archive

Tags
 Find an article Search
About

Removing the static API from AutoMapper


21 January, 2016. It was a Thursday.

As I work towards the 4.2 release of AutoMapper, I got a little inspiration. Over the past
year or so I’ve given some talks/podcasts about a long-lived open source codebase. One
of my biggest regrets was that I made AutoMapper have a static API from literally the
very beginning. The rst tests/prototypes of AutoMapper all started out with
“Mapper.CreateMap” and “Mapper.Map”. I showed my boss, Je rey Palermo, at the time
and asked what he thought, and he said “looks great Jimmy, maybe you shouldn’t make
it static” and I said “PFFFFFFFFFFFT NO WAY”.

Well, I’ve seen the problems with static and I’ve regretted it ever since. With the
upcoming release, I’ve had a chance to prototype what it might look like without static –
it worked great – and I’m ready to mark the entire static API as obsolete.

This is a huge shift in AutoMapper, not so much the API, but forcing everything to be
static. Here’s the before:

1 Mapper.CreateMap<Source, Dest>();
2
3 var source = new Source();
4 var dest = Mapper.Map<Source, Dest>(source);

Before.cs hosted with ❤ by GitHub view raw

Or if you’re doing things the Right Way™ you used Initialize:

1 Mapper.Initialize(cfg => {
2 cfg.CreateMap<Source, Dest>();
3 });
4

https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 1/13
8/27/2020 Removing the static API from AutoMapper · Los Techies

5 var source = new Source();


6 var dest = Mapper.Map<Source, Dest>(source);

BeforeInit.cs hosted with ❤ by GitHub view raw

There are a number of issues with this approach, most of which just result from having
a static API. The static API was just a wrapper around instances, but the main API was all
static.

With 4.2, you’ll be able to, and encouraged, to do this:

1 var config = new MapperConfiguration(cfg => {


2 cfg.CreateMap<Source, Dest>();
3 });
4
5 IMapper mapper = config.CreateMapper();
6 var source = new Source();
7 var dest = mapper.Map<Source, Dest>(source);

After.cs hosted with ❤ by GitHub view raw

The IMapper interface is a lot lighter, and the underlying type is now just concerned
with executing maps, removing a lot of the threading problems I was having before.

I’m keeping the existing functionality and API there, just all obsoleted. The one di cult
piece will be the LINQ extensions, since those as extensions methods are inherently
static. You’d have to do something like this:

1 var config = new MapperConfiguration(cfg => {


2 cfg.CreateMap<User, UserDto>();
3 });
4
5 var builder = config.CreateExpressionBuilder();
6 var users = dbContext.Users.ProjectTo<UserDto>(builder);

LINQ.cs hosted with ❤ by GitHub view raw

It’s not exactly ideal, so I’m playing with doing something like this:

1 var config = new MapperConfiguration(cfg => {


2 cfg.CreateMap<User, UserDto>();
3 });
4 QueryableExtensions.Factories.Configuration = () => config;
5 // The above two can be done once at startup
6
7 var users = dbContext.Users.ProjectTo<UserDto>();

NewLINQ.cs hosted with ❤ by GitHub view raw

https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 2/13
8/27/2020 Removing the static API from AutoMapper · Los Techies

Constrained Open Generics Support Merged in .NET Core DI Container


Diagnostics and Instrumentation Packages Targeting Open Telemetry Beta for MongoDB and
NServiceBus Published
End-to-End Integration Testing with NServiceBus: How It Works
End-to-End Integration Testing with NServiceBus
Becoming a Technical Fellow at Headspring, and New Beginnings
Building End-to-End Diagnostics: User-De ned Context with Correlation Context
Diagnostics and Instrumentation Packages for MongoDB and NServiceBus Published
Picking a Web Microframework
Building End-to-End Diagnostics: Visualization with Exporters
Building End-to-End Diagnostics: Activity and Span Correlation

Authors

Andrew Siemer
Chad Myers
Chris Missal
Chris Patterson
Derek Greer
Derik Whittaker
Eric Anderson
Eric Hexter
Gabriel Schenker
Gregory Long
Hugo Bonacci
James Gregory
Jason Meridth
Jimmy Bogard
John Teague
Josh Arnold
Joshua Flanagan
Joshua Lockwood
Keith Dahlby
Matt Hinze
Patrick Lioi
Rod Paddock
Ryan Rauh
Ryan Svihla
Scott Densmore
Sean Biefeld
Sean Chambers
Sharon Cichelli
Steve Donie
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 12/13
8/27/2020 Removing the static API from AutoMapper · Los Techies

https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 13/13
8/27/2020 Removing the static API from AutoMapper · Los Techies

Expressions can’t depend on any runtime values, and can be more or less explicitly tied
to the con guration.

The pre-release versions of AutoMapper on MyGet now have this API, so it’s not release
yet as 4.2. Before I pushed 4.2 out the door, I wanted to get some feedback.

So do you like this idea? Let me know! I’ve got a GitHub issue to track the progress:
https://github.com/AutoMapper/AutoMapper/issues/1031

← C# 6 Feature Review: Expression-Bodied Function Members AutoMapper 4.2.0 released →

Sponsored

Pitch live to over 100 investors, corporates


SLINGSHOT pow ered by StartupSG

Do You Speak English? Work a USA job from home in Indonesia


Work from Hom e | Search Ads

Mereka Yang Lahir Antara Tahun 1941 dan 1981 Memenuhi Syarat untuk Survei dengan Bayaran
Tinggi
Survey Com pare

Penguat Wifi Baru Mengakhiri Internet Mahal di Indonesia


WiFi Booster

ALSO ON JIMMY BOGARD BLOG

MediatR Extensions for Micro AutoMapper 5.0 Beta release New Yea

MediatR Extensions for Dealing with AutoMapper 5.0 Beta New Ye


Microsoft … Duplication in … released · Los Techies Los Tec

4 years ago • 9 comments 4 years ago • 7 comments 4 years ago • 15 comments 4 years a
To help those building We’ve been using MediatR This week marks a huge One of m
applications using the new (or some manifestation of it) milestone in AutoMapper- year was
Microsoft DI libraries … for a number of years … land, the beta release of … of my dig

50 Comments Jimmy Bogard Blog 🔒 Disqus' Privacy Policy 


1 Login

 Recommend 6 t Tweet f Share Sort by Best

Join the discussion…

LOG IN WITH
OR SIGN UP WITH DISQUS ?

Name
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 3/13
8/27/2020 Removing the static API from AutoMapper · Los Techies
Name

gilligan_MH • 5 years ago


thumbs up
6△ ▽ • Reply • Share ›

Thomas Levesque • 5 years ago


The static API has always struck me as "wrong", so I'm glad you're getting rid of it! Actually, I had
suggested something similar a while back ;)
7△ ▽ 1 • Reply • Share ›

Dan Keller • 5 years ago • edited


I've just been doing enough F# to annoy my friends talking about it, but
some of problems you are having with the code, just don't happen in the
functional programming style.

I think the reason static methods took off as a style was because of Linq
and extension methods that came with it. The only problem was that people (I know I did) wrote
extension methods (a very functional style) as if they were instance methods (very OO style),
and I guess would get caught in some traps that I just don't see in F#, such as threading issues.

Best practices I've tried to follow. Taken from guru's like Scott Wlaschin, Tomas Petricek, Jon
Skeet
F# Best Practice 1) Try to make most things immutable, goal being everything is immutable.

F# Best Practice 2) If it is mutable make it explicit, big warning flags (in F# this would usually be
.NET Properties)

F# Best Practice 3) Treat your functions as input and output, no side effects, do only one thing. In
the end you could almost substitute it with a table of values or dictionary of precalculated/cached
values.

Gist with some thoughts protecting or adding fluent to a function: https://gist.github.com/kel...

String does this, Linq does this. You call .ToUpper or .Where, you get a new thing, you don't
modify the original. At first it was weird, then overtime we came to enjoy the features of this and
but may not have known why.

I think there are other ways around this, like what you're proof of concept is doing, closures or
functions that create functions to create your thing.
3△ ▽ • Reply • Share ›

Mike-E > Dan Keller • 5 years ago


I'm a C#'er for life, but very interested in F#. Love seeing posts like these! Once the
tooling (ReSharper, for starters) catches up there's going to be a disturbance in the .NET
Force. :)
1△ ▽ • Reply • Share ›

Dan Keller > Mike-E • 5 years ago


Fsharpforfunandprofit.com :) Even tips for using it at work
1 R l Sh
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 4/13
8/27/2020 Removing the static API from AutoMapper · Los Techies
1△ ▽ • Reply • Share ›

dasjestyr • 4 years ago • edited


So can I no longer pre-configure all of the mappings? This seems like I have to always run the
config before using the mapper. Or do I just call Initialize() for each mapping?
1△ ▽ • Reply • Share ›

jbogard Mod > dasjestyr • 4 years ago


Eh? Just use Mapper.Initialize.
△ ▽ • Reply • Share ›

dasjestyr > jbogard • 4 years ago


For every mapping? I don't mean to sound obtuse, but usually "Initialize" only gets
run once on something.
1△ ▽ • Reply • Share ›

jbogard Mod > dasjestyr • 4 years ago


Yes, you call Mapper.Initialize once on startup (just like you would your
ORM or DI container). Mapper.CreateMap is dead, I threw it in a dumpster,
poured gasoline and lit it on fire.
△ ▽ • Reply • Share ›

dasjestyr > jbogard • 4 years ago • edited


What I mean is, before, I could have a class that would setup all of the
mapping combinations, basically "teaching" the mapper how to map which
objects to which, and that is what I would run at startup as initialization.
But, the new initialize method only takes a single expression which makes
it seem like I can only register a single mapper which isn't useful. How do I
create (or register) multiple maps at startup?

...or is that just no longer supported?


1△ ▽ • Reply • Share ›

jbogard Mod > dasjestyr • 4 years ago


Maybe open a GitHub issue? You can't really format code in a Disqus
comment, so I'm curious to see what you were doing before. I don't know
what "teaching the mapper how to map objects" means exactly.
△ ▽ • Reply • Share ›

dasjestyr > jbogard • 4 years ago • edited


I didn't want to open an issue until I knew it was an issue.

Basically with the old static interface, one would simply call
Mapper.CreateMap (with optional mapping config) *for each pair of objects
(source/destination)* that you'd want to map, essentially registering the
mapper internally (the "teaching" part to which I referred). Then, you'd just
call Mapper.Map(source) and so long as you created the map beforehand,
you'd be good. But since Mapper.CreateMap() has been removed, I'm not
sure how to register all of the mappers, as the Initialize() method only
seems to take a single expression which is why I'm asking how would
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 5/13
8/27/2020 Removing the static API from AutoMapper · Los Techies
seems to take a single expression -- which is why I m asking how would
one CreateMap for multiple objects.

So for example, in the meanwhile, I've recreated the effect by making a


factory of sorts where during startup, I can register the object pairs with the
mapping configuration to be recalled later when I need it.

Something like this: https://gist.github.com/dra...

I feel like this would probably be in Automapper somewhere and I just


haven't found it.
1△ ▽ • Reply • Share ›

jbogard Mod > dasjestyr • 4 years ago


The Initialize method takes a delegate, so you can use any sort of delegate
in C#, a lambda expression, lambda statement, method group to a static
method, almost anything really.

Sprinkling around Mapper.CreateMap inside runtime code though is pretty


dangerous - you can't use Mapper.AssertConfigurationIsValid! Which, imo,
is crazy if you don't do that somewhere.
△ ▽ • Reply • Share ›

dasjestyr > jbogard • 4 years ago


Right. I don't want to sprinkle that around which is why I'm trying to do it on
startup, but it wasn't obvious (at least to me and a few others here) on how
to register multiple maps. Ok, so the delegate you speak of; are you just
saying call .CreateMap on its argument as many times as I need?
Something like:

Mapper.Initialize(cfg =>
{
cfg.CreateMap<test1a, test1b="">();
cfg.CreateMap<test2a, test2b="">();
});

I think I just came to that realization. Feels a little awkward because it's
referred to as an expression rather than a delegate (I guess I took it literally
and was thinking of it like a MemberExpression for whatever reason); I was
comparing it to the old interface, but i'll buy it. Can I recommend showing
that as an example in the Getting Started doc?
△ ▽ • Reply • Share ›

jbogard Mod > dasjestyr • 4 years ago


Ohhhhhh yeah I see now. Yeah, I was copying another library's names for
those classes when I was building that stuff years ago. Proooooobably not
the best of ideas.
△ ▽ • Reply • Share ›

dasjestyr > jbogard • 4 years ago


I just realized that I'm asking pretty much the same question that Vitaliy M
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 6/13
8/27/2020 Removing the static API from AutoMapper · Los Techies
is asking below, which doesn't seem to be actually answered.
△ ▽ • Reply • Share ›

James Grace • 4 years ago


Lord love a duck, Jimmy. Is there any clear examples of how to set this up for use in an MVC5
project?

I just found out about AutoMapper but cannot figure out in my MVC5 application where to place
configuration code (startup.cs? global.asax?) and how to properly use AutoMapper to map the
results of an EF LINQ query results to a viewmodel which gets send to a view in the Return View
statement... I desperately wanna get out of matching field for field ..

Any chance you can help out a newbie to this? I need to know where in Donald Trump (sorry for
the swearing) I'm supposed to place my code...
1△ ▽ • Reply • Share ›

jbogard Mod > James Grace • 4 years ago


The static API is back, with the exception that CreateMap is gone. If you're using
Mapper.Initialize, you're good to do.
△ ▽ • Reply • Share ›

James Grace > jbogard • 4 years ago


Thanks for the quick reply, Jimmy ... but I'm struggling to figure out where I place
my initializing code in MVC5 project (static or not).

Can you point me to a good code sample that maps a model to a Viewmodel and
how it is initialized at application start and used within a controller? There are
many partial examples that "assume" we know where stuff goes... I'd prefer doing
it the "new" way... so I don't have to change much when going to V5...
△ ▽ • Reply • Share ›

jbogard Mod > James Grace • 4 years ago


My ContosoUniversity project is a good start.
△ ▽ • Reply • Share ›

Bruno Brant • 5 years ago


I always wrapped AutoMapper so that it could be injected, so yeah, you're saving a lot of
redundant code in my projects.
1△ ▽ • Reply • Share ›

Colin M • 3 years ago


So you say you're keeping it available but Obsolete, yet on the current GitHub branch (at the time
of writing this comment), the ObsoleteAttribute no longer exists on the static API. What's the
decision behind reverting this?
△ ▽ • Reply • Share ›

jbogard Mod > Colin M • 3 years ago


This is all old, check out the wiki for static vs. instance. The wiki is always up to date, blog
posts are not.
1△ ▽ • Reply • Share ›
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 7/13
8/27/2020 Removing the static API from AutoMapper · Los Techies
1△ ▽ • Reply • Share ›

Vitaliy M • 4 years ago


Jimmy, could you please clarify new approach.
Before in Web application I called from Global.asax.cs Application_Start() method where all
mappers got initialized.
Somewhat like this:
Mapper.Initialize(map=>
{
map.AddProfile<atobprofile>();
..}
Mapper.CreateMap<source,target>()
..
)

And I used Mapper.Map<target>(source) where i need it.


So mapping happened only once per application start and all mapping was kept in one place.

Now how do I do mapping once per application? Do I need to create map before I do mapping
every time? What is project structure for new approach?
△ ▽ • Reply • Share ›

jbogard Mod > Vitaliy M • 4 years ago


The static API is back. Continue on.
△ ▽ • Reply • Share ›

Vitaliy M > jbogard • 4 years ago


what do you mean it is back? I updated to v.5 from v.4.2.1.0 and project can not be
built any more. Errors about non existing methods..
1△ ▽ • Reply • Share ›

jbogard Mod > Vitaliy M • 4 years ago


Mapper.Initialize and Mapper.Map are back.

Not Mapper.CreateMap, that's dead as the dodo.


△ ▽ • Reply • Share ›

Vitaliy M > jbogard • 4 years ago • edited


looks like documentation for "Custom value resolvers" should be updated..
new interface has different signature with 3 param, not 2 as used to be:
public interface IValueResolver<in tsource,="" in="" tdestination,=""
tdestmember="">
△ ▽ • Reply • Share ›

bibek gautam • 4 years ago


thanks for the update and saving my time :)
△ ▽ • Reply • Share ›

jeffreypalermo • 4 years ago


Good stuff, Jimmy. It's been an incredibly successful project, and using static forces the usage of
https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 8/13
8/27/2020 y Removing the
ystatic API from AutoMapper
j · Los Techiesg g
a global variable at some point. And we all know globals are "bad". :)
△ ▽ • Reply • Share ›

Matt Baker • 5 years ago


I can't seem to get this working with Profiles, do you have an example to show? Thank you!
△ ▽ • Reply • Share ›

Brian Bauer > Matt Baker • 4 years ago


I have the same issue, were you able to resolve it?
△ ▽ • Reply • Share ›

cbates • 5 years ago


Just when I convince myself that using the static mapper is
okay and can be overlooked when my code OCD kicks in, you go and change it…such
is life. Thanks for the great tool btw!
△ ▽ • Reply • Share ›

Gabriel • 5 years ago


Hi thanks for the update! I use AutoMapper in every project. How do you recommend to deal with
null values? I would like for all members to ignore if value is null. This is the example (lets keep it
simple):
Category class with Properties Id and Name
CategoryModel class with Id and Name

If I want to go from CategoryModel to Category and CategoryModel has no value in Property "Id", it
should keep the Id of the original Category.

Category category = new Category() { Id = 2, Name = "a" };


CategoryModel model = new CategoryModel() { Name = "b"};
category = _mapper.Map(model, category );

category should be Id = 2 and Name "b". It ignores the "Id" of model because it came null, so It
should keep the original value.

Thanks!
△ ▽ • Reply • Share ›

Xisvaldo • 5 years ago


Thanks! Greate article! :)
△ ▽ • Reply • Share ›

Sameh Saeed • 5 years ago


thx you save my time :)
△ ▽ • Reply • Share ›

Diechort • 5 years ago


How about something like:
var query = context.Users.Where( ... etc
mapper.ProjectTo<userdto>(query);

https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 9/13
8/27/2020 Removing the static API from AutoMapper · Los Techies

The syntax is a little nastier than the extension methods, but this would allow using different
mapping profiles in different places of the application. (Not sure why you'd need that though)
△ ▽ • Reply • Share ›

jbogard Mod > Diechort • 5 years ago


You can apply different profiles through different mapping configurations still with the
4.2/5.0 API.

But I often chain after the Select too, so that syntax would be awkward.
△ ▽ • Reply • Share ›

Diechort > jbogard • 5 years ago • edited


Maybe there's something i'm missing... Suppose you go with the second approach
you mention in the post:

---
var config = new MapperConfiguration(cfg => {

cfg.CreateMap<user, userdto="">();

});

QueryableExtensions.Factories.Configuration = () => config;

// The above two can be done once at startup

var users = dbContext.Users.ProjectTo<userdto>();


---
And supose you have a multi tenant application, that for some reason needs
different mapping profiles for different tenants.

Since the configuration is done at startup, how would you tell the extension
method which mapping profile or configuration it would need to use?

PS: I've started using automapper a few moths ago, and i fell in love with it
immediately, so thanks for building this awesome framework :)

EDIT: Now that i think about it, i guess using the first approach, one could register
expression builders for each tenant, and inject the expression builder on your
service/query/command/whatever
△ ▽ • Reply • Share ›

Mike-E • 5 years ago • edited


Yeah... with xUnit I too have learned the ways (or rather "unways") of static resources. Thank you
for posting this! Glad this showed up in the search engines while trying to deal with my new
obsolete warnings. :)

Speaking of which, a random thought I had just now, but maybe a new best practice for all
obsolete/deprecated messages should include a URL if possible? That would be pretty
rad/convenient.
△ ▽ • Reply • Share ›

https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 10/13
8/27/2020 Removing the static API from AutoMapper · Los Techies

Pawel Kowalski • 5 years ago


Thanks for fixing this static nightmare. No more need to write dump wrapping AM? Szczesc Boze
panu za to dobre oprogramowanie!
△ ▽ • Reply • Share ›

Owen Morgan-Jones • 5 years ago


I think this is great. It would have helped me out on a previous project where I called
Mapper.Initialize() in my code and overwrote the config being used under the covers in a
dependency, causing it to fail.

It looks like this approach would eliminate that completely, and let me scope configs/IMappers
only as much as I needed to, without worrying what my dependencies may or may not be doing.
△ ▽ • Reply • Share ›

arbenowskee • 5 years ago


Love it! DI 4 teh win =)
△ ▽ • Reply • Share ›

Ricardo Peres • 5 years ago


I had long thought about this, but now I'm not so sure. For once, you have to make maps
available everywhere you want to do the transformations... Thoughts, guys?
△ ▽ • Reply • Share ›

Thomas Levesque > Ricardo Peres • 5 years ago


You can easily inject the IMapper anywhere you need it
1△ ▽ • Reply • Share ›

Betty > Ricardo Peres • 5 years ago


it would also allow you to do mappings different ways in different parts of the code even if

Recent Author Posts

Constrained Open Generics Support Merged in .NET Core DI Container


Diagnostics and Instrumentation Packages Targeting Open Telemetry Beta for MongoDB and
NServiceBus Published
End-to-End Integration Testing with NServiceBus: How It Works
End-to-End Integration Testing with NServiceBus
Becoming a Technical Fellow at Headspring, and New Beginnings
Building End-to-End Diagnostics: User-De ned Context with Correlation Context
Diagnostics and Instrumentation Packages for MongoDB and NServiceBus Published
Building End-to-End Diagnostics: Visualization with Exporters
Building End-to-End Diagnostics: Activity and Span Correlation
Building End-to-End Diagnostics: OpenTelemetry Integration

Recent Site Posts


https://lostechies.com/jimmybogard/2016/01/21/removing-the-static-api-from-automapper/ 11/13

You might also like