AutoMapper和Windsor

时间:2014-06-24 09:49:16

标签: castle-windsor automapper

我在 ITypeConverter 中使用 AutoMapper ,我想保留 Castle Windsor 中的所有内容。 在一个程序集中,我有 ITypeCoverter ,我使用这种方法加载它们:

container
.Register(Types.FromAssembly(Assembly.GetExecutingAssembly())
.BasedOn(typeof(ITypeConverter<,>)));

到目前为止,我可以看到Windsor正在正确加载我的所有转换器。

然后我在Windsor中注册AutoMapper

Mapper.Initialize(m => m.ConstructServicesUsing(container.Resolve));
container.Register(Component.For<IMappingEngine>().Instance(Mapper.Engine));

但是当我问一个IMappingEngine的实例时,没有加载约定。我在这里想念一下吗?

3 个答案:

答案 0 :(得分:3)

我让AutoMapper和Windsor与Profiles和TypeConverters很好地配合使用。我认为这对你来说应该是不可知的,因为AutoMapper会自动获取ITypeConverter的任何实现。

如果它能解决您的问题,请告诉我。

首先我向温莎注册了AutoMapper:

public class AutoMapperInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        // Replace by whatever assembly contains your ITypeConverter, IValueResolver and Profile implementations
        var myAssembly = Classes.FromAssemblyNamed("MyAssembly");

        // Register AutoMapper such that it uses a singleton configuration
        container.Register(
            myAssembly.BasedOn(typeof(ITypeConverter<,>)).WithServiceSelf(),
            myAssembly.BasedOn<IValueResolver>().WithServiceBase(),
            myAssembly.BasedOn<Profile>().WithServiceBase(),
            Component.For<IEnumerable<IObjectMapper>>().UsingFactoryMethod(() => MapperRegistry.Mappers),
            Component.For<ConfigurationStore>()
                .LifestyleSingleton()
                .UsingFactoryMethod(x =>
                {
                    var typeMapFactory = x.Resolve<ITypeMapFactory>();
                    var mappers = x.Resolve<IEnumerable<IObjectMapper>>();
                    ConfigurationStore configurationStore = new ConfigurationStore(typeMapFactory, mappers);
                    configurationStore.ConstructServicesUsing(x.Resolve);
                    configurationStore.AssertConfigurationIsValid();
                    return configurationStore;
                }),
            Component.For<IConfigurationProvider>().UsingFactoryMethod(x => x.Resolve<ConfigurationStore>()),
            Component.For<IConfiguration>().UsingFactoryMethod(x => x.Resolve<ConfigurationStore>()),
            Component.For<IMappingEngine>().ImplementedBy<MappingEngine>().LifestyleSingleton(),
            Component.For<ITypeMapFactory>().ImplementedBy<TypeMapFactory>()
        );

        // Add all Profiles
        var configuration = container.Resolve<IConfiguration>();
        container.ResolveAll<Profile>().ToList().ForEach(configuration.AddProfile);
    }
}

然后我创建了一个配置文件,我在其中使用一些反射注册了所有的ITypeConverter实现:

public class TypeConverterProfile : Profile
{
    private readonly IConfiguration _configuration;

    public TypeConverterProfile(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    protected override void Configure()
    {
        // Replace by whatever assembly contains your ITypeConverter implementations
        var myAssembly = Classes.FromAssemblyNamed("MyAssembly");
        var typeConverters =
            from x in myAssembly.GetTypes()
            from type in x.GetInterfaces()
            where type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ITypeConverter<,>)
            select new
            {
                Type = x,
                Source = type.GetGenericArguments()[0],
                Destination = type.GetGenericArguments()[1]
            };

        // Apply type converters to AutoMapper configuration
        foreach (var typeConverter in typeConverters)
            _configuration.CreateMap(typeConverter.Source, typeConverter.Destination).ConvertUsing(typeConverter.Type);
    }
}

AutoMapper现在将自动选择并使用&#34; MyAssembly&#34;中的任何Profiles和ITypeConverters实现。

例如,您可能有个人资料:

public class MapProfile : Profile
{
    private readonly IConfiguration _configuration;

    public MapProfile(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    protected override void Configure()
    {
        // Create an auto-map from SearchResultModel -> SearchResult
        _configuration.CreateMap<SearchResultModel, SearchResult>();
    }
}

和一个ITypeConverter:

public class SearchRequestConverter : ITypeConverter<SearchRequest, SearchRequestModel>
{
    private readonly IConfiguration _configuration;

    public MapProfile(IConfiguration configuration)
    {
        // Also in the ITypeConverter you may have the IConfiguration injected in case you need it
        _configuration = configuration;
    }

    public SearchRequestModel Convert(ResolutionContext context)
    {
        var model = (SearchRequest) context.SourceValue;
        return new SearchRequestModel
        {
            Results = model.Results
        };
    }
}

最后,通过依赖IMappingEngine来执行类中的实际映射:

public class FolderRepository
{
    private readonly IMappingEngine _mappingEngine;

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

    public SearchResult Search(SearchRequest searchRequest)
    {
        // This mapping will use the ITypeConverter implementation
        SearchRequestModel searchRequestModel = _mappingEngine.Map<SearchRequestModel>(searchRequest);
        SearchResultModel searchResultModel = Search(searchRequestModel);

        // This mapping will use the auto-map from the Profile
        SearchResult searchResult = _mappingEngine.Map<SearchResultModel>(searchResultModel);
        return searchResult;
    }

    private SearchResultModel Search(SearchRequestModel searchRequestModel)
    {
        SearchResultModel result = new SearchResultModel();
        // ... perform search ...
        return result;
    }
}

要拥有更多的ITypeConverters,您只需要实现它们,它们将自动被Windsor和AutoMapper选中。可以在配置文件中添加手动自动映射(CreateMap&lt;&gt;)。

这能解决您的问题吗?

答案 1 :(得分:1)

我看不到创建/设置映射的代码。既不Mapper.CreateMap<Source, Destination>();也不configuration.CreateMap<Source, Destination>();

不幸的是,关于一起使用IoC和AutoMapper的信息还不够。您只能找到一个an example of usage AutoMapper and Structure Map in the official samples

还有my example of usage AutoMapper and Castle Windsor。它与前一个类似,但使用Castle Windsor而不是Structure Map。

/// <summary>
/// Castle Windsor example.
/// </summary>
/// <remarks>
/// StructureMap example
/// see  https://github.com/AutoMapper/AutoMapper/blob/develop/src/AutoMapperSamples/CastleWindsorIntegration.cs
/// </remarks>
public class CastleWindsorIntegration
{
    private readonly IWindsorContainer container;

    public CastleWindsorIntegration()
    {
        container = new WindsorContainer();
    }

    [Fact]
    public void Example()
    {
        container.Install(new ConfigurationInstaller());

        var configuration1 = container.Resolve<IConfiguration>();
        var configuration2 = container.Resolve<IConfiguration>();
        configuration1.Should().BeSameAs(configuration2);

        var configurationProvider = container.Resolve<IConfigurationProvider>();
        configurationProvider.Should().BeSameAs(configuration1);

        var configuration = container.Resolve<ConfigurationStore>();
        configuration.Should().BeSameAs(configuration1);

        configuration1.CreateMap<Source, Destination>();

        var engine = container.Resolve<IMappingEngine>();

        var destination = engine.Map<Source, Destination>(new Source { Value = 15 });

        destination.Value.Should().Be(15);
    }

    [Fact]
    public void Example2()
    {
        container.Install(new MappingEngineInstaller());

        Mapper.Reset();

        Mapper.CreateMap<Source, Destination>();

        var engine = container.Resolve<IMappingEngine>();

        var destination = engine.Map<Source, Destination>(new Source { Value = 15 });

        destination.Value.Should().Be(15);
    }

    public class Source
    {
        public int Value { get; set; }
    }

    public class Destination
    {
        public int Value { get; set; }
    }

    public class ConfigurationInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<IEnumerable<IObjectMapper>>()
                    .LifestyleSingleton()
                    .UsingFactoryMethod(() => MapperRegistry.Mappers),
                Component.For<ConfigurationStore>().ImplementedBy<ConfigurationStore>(),
                Component.For<IConfigurationProvider>().UsingFactoryMethod(k => k.Resolve<ConfigurationStore>()),
                Component.For<IConfiguration>().UsingFactoryMethod(k => k.Resolve<ConfigurationStore>()),
                Component.For<IMappingEngine>().ImplementedBy<MappingEngine>(),
                Component.For<ITypeMapFactory>().ImplementedBy<TypeMapFactory>());
        }
    }

    public class MappingEngineInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<IMappingEngine>().UsingFactoryMethod(() => Mapper.Engine));
        }
    }
}

为了使测试变为绿色,例如需要使用Mapper.CreateMap<Source, Destination>().ConvertUsing<SourceToDestinqtionConvertor>();

    [Fact]
    public void Example3()
    {
        container
            .Register(Types.FromAssembly(Assembly.GetExecutingAssembly())
            .BasedOn(typeof(ITypeConverter<,>)));

        Mapper.Initialize(m => m.ConstructServicesUsing(container.Resolve));
        container.Register(Component.For<IMappingEngine>().Instance(Mapper.Engine));

        var engine = container.Resolve<IMappingEngine>();

        Mapper.CreateMap<Source, Destination>().ConvertUsing<SourceToDestinqtionConvertor>();

        var destination = engine.Map<Source, Destination>(new Source { Value = 15 });

        destination.Value.Should().Be(15);
    }

    public class SourceToDestinqtionConvertor : ITypeConverter<Source, Destination>
    {
        public Destination Convert(ResolutionContext context)
        {
            throw new System.NotImplementedException();
        }
    }

编辑:

为了能够解决&#39; ITypeConverter&#39;需要指定要使用的服务。

        container
            .Register(Types.FromAssembly(Assembly.GetExecutingAssembly())
            .BasedOn(typeof(ITypeConverter<,>))
            .WithService.AllInterfaces());

        // Makes sure that type converter can be resolved
        var resolver = container.Resolve<ITypeConverter<Source, Destination>>();
        resolver.Should().BeOfType<SourceToDestinqtionConvertor>();

答案 2 :(得分:0)

我执行以下操作以使Automapper工作。

注册点第一名:

        foreach (var automapperProfileType in types.Where(t => t.IsInterface == false && typeof(Profile).IsAssignableFrom(t)))
        {
            container.Register(
                Component.For(typeof(Profile))
                    .ImplementedBy(automapperProfileType)
                    .LifestyleTransient()
                    .Named("AutoMapper / Profile / " + automapperProfileType.FullName));
            automapperProfileTypes.Add(automapperProfileType);
        }

然后在所有类型的初始化之后:

        foreach (var profileMap in container.ResolveAll<Profile>())
        {
            Mapper.AddProfile(profileMap);
        }

希望有所帮助。