IoC, ссылки на библиотеки DLL и сканирование сборки

StackOverflow https://stackoverflow.com/questions/809051

Вопрос

Хотя этот вопрос связан со StructureMap, мой Общая информация вопрос в том,:

При подключении компонентов с МОК контейнер в коде (в отличие от настройки через xml) вам вообще нужны явные ссылки на проект / сборку на все сборки?

Зачем нужны отдельные сборки?Потому что:


"Абстрактные классы, находящиеся в отдельной сборке от их конкретных реализаций, являются отличным способом добиться такого разделения". -Структура Рекомендации по проектированию, стр.91


Пример:

Допустим, у меня есть PersonBase.dll и Bob.dll

Боб наследуется от абстрактного класса База данных персон.Они оба находятся в Человек пространство имен. Но в разных сборках.

Я программирую, чтобы База данных персон, не Боб.

Возвращаясь к моему основному коду, мне нужен человек.StructureMap может сканировать сборки.Отлично, я попрошу StructureMap сделать это!

Теперь, в моем основном коде, я, конечно, имею в виду только База данных персон, не для того , чтобы Боб.На самом деле я не хочу, чтобы мой код знал что угодно о нас Боб.Никаких ссылок на проект, вообще ничего.В этом-то все и дело.

Поэтому я хочу сказать:

//Reference: PersonBase.dll (only)
using Person;  
...

//this is as much as we'll ever be specific about Bob:
Scan( x=> { x.Assembly("Bob.dll"); }

//Ok, I should now have something that's a PersonBase (Bob). But no ?
ObjectFactory.GetAllInstances<PersonBase>().Count == 0

Не повезло.Что действительно работает, так это явное указание на то, что я хочу Боба:

//Reference: PersonBase.dll and Bob.dll
using Person; 
...
Scan( x => {x.Assembly("Bob.dll"); }

//If I'm explicit, it works. But Bob's just a PersonBase, what gives?
ObjectFactory.GetAllInstances<Bob>().Count == 1 //there he is!

Но теперь мне пришлось сослаться Bob.dll в моем проекте, а это именно то, чего я не хотел.

Я могу избежать этой ситуации, используя конфигурацию Spring + Xml.Но затем я возвращаюсь к конфигурации Spring + Xml ...!

Я что-то упускаю при использовании StructureMap или, в качестве общего принципа, нужны ли (свободно) конфигурации IoC явные ссылки на все сборки?

Возможно, связанный с этим вопрос: Структурная карта и сканирующие сборки

Это было полезно?

Решение

Наконец-то я во всем разобрался.Это выглядит примерно так:

IoC Uml http://img396.imageshack.us/img396/1343/iocuml.jpg

с помощью сборок

  • Core.exe
  • PersonBase.dll (ссылка время компиляции автор Core.exe)
  • Bob.dll (загруженное время выполнения с помощью сканирования карты структуры)
  • Бетти.библиотека dll (загруженное время выполнения с помощью сканирования карты структуры)

Чтобы получить его с помощью StructureMap, мне понадобился пользовательский "ITypeScanner" для поддержки сканирования сборок:

public class MyScanner : ITypeScanner {
  public void Process(Type type, PluginGraph graph) {

    if(type.BaseType == null) return;

    if(type.BaseType.Equals(typeof(PersonBase))) {
      graph.Configure(x => 
        x.ForRequestedType<PersonBase>()
        .TheDefault.Is.OfConcreteType(type));
    }
  }
} 

Итак, мой основной код выглядит следующим образом:

ObjectFactory.Configure(x => x.Scan (
  scan =>
  {
    scan.AssembliesFromPath(Environment.CurrentDirectory 
    /*, filter=>filter.You.Could.Filter.Here*/);

    //scan.WithDefaultConventions(); //doesn't do it

    scan.With<MyScanner>();
  }
));

ObjectFactory.GetAllInstances<PersonBase>()
 .ToList()
  .ForEach(p => 
  { Console.WriteLine(p.FirstName); } );

Другие советы

Вы также можете выполнить настройку xml с помощью StructureMap.Вы даже можете смешать их, если хотите.

Существуют также атрибуты StructureMap, которые вы могли бы поместить в свой класс Bob, чтобы указать StructureMap, как загружать сборку.DefaultConstructor - это тот, который я в конечном итоге использую время от времени.

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

ObjectFactory.Initialize(initialization => 
   initialization.ForRequestedType<PersonBase>()
    .TheDefault.Is.OfConcreteType<Bob>());

Что мы делаем в моем текущем проекте (который использует AutoFac, а не StructureMap, но я думаю, что это не должно иметь значения):

У нас есть интерфейсы, определяющие внешние службы, которые приложение использует, скажем, в базовой сборке App.Core (например, ваша персональная база).

Затем у нас есть реализации этих интерфейсов в Services.Real (например, Bob.dll).

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

Само интерфейсное "клиентское" приложение (в нашем случае, ASP.NET Приложение MVC) ссылается App.Core.

Когда приложение запускается, мы используем Assembly.Load загрузить соответствующую библиотеку DLL реализации "Services", основанную на настройках конфигурации.

Каждая из этих библиотек DLL имеет реализацию IServiceRegistry, которая возвращает список сервисов, которые она реализует:

public enum LifestyleType { Singleton, Transient, PerRequest}

public class ServiceInfo {
    public Type InterfaceType {get;set;}
    public Type ImplementationType {get;set;}
    // this might or might not be useful for your app, 
    // depending on the types of services, etc.
    public LifestyleType Lifestyle {get;set;} 
}

public interface IServiceRegistry {
    IEnumerable<ServiceInfo> GetServices();
}

...приложение находит этот ServiceRegistry с помощью отражения и перечисляет через эти экземпляры ServiceInfo и регистрирует их в контейнере.Для нас этот реестр всех служб находится в веб-приложении, но возможно (и предпочтительнее во многих случаях) разместить его в отдельной сборке.

Таким образом, мы можем изолировать логику домена от кода инфраструктуры и предотвратить обходные пути "только один раз", когда приложение оказывается в зависимости от прямой ссылки на код инфраструктуры.Мы также избегаем необходимости иметь ссылку на контейнер в каждой реализации Сервисов.

Одна действительно важная вещь, если вы делаете это:сделать конечно что у вас есть тесты, которые подтверждают, что вы можете создавать каждый тип "верхнего уровня" (в нашем случае, ASP.NET Контроллеры MVC) с каждой потенциальной конфигурацией контейнера IOC.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top