Looking for the best modern equivalent of some old static code

42 views
Skip to first unread message

m...@dynamit.com

unread,
Aug 10, 2016, 8:38:23 AM8/10/16
to AutoMapper-users
I have a pattern which has served me well on several past projects. I use concrete mapper classes that use AutoMapper internally as an implementation detail. This lets me get back a few things I enjoy, such as being able to easily find usages of a particular mapping. For instance, a FooMapper class will create Foo objects from a variety of different sources.

public class FooMapper : EntityMapper<Foo>, IFooMapper
{
    static FooMapper()
    {
        AutoMapper.Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Bar, Foo>();
            cfg.CreateMap<Baz, Foo>();
        });
    }

    public Foo Map(Bar source)
    {
        return AutoMapper.Mapper.Map(source, new Foo());
    }

    public Foo Map(Baz source)
    {
        return AutoMapper.Mapper.Map(source, new Foo());
    }
}

In the real world, there's usually more to it than that, with the base EntityMapper knowing how to handle the simple Foo to Foo mapping for unproxying things, and with each individual Map method doing any custom code-based work as appropriate. In some cases, certain mappings don't even use AutoMapper. One of the big wins, though, is that I can find usages of the individual mappings quite easily, and the rest of the code doesn't even need to know that AutoMapper is involved. I don't necessarily like my choice of tools leaking into the rest of my code base. I also favor thin repository layers to abstract which ORM I'm using, by the way.

I want to move to AutoMapper 5, and modernize the pattern, but I need to retain the ability to update the mappings from the static constructors of the concrete mapper classes. What I'd really like to do is hold the configuration in the base class as a static so that all of MY mappings end up together in that one configuration together, and can leverage each other, but wouldn't see mappers defined in other "trees", with EntityMappers not knowing about ViewModelMappers, etc.

My current problem is that AM5 really wants a separate configuration step before you start actually using the mappers. My old method relied on the mappers lazily adding themselves to the mix the first time they are used in any given run. If a particular mapper is never used in a run, then it will never have configured itself to begin with. I could add methods to each mapper that take in the configuration expression and configure themselves, but I would lose this passive configuration, and have to maintain a master list of mappings by hand, updating it whenever I add a new type of mapping to the project.

Is there any compromise in AM5, or should I just keep using the resurrected static API? Am I losing out on AM5's new performance gains if I stick with the static API?

Jimmy Bogard

unread,
Aug 10, 2016, 12:38:22 PM8/10/16
to automapper-users
Since the beginning of AutoMapper, the idea was to initialize AutoMapper once, and never touch configuration again. That's why Mapper.Initialize exists, to initialize once, at the startup of your application (just like you do with your ORM).

The closest thing you'll get is to use a Profile class (doesn't need to be static). Then, in application startup, you can scan all types in your assemblies for concrete Profile classes, calling AddProfile in your Initialize method. That's how we do it.

I don't know what you're talking about mappers knowing about each other. We have apps with hundreds of map configurations using the above Initialize method without a problem. AutoMapper passively compiles the mapping configuration on first Map call, so that there's not a huge perf hit in Initialize. Also, new in AutoMapper 5, is the IMapper interface that makes it super easy to unit test. Although again, I don't recommend it strictly for unit testing or abstraction, it's pretty much zero value for that. I only use an IMapper instance injected in when there are things like resolvers that use ISession/DbContext things

If you don't want to go the static initialization route, I'd go instead for instance-based based mappers. I wouldn't recommend it though - your app performs way worse if you don't cache those mappings once per AppDomain. Initialize also uses locks internally, so only 1 thread can call Initialize at the same time. Again, generally a bad idea.

Hope this helps!

--
You received this message because you are subscribed to the Google Groups "AutoMapper-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to automapper-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Mel Grubb

unread,
Aug 10, 2016, 1:10:18 PM8/10/16
to automapp...@googlegroups.com
When I'm talking about mappers knowing about each other, it isn't a performance thing. Much like I would separate my data layer from my service layer from my UI layer into different projects, I might like to split up my mappers rather than having them all together in one configuration. In my assemblies, if one of my MVC controllers finds itself touching raw EF entities, I know I've done something wrong. It shouldn't even be able to SEE those. That's what I want to accomplish by splitting up my mappers. If my view model mappers have no business knowing about some DTO mapper from elsewhere in the solution, I don't want them to know about them. I'd rather have an error letting me know I got my wires crossed somewhere, and preferably sooner rather than later.

I don't see myself using IMapper, at least in its raw form. I prefer individual IFooMapper, IBarMapper, etc interfaces, and inject only the concrete mappers I'm expecting to use in a given class. Also, when I'm unit testing, I usually don't want my mappers mocked. I go out of my way to make sure that the mappers are real since they're usually an integral part of what I'm testing. I'll mock out the database, sure, or feed the mappers some fake data, but I want to exercise my mappers just like the rest of my code. If I had a particularly complicated mapper with some kind of expensive post-processing, then I suppose I would mock that one out, but that's more of an exception than a rule.

I'll see what I can do with Profile classes. At first glance, it seems like I'd just end up with more classes. My concrete mapper, and a matching profile class that defines the actual mappings. I'd get the best of both worlds that way, a usable "Find Usages", and up-to-date AM5 usage. I'll give it a shot on the next new project.

--
You received this message because you are subscribed to a topic in the Google Groups "AutoMapper-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/automapper-users/ZyhpteSKp8g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to automapper-users+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Mel Grubb | Developer | Dynamit | c: 614.432.0037 | o: 614.538.0095
274 Marconi Boulevard | Suite 300 | Columbus, OH 43215

Jimmy Bogard

unread,
Aug 10, 2016, 1:40:47 PM8/10/16
to automapper-users
What do you mean "know about"? I don't understand what that means in the context of AutoMapper.

I don't create a ton of profiles, I usually create one per feature folder:


Feature folder being "all the things related to one feature", models, handlers, views, javascript, everything. If it changes together, it lives together. One profile per feature folder seems to be a nice organization. One per mapping config is too much, and one per kind of mapping (editing stuff, viewing stuff) is the wrong organization. I tried for example once "ViewModelProfile" and "FormModelProfile" and "ReportModelProfile", but organizing based on type versus affinity was, it turns out, a pretty lousy idea (also why I got rid of projects organized by kind of thing).

One last thing - static initialization makes it the easiest to do ProjectTo, one of the coolest features in AutoMapper to date. Otherwise when you call ProjectTo, you have to pass in configuration every time. Annoying.

Mel Grubb

unread,
Aug 10, 2016, 1:56:43 PM8/10/16
to automapp...@googlegroups.com
Now that I'm trying to type it out, I realize I can't really come up with a concrete example that wouldn't result in other errors anyway. The idea was that since AutoMapper will translate properties of a parent object as well as long as it's something else that it already knows how to map, I wanted to isolate different "Trees" of mapper configurations so that unexpected items that shouldn't be there, but which AutoMapper knows how to translate, would result in a mapping configuration error. I can enforce that separation through separation into different assemblies, though. It seemed to make sense when I was originally thinking about it, though.

The seed of the idea was a desire to keep "my" mappings separate from others, or from those defined in a shared library. A single static AutoMapper configuration would jumble them all together. Namespaces should mitigate any collisions, but separating "my" configuration from others seemed like a good idea. In a very very large solution, I could see maybe starting to notice performance issues that could be mitigated by only talking to the configuration that's concerned with the things you're trying to translate. For example, if I know I'm trying to translate a ViewModel, I would address that to a Mapper instance that doesn't know anything about mapping Entities to DTOs, or mapping public API requests to internal service requests. It would have to be a pretty large solution for this to be a concern, though.
Reply all
Reply to author
Forward
0 new messages