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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2651613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 14:10:15  来源:igfitidea点击:

How to scan and auto-configure profiles in AutoMapper?

.netstructuremapprofileautomapper

提问by Wojciech Markowski

Is there any way to auto-configue Automapper to scan for all profiles in namespace/assembly? What I would like to do is to add mapping profiles to AutoMapper from given assembly filtered by given interface, something like Scan Conventions in StructureMap:

有没有办法自动配置 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);            
    }

I've tried to use SelfConfigure but can't find any documentation on how to use it to filter out profiles:

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

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

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

Another question is how can I report all maps/profiles already initialized (something like ObjectFactory.WhatDoIHave() in StructureMap)?

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

回答by Jason More

I found this post while searching as well, but this is how I implemented an auto mapping scheme:

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

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);
        }
    }
}

So when my application starts, all I call is

所以当我的应用程序启动时,我只调用

AutoMapperConfiguration.Configure(); 

And all my maps are registered.

我所有的地图都已注册。

回答by Martino Bordin

In the latest versions of AutoMapper it's possible to register multiple Profilescanning one or more assemblies :

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

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

Tested with AutoMapper v. 6.0.2.0

使用 AutoMapper v. 6.0.2.0测试

回答by Jimmy Bogard

Yeah, that would be fantastic...and exactly what I'm overhauling for V2. Scanning, registration, conventions etc.

是的,那太棒了……这正是我正在为 V2 大修的内容。扫描、注册、约定等

There's not a good "What do I have" feature, but I think it would definitely be worth adding.

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

回答by Rosco

In version 9 of AutoMapper it can be done this way

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

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

If you are using ASP.NET Core there is a helper extension to register all Profiles in Startup.ConfigureServices

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

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

or

或者

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

回答by epitka

I have it like this, don't know if it is the best way but it works very well on pretty large project.

我有这样的,不知道这是否是最好的方法,但它在相当大的项目中效果很好。

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);
            }
        }
    }
}

回答by user3472484

 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);
    }
}

回答by Cirem

Similar to @Martino's answer, but with a MapperConfiguration object. This will add all profiles from the assembly that contains the type MyProfile.

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

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

回答by Vinicius.Beloni

In .NET Core:

在 .NET 核心中:

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