Как я могу добавить профили AutoMapper в конфигурацию Mapper, используя цикл for? - PullRequest
0 голосов
/ 07 марта 2019

Я хочу загрузить несколько профилей автоматического создания библиотек, на которые ссылаются, без необходимости набирать каждый из них вручную.

Я пытаюсь предпринять следующие шаги:

  1. Получить все профили из сборок, на которые есть ссылки
  2. Добавить профили в конфигурацию mapper
  3. Зарегистрировать mapper для DI

Шаг 1 работает, но что-то идет не так в шаге 2.

Текущий код:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {            
        var container = new UnityContainer();

        var assemblyNames = Assembly.GetExecutingAssembly().GetReferencedAssemblies()
            .Where(a => a.Name.StartsWith("OKL_KPS"));

        var assemblies = assemblyNames.Select(an => Assembly.Load(an));

        var loadedProfiles = new List<Type>();
        foreach (var assembly in assemblies)
        {
            var assemblyProfiles = assembly.ExportedTypes.Where(type => type.IsSubclassOf(typeof(Profile)));
            loadedProfiles.AddRange(assemblyProfiles);
        }

        var mapconfig = new MapperConfiguration(cfg =>
        {
            // Magic should happen here
            foreach (var profile in loadedProfiles)
            {
                var resolvedProfile = container.Resolve(profile) as Profile;
                cfg.AddProfile(resolvedProfile);
            }
        });

        container.RegisterInstance<IMapper>(mapconfig.CreateMapper());

        config.DependencyResolver = new UnityResolver(container);

        //routes here
    }
}

Я также попытался cfg.AddProfile((Profile)Activator.CreateInstance(profile.AssemblyQualifiedName, profile.Name).Unwrap());, но при этом возвращается имя сборки службы, в которой я его использую, а не имя библиотеки, в которой находится профильс.

Редактировать

Сборки не загружаются во время шага регистрации.Чтобы взломать это, в каждой библиотеке есть класс Dummy, который инициализируется перед регистрацией профилей.Оптимальное решение - не использовать эти фиктивные классы, иначе было бы удобнее добавить каждый профиль явно.

Я также попытался добавить ExportAttribute в профиль, но это тоже не сработало.

Ответы [ 3 ]

1 голос
/ 11 марта 2019

Вы сканируете загруженные сборки на доступные свойства, используя запросы LINQ. Примерно так должно работать:

            var profiles = AllClasses.FromLoadedAssemblies().
                Where(type => typeof(Profile).IsAssignableFrom(type));

            //add profiles to config
            var mapconfig = new MapperConfiguration(cfg =>
            {
                // Magic should happen here
                foreach (var profile in profiles)
                {
                    var resolvedProfile = container.Resolve(profile) as Profile;
                    cfg.AddProfile(resolvedProfile);
                }
            });

            //register mapper using config
            container.RegisterInstance<IMapper>(mapconfig.CreateMapper());
0 голосов
/ 11 марта 2019

В документации описано, как использовать AutoMapper с платформой Microsoft DI. И там он просто перенаправляет в соответствующий пакет NuGet и статью , в которой описывается, как он ищет в текущем домене приложения все открытые типы и профили для их загрузки.

В ваших классах вам нужно просто вставить IMapper imapper в конструктор, который просто делает то, что вы ожидаете.

Единственное следующее предостережение, с которым я столкнулся, было то, что не все мои сборки были загружены до того, как я вызвал services.AddAutoMapper() в моем методе ConfigureServices(). Но для этого случая я просто добавил простой вспомогательный метод, который будет вызываться до того, как DI начнет выполнять свою работу:

public static void LoadAllLocalAssemblies()
{
    var entryAssembly = Assembly.GetEntryAssembly();
    var location = entryAssembly.Location;
    var path = Path.GetDirectoryName(location);

    var files = Directory.EnumerateFiles(path, "*.dll");

    foreach (var file in files)
    {
        try
        {
            Assembly.LoadFrom(file);
        }
        catch
        {
        }
    }
}

После этого все сборки загружаются в текущий домен приложения, и пакет NuGet разрешает все классы, производные от Profile. Мои обработчики вставляют IMapper mapper в конструктор, и в моем методе я могу вызвать mapper.Map<MyDestination>(mySource), и он работает как положено.

Никаких фиктивных классов, интерфейсов или чего-либо еще не требуется.

0 голосов
/ 08 марта 2019

Вы можете добавить профили, указав свой экземпляр сборки, имя или тип сборки.

Использование имен:

 var mapconfig = new MapperConfiguration(cfg =>
        {
           cfg.AddProfiles("Foo.YourProject.API");
           cfg.AddProfiles("Foo.YourProject.Service");
           cfg.AddProfiles("Foo.YourProject.Repository");
           ...
        });

Также см. Официальную документацию для получения дополнительной информации.

...