Что мы делаем в моем текущем проекте (который использует AutoFac, а не StructureMap, но я думаю, что это не должно иметь значения):
У нас есть интерфейсы, определяющие внешние службы, которые приложение использует в базовой сборке, скажем, App.Core
(например, ваша PersonBase).
Тогда у нас есть реализации этих интерфейсов в 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 Controllers) с каждая потенциальная конфигурация контейнера IOC.
В противном случае довольно легко забыть реализовать один интерфейс и разбить огромные разделы вашего приложения.