Inject AutoMapper
Asked Answered
A

3

8

I have been working on injecting AutoMapper into controllers. I like the implementation of Code Camp Server. It creates a wrapper around AutoMapper's IMappingEngine. The dependency injection is done using StructureMap. But I need to use Castle Windsor for my project. So, how do we implement the following dependency injection and set-up using Windsor? I am not looking for line-by-line equivalent implementation in Castle Windsor. If you want to do that, please feel free. Instead, what is Windsor equivalent of StructureMap's Registry and Profile? I need Profile to define CreateMap<> like the following.

Thanks.

Meeting controller:

public MeetingController(IMeetingMapper meetingMapper, ...)

Meeting Mapper:

public class MeetingMapper : IMeetingMapper
{

    private readonly IMappingEngine _mappingEngine;

    public MeetingMapper(IMappingEngine mappingEngine)
    {
      _mappingEngine = mappingEngine;
    }

    public MeetingInput Map(Meeting model)
    {
        return _mappingEngine.Map<Meeting, MeetingInput>(model);    
    }

    ......
}

Auto Mapper Registry:

public class AutoMapperRegistry : Registry
{

    public AutoMapperRegistry()
    {
        ForRequestedType<IMappingEngine>().TheDefault.Is.ConstructedBy(() => Mapper.Engine);
    }
}

Meeting Mapper Profile:

public class MeetingMapperProfile : Profile
{

    public static Func<Type, object> CreateDependencyCallback = (type) => Activator.CreateInstance(type);

    public T CreateDependency<T>()
    {
        return (T)CreateDependencyCallback(typeof(T));
    }

    protected override void Configure()
    {
        Mapper.CreateMap<MeetingInput, Meeting>().ConstructUsing(
            input => CreateDependency<IMeetingRepository>().GetById(input.Id) ?? new Meeting())

       .ForMember(x => x.UserGroup, o => o.MapFrom(x => x.UserGroupId))
       .ForMember(x => x.Address, o => o.Ignore())
       .ForMember(x => x.City, o => o.Ignore())
       .ForMember(x => x.Region, o => o.Ignore())
       .ForMember(x => x.PostalCode, o => o.Ignore())
       .ForMember(x => x.ChangeAuditInfo, o => o.Ignore());
    }
}
Apothecary answered 12/11, 2009 at 3:37 Comment(0)
D
3

you mean how do you register it in Windsor?

you may have to register FactorySupportFacility fist... I have no way of checking at this moment.

container.AddFacility<FactorySupportFacility>();

and then

container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(()=>
            Mapper.Engine));
Deanndeanna answered 12/11, 2009 at 8:38 Comment(3)
What about the Profile part in StructureMap? Mapper.CreateMap<x, y>.ForMember() is called from MeetingMapperProfile class. How to do that in Castle Windsor? Thanks.Apothecary
what is this Profile? What does it do? If you mean just the Configure method, than you do it, where you register your components to the container, It has no dependency on the container whatsoever AFAICSDeanndeanna
Profile in StructureMap is the ability to switch out different concrete implementations of a service (i.e. class) at runtime depending on the context in which they are used. But if you look at the Meeting profile, it is not actually doing that. The Mapper.CreateMap<>.ForMember(...) in the Meeting Profile has to be called before the MeetingMapper calls _mappingEngine.Map(). I am thinking about creating a Facility in Windsor to do what the Meeting Profile is doing right now. What do you think? Thanks.Apothecary
H
2

I'm not familiar with Castle Windsor but here is the StructureMap syntax. You would need to set up your registry a little different. Instead of setting the IMappingEngine to Mapper.Engine, you will have to do configure a few more interfaces. It's a little more work but this will allow you to set the profile as part of registration.

public AutoMapperRegistry()
{
    //type mapping
    For<ConfigurationStore>()
        .Singleton()
        .Use(ctx =>
        {
            ITypeMapFactory factory = ctx.GetInstance<ITypeMapFactory>();
            ConfigurationStore store 
                = new ConfigurationStore(factory, MapperRegistry.AllMappers());
            IConfiguration cfg = store;
            //Here's where you load your profile
            cfg.AddProfile<MeetingMapperProfile>();
            store.AssertConfigurationIsValid();
            return store;
        });
    For<IConfigurationProvider>().Use(ctx => ctx.GetInstance<ConfigurationStore>());
    For<IConfiguration>().Use(ctx => ctx.GetInstance<ConfigurationStore>());
    For<IMappingEngine>().Use<MappingEngine>();
    For<ITypeMapFactory>().Use<TypeMapFactory>();
}
Hosbein answered 26/9, 2012 at 14:57 Comment(0)
T
2

I realize this is a bit old, but I use Castle Windsor, and it's been fairly easy to get AutoMapper profiles loaded using an installer:

using System.Linq;
using System.Reflection;

using AutoMapper;

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;

namespace YourNamespace
{
    public class AutoMapperInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            Mapper.Initialize(m => m.ConstructServicesUsing(container.Resolve));

            container.Register(Types.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IValueResolver>());
            container.Register(Types.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
            var profiles = container.ResolveAll<Profile>();
            profiles.ToList().ForEach(p => Mapper.AddProfile(p));

            container.Register(Component.For<IMappingEngine>().Instance(Mapper.Engine));
        }
    }
}

This installer would pick up the MeetingMapperProfile shown in the question, or any other class based on AutoMapper's Profile.

Triste answered 13/12, 2013 at 18:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.