Статьи

StructureMap — не сканировать все сборки

В одном из моих проектов (на основе .NET — с использованием веб-API) я использую StructureMap в качестве инструмента внедрения зависимостей. Основная настройка, которую я имею для этого, состоит в том, что для каждой сборки, где требуется внедрение зависимости, у меня есть класс разрешения зависимости, который расширяет класс RegistryMap Registry. Вот простой и понятный пример:

namespace Security.DependencyResolution
{
    public class SecurityRegistry : Registry
    {
        public SecurityRegistry()
        {
            Scan(config =>
                        {
                            config.WithDefaultConventions();
                            config.AssembliesFromApplicationBaseDirectory();
                            config.IncludeNamespace("Data.Repositories");
                            config.IncludeNamespace("Security");
                        });
                    }

        public static void Initialize(IContainer container)
        {
            container.Configure(ct => ct.Scan(scan =>
                                                {
                                                    scan.LookForRegistries();
                                                    scan.TheCallingAssembly();
                                                }));
        }
    }
}

Я хочу сосредоточиться на методе AssembliesFromApplicationBaseDirectory, поскольку именно он вызвал у меня сегодня головную боль. Когда вызывается AssembliesFromApplicationBaseDirectory, обходится базовый каталог текущего домена приложения, и любая найденная сборка добавляется в операцию сканирования. Обратите внимание, что я также использую WithDefaultConventions, которая сообщает сканеру, что любой конкретный класс с именем Product , например, реализует интерфейс с именем IProduct , и он добавляется в PluginTypeIProduct . Это избавит вас от использования явных объявлений PluginTypes для <IProduct> (). Используйте <Product> () .

Поскольку приложение имеет несколько уровней, зависимости довольно сложны. Вот почему я подумал, что если я использую AssembliesFromApplicationBaseDirectory в конфигурации сканера, это будет отличная идея. Что ж, я был не прав, потому что в итоге я получил следующее исключение, которое выдается каждый раз при загрузке StructureMap:


Сбои конфигурации StructureMap: Ошибка: 170 Источник: Реестр: StructureMap.Configuration.DSL.Registry, StructureMap, Версия = 2.6.4.0, Culture = нейтральный, PublicKeyToken = e60ad81abae3c223 Не удается найти экспортированные типы в сборке System.Web.Http, Version = 5.0.0.0, Культура = нейтральная, PublicKeyToken = 31bf3856ad364e35. Одна или несколько зависимостей сборки могут отсутствовать. Не удалось загрузить файл или сборку ‘System.Net.Http.Formatting, версия = 5.0.0.0, культура = нейтральная, PublicKeyToken = 31bf3856ad364e35’ или одна из ее зависимостей. Определение манифеста обнаруженной сборки не соответствует ссылке на сборку. (Исключение из HRESULT: 0x80131040) System.IO.FileLoadException: не удалось загрузить файл или сборку ‘System.Net.Http.Formatting, версия = 5.0.0.0, культура = нейтральная, PublicKeyToken = 31bf3856ad364e35’или одна из его зависимостей. Определение манифеста обнаруженной сборки не соответствует ссылке на сборку. Было очевидно, что StructureMap проверяет «все» сборки из базового каталога текущего домена приложения. Это не то, что я собирался осуществить, есть системные сборки, которые не нужны для внедрения зависимостей. Я мог бы сказать, что мне повезло, что это исключение появилось, потому что это решило меня добавить некоторую фильтрацию в процесс. Если вы проверите документацию StructureMap, вы заметите, что AssembliesFromApplicationBaseDirectory имеет перегрузку, которая принимает предикат, на основе которого он будет фильтровать сборки, которые должны быть добавлены в операцию сканирования.Поэтому я определил локальный массив, который содержит имя сборок, которые должны быть добавлены в операцию сканирования, и использовал его в предикате фильтрации.

Было очевидно, что StructureMap проверяет «все» сборки из базового каталога текущего домена приложения. Это не то, что я хотел. Существуют системные сборки, которые не нужны для внедрения зависимостей. Могу сказать, что мне повезло, что появилось это исключение, поэтому я решил добавить немного фильтрации в этот процесс. Если вы проверите документацию StructureMap, вы заметите, что AssembliesFromApplicationBaseDirectory имеет перегрузку, которая принимает предикат. Основываясь на предикате, он будет фильтровать сборки, которые должны быть добавлены в операцию сканирования. Поэтому я определил локальный массив, который содержит имя сборок, которые следует добавить в операцию сканирования и использовать их в предикате фильтрации.

namespace  Security.DependencyResolution
{
    public class SecurityRegistry : Registry
    {
        public SecurityRegistry()
        {
            var assemblies = new[] { "Data.Repositories", " Security" };
            Scan(config =>
                        {
                            config.AssembliesFromApplicationBaseDirectory(assembly => assemblies.Contains(assembly.FullName));
                            config.IncludeNamespace("Data.Repositories");
                            config.IncludeNamespace("Security");
                        });
                    }

        public static void Initialize(IContainer container)
        {
            container.Configure(ct => ct.Scan(scan =>
                                                {
                                                    scan.LookForRegistries();
                                                    scan.TheCallingAssembly();
                                                }));
        }
    }
}

Кроме того, я решил отказаться от WithDefaultConventions в пользу явного объявления. По крайней мере, это сделает вещи более очевидными, хотя и более многословно. Вывод: не используйте ярлыки, если только вы не уверены на 100%, что они будут работать должным образом при любых обстоятельствах.