Register automapper profiles with autofac

21 Nov 2018

AutoMapper is simple library that takes care of Object-to-Object mappings which is otherwise boring & redundant to code every-time. An example scenario would be creating a Data Transfer Objects(DTOs) from a Data Model (Entity).

The map configuration is usually done once per App domain so you would probably add it in the Application startup like global.asax. This would mean that you need to do a reference of all namespaces that contains mapping in your app startup file like below

Mapper.Initialize(cfg => cfg.CreateMap<Com.Davidsekar.Order, Com.Davidsekar.OrderDto>());
//or
var config = new MapperConfiguration(cfg => cfg.CreateMap<Com.Davidsekar.Order, Com.Davidsekar.OrderDto>());

So to overcome this type of concrete references,
AutoMapper offers a way to group all map creation as an AutoMapper Profile within its  respective namespaces, which allows you to keep the map registration within its library.

namespace Com.Davidsekar.Models.Mapping
{
    using AutoMapper;
    using Com.Davidsekar.Models.Data;
    using Com.Davidsekar.Models.Dto;

    public class ContactFormMappingProfile : Profile
    {
        #region Constructors

        public ContactFormMappingProfile()
        {
            CreateMap<ContactForm, ContactFormDto>().ReverseMap();
        }

        #endregion Constructors
    }
}

You can keep the mappings in the AutoMapper profile class within library and then, these individual profiles can be easily scanned and initialized using Autofac using following code

/// <summary>
/// Registers the AutoMapper profile from the external assemblies.
/// </summary>
/// <param name="builder">The builder.</param>
private static void RegisterMaps(ContainerBuilder builder)
{
    var assemblyNames = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
    var assembliesTypes = assemblyNames
        .Where(a => a.Name.Equals("Com.Davidsekar.Models", StringComparison.OrdinalIgnoreCase))
        .SelectMany(an => Assembly.Load(an).GetTypes())
        .Where(p => typeof(Profile).IsAssignableFrom(p) && p.IsPublic && !p.IsAbstract)
        .Distinct();

    var autoMapperProfiles = assembliesTypes
        .Select(p => (Profile)Activator.CreateInstance(p)).ToList();

    builder.Register(ctx => new MapperConfiguration(cfg =>
    {
        foreach (var profile in autoMapperProfiles)
        {
            cfg.AddProfile(profile);
        }
    }));

    builder.Register(ctx => ctx.Resolve<MapperConfiguration>().CreateMapper()).As<IMapper>().InstancePerLifetimeScope();
}

In above code, we are scanning through all referenced assemblies for an assembly with a particular name and  then, try to register all the types with type AutoMapper Profile. You can very well convert that single assembly name to a List<string> of assembly names.

The above sample code give you a gist on how you can dynamically register all mapper configurations. Share your views.

Related Posts