bevacqua
bevacqua

Reputation: 48496

AutoMapper how to avoid initialization

How do I avoid requiring code like this:

public static class BusinessLogicAutomapper
{
    public static bool _configured;

    public static void Configure()
    {
        if (_configured)
            return;

        Mapper.CreateMap<Post, PostModel>();
        _configured = true;
    }
}

in my BL assembly, and having to call Configure() from my Global.asax in my MVC application?

I mean, I expect a call like this:

    public PostModel GetPostById(long id)
    {
        EntityDataModelContext context = DataContext.GetDataContext();
        Post post = context.Posts.FirstOrDefault(p => p.PostId == id);

        PostModel mapped = Mapper.Map<Post, PostModel>(post);
        return mapped;
    }

to Mapper.Map<TIn,TOut> to produce the mapper if it isn't in existance, instead of having to create it myself manually (I shouldn't even know about this inner working). How can I work around declaratively creating mappers for AutoMapper?

A solution that's natural to AutoMapper would be desired, but an extension or some architectural change in order to avoid this initialization would work too.

I'm using MVC 3, .NET 4, and no IoC/DI (yet, at least)

Upvotes: 4

Views: 2653

Answers (2)

Chris McKelt
Chris McKelt

Reputation: 1388

check out Automapper profiles.

I have this setup in my Global.asax - it runs once statically so everything is setup at runtime ready to go.

I also have 1 unit test which covers all maps to check they are correct.

A good example of this is Ayendes Raccoon Blog

https://github.com/ayende/RaccoonBlog

Upvotes: 1

tvanfosson
tvanfosson

Reputation: 532505

I completely misunderstood what you were trying to do in my original answer. You can accomplish what you want by implementing part of the functionality of AutoMapper using reflection. It will be of very limited utility and the more you extend it, the more like AutoMapper it will be so I'm not sure that there's any long term value to it.

I do use a small utility like what you are wanting to automate my auditing framework to copy data from a entity model to its associated audit model. I created it before I started using AutoMapper and haven't replaced it. I call it a ReflectionHelper, the below code is a modification of that (from memory) -- it only handles simple properties but can be adapted to support nested models and collections if need be. It's convention-based, assuming that properties with the same name correspond and have the same type. Properties that don't exist on the type being copied to are simply ignored.

public static class ReflectionHelper
{
      public static T CreateFrom<T,U>( U from )
          where T : class, new
          where U : class
      {
            var to = Activator.CreateInstance<T>();
            var toType = typeof(T);
            var fromType = typeof(U);

            foreach (var toProperty in toType.GetProperties())
            {
                var fromProperty = fromType.GetProperty( toProperty.Name );
                if (fromProperty != null)
                {
                   toProperty.SetValue( to, fromProperty.GetValue( from, null), null );
                }
            }

            return to;
      }

Used as

    var model = ReflectionHelper.CreateFrom<ViewModel,Model>( entity );

    var entity = ReflectionHelper.CreateFrom<Model,ViewModel>( model );

Original

I do my mapping in a static constructor. The mapper is initialized the first time the class is referenced without having to call any methods. I don't make the logic class static, however, to enhance its testability and the testability of classes using it as a dependency.

public class BusinessLogicAutomapper
{
    static BusinessLogicAutomapper
    {
        Mapper.CreateMap<Post, PostModel>();
        Mapper.AssertConfigurationIsValid();
    }
}

Upvotes: 2

Related Questions