如何在AutoMapper中扫描和自动配置配置文件?

时间:2010-04-16 08:34:55

标签: .net structuremap profile automapper

有没有办法自动配置Automapper来扫描命名空间/程序集中的所有配置文件?我想要做的是从给定接口过滤的给定程序集中将映射配置文件添加到AutoMapper,类似于StructureMap中的扫描约定:

    public static void Configure()
    {
        ObjectFactory.Initialize(x =>
            {
                // Scan Assembly
                x.Scan(
                    scanner =>
                    {
                        scanner.TheCallingAssembly();
                        scanner.Convention<MyCustomConvention>();
                        scanner.WithDefaultConventions();
                    });

                // Add Registries
                x.AddRegistry(new SomeRegistry());
            });

        Debug.WriteLine(ObjectFactory.WhatDoIHave());
    }

public class MyCustomConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (!type.CanBeCastTo(typeof(IMyType)))
        {
            return;
        }

        string name = type.Name.Replace("SomeRubishName", String.Empty);
        registry.AddType(typeof(IMyType), type, name);            
    }

我尝试使用SelfConfigure但找不到任何关于如何使用它来过滤配置文件的文档:

    public static void Configure()
    {
        Mapper.Initialize(x =>
                              {
                                  // My Custom profile
                                  x.AddProfile<MyMappingProfile>();

                                  // Scan Assembly
                                  x.SelfConfigure(Assembly.GetCallingAssembly());
                              });
    }

另一个问题是我如何报告已经初始化的所有地图/配置文件(类似于StructureMap中的ObjectFactory.WhatDoIHave())?

9 个答案:

答案 0 :(得分:35)

我在搜索时发现了这篇文章,但这就是我实现自动映射方案的方式:

public class MyCustomMap : Profile
{
    protected override void Configure()
    {
        CreateMap<MyCustomViewModel, MyCustomObject>()
            .ForMember(dest => dest.Phone,
                        opt => opt.MapFrom(
                        src => src.PhoneAreaCode + src.PhoneFirstThree + src.PhoneLastFour));
    }
}

public static class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(x => GetConfiguration(Mapper.Configuration));
    }

    private static void GetConfiguration(IConfiguration configuration)
    {
        var profiles = typeof(MyCustomMap).Assembly.GetTypes().Where(x => typeof(Profile).IsAssignableFrom(x));
        foreach (var profile in profiles)
        {
            configuration.AddProfile(Activator.CreateInstance(profile) as Profile);
        }
    }
}

所以当我的应用程序启动时,我所有的呼叫都是

AutoMapperConfiguration.Configure(); 

我的所有地图都已注册。

答案 1 :(得分:13)

在最新版本的AutoMapper中,可以注册多个配置文件扫描一个或多个程序集:

 Mapper.Initialize(x => x.AddProfiles(typeof(MyMappingProfile).Assembly));

使用AutoMapper v。 6.0.2.0

进行测试

答案 2 :(得分:9)

在AutoMapper的版本9中,可以通过这种方式完成

var configuration = new MapperConfiguration(cfg =>
{
    // Add all Profiles from the Assembly containing this Type
    cfg.AddMaps(typeof(MyApp.SomeClass));
});

如果您使用的是ASP.NET Core,则有一个帮助程序扩展,可以在Startup.ConfigureServices中注册所有配置文件。

// UI project
services.AddAutoMapper(Assembly.GetExecutingAssembly());

// Another assembly that contains a type
services.AddAutoMapper(Assembly.GetAssembly(typeof(MyApp.SomeClass)));

答案 3 :(得分:7)

是的,那太棒了......而且正是我正在为V2进行改造。扫描,注册,会议等。

没有一个好的“我有什么”功能,但我认为这绝对值得添加。

答案 4 :(得分:1)

我喜欢这样,不知道这是不是最好的方式,但它在相当大的项目中运作良好。

public class AutoMapperGlobalConfiguration : IGlobalConfiguration
    {
        private AutoMapper.IConfiguration _configuration;

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

        public void Configure()
        {
            //add all defined profiles
            var query = this.GetType().Assembly.GetExportedTypes()
                .Where(x => x.CanBeCastTo(typeof(AutoMapper.Profile)));

            _configuration.RecognizePostfixes("Id");

            foreach (Type type in query)
            {
                _configuration.AddProfile(ObjectFactory.GetInstance(type).As<Profile>());
            }

            //create maps for all Id2Entity converters
            MapAllEntities(_configuration);

           Mapper.AssertConfigurationIsValid();
        }

        private static void MapAllEntities(IProfileExpression configuration)
        {
            //get all types from the SR.Domain assembly and create maps that
            //convert int -> instance of the type using Id2EntityConverter
            var openType = typeof(Id2EntityConverter<>);
            var idType = typeof(int);
            var persistentEntties = typeof(SR.Domain.Policy.Entities.Bid).Assembly.GetTypes()
               .Where(t => typeof(EntityBase).IsAssignableFrom(t))
               .Select(t => new
               {
                   EntityType = t,
                   ConverterType = openType.MakeGenericType(t)
               });
            foreach (var e in persistentEntties)
            {
                var map = configuration.CreateMap(idType, e.EntityType);
                map.ConvertUsing(e.ConverterType);
            }
        }
    }
}

答案 5 :(得分:1)

只是为了添加到@Rosco 答案中,您可以使用 typeof(class) 而不是程序集。任何课程都可以。

services.AddAutoMapper(typeof(Startup));

那么你就不需要添加反射引用了。

如果您在多个程序集中有配置文件,您可以像这样使用它。

services.AddAutoMapper(typeof(Startup), typeof(User));

答案 6 :(得分:0)

 public class AutoMapperAdapter : IMapper
{
    private readonly MapperConfigurationExpression _configurationExpression =
        new MapperConfigurationExpression();

    public void AssertConfigurationIsValid() { Mapper.AssertConfigurationIsValid(); }

    public void CreateMap<TSource, TDestination>()
    {
        _configurationExpression.CreateMap<TSource, TDestination>();
    }

    public void Initialize() { Mapper.Initialize(_configurationExpression); }

    public TDestination Map<TDestination>(object source)
    {
        return Mapper.Map<TDestination>(source);
    }
}

答案 7 :(得分:0)

类似于@Martino的答案,但带有MapperConfiguration对象。这将添加程序集中包含MyProfile类型的所有配置文件。

var config = new MapperConfiguration(cfg =>
   {
      cfg.AddProfiles(typeof(MyProfile));
   });
var mapper = config.CreateMapper();

答案 8 :(得分:0)

在.NET Core中:

    services.AddSingleton(this.CreateMapper());
    //...
    private IMapper CreateMapper()
            => new MapperConfiguration(config => config.AddMaps(Assembly.Load("Your.Project.App")))
            .CreateMapper();