Я использую библиотеку классов, которые могут быть повторно использованы другими компонентами. В этой библиотеке классов я использую единство для инъекций зависимостей. Для этой библиотеки классов я создаю тестовый проект. Вызывающий также получает тестовый проект. Единственное, о чем я не сомневаюсь, это расположение привязок. Должен ли я включить это в библиотеку классов или должен ли я сделать это из вызывающего приложения?
IoC в библиотеке классов. Где загружать
Ответ 1
Это интересная проблема. Как вы можете зависеть внедрять повторно используемые сборки, которые не имеют точки входа. Я бы очень хотел, чтобы другие люди ответили.
Запуск зависимостей несет ответственность за сборку входа. Тем не менее, если у вас есть много классов и сборок, каждый из которых нуждается в DI, то возможно, что они оставлены для некоторых классов/сборок, и задача становится обременительной.
Решение 1
Использование условной конфигурации. Вы придерживаетесь правила класса Foo
, реализующего IFoo
и т.д. Многие рамки DI имеют средства для настройки с помощью соглашения.
Решение два
Выше решение не решает всех проблем, так как иногда вам необходимо параметризовать установку инъекции. Вот как я решил проблему (особенно для тех сборок, загруженных MEF, и это для AutoFac
):
Создал интерфейс IIocInstaller
, где контейнер (или строитель передан)
public interface IIocInstaller
{
void Setup(ContainerBuilder builder);
}
Создан атрибут сборки, который содержит флажки сборок, требующих DI:
[AttributeUsage(AttributeTargets.Assembly)]
public class ExportAssemblyAttribute : Attribute
{
}
В каждой сборке я создаю класс, который устанавливает DI:
[assembly: ExportAssembly]
namespace This.That
{
[Export(typeof(IIocInstaller))]
public class IocInstaller : IIocInstaller
{
public void Setup(ContainerBuilder builder)
{
....
}
}
}
Затем в точке входа у меня есть общий код, который просматривает все загруженные сборки (включая MEFed), которые имеют атрибут сборки, а затем ищет тип, реализующий IIocInstaller
, а затем вызывает на них программу установки.
Ответ 2
Я знаю, что был выбран ответ, однако я думаю, что часть Unity игнорируется. Поскольку это был конкретный вопрос Единства, я думал, что я указываю базовый класс UnityContainerExtension, который реализует IUnityContainerExtensionConfigurator. Это позволяет расширять библиотеку API, чтобы облегчить для приложения-точки входа, которому принадлежит Контейнер, иметь простой способ убедиться, что ваша библиотека правильно зарегистрирована в контейнере и позволяет владельцу API контролировать, что регистрируется и как.
Это используется библиотеками Microsoft Enterprise для этой цели.
Я собираюсь использовать библиотеку журналов как простой:
public class LoggingUnityExtension : UnityContainerExtension
{
protected override void Initialize()
{
Container.RegisterType<ILogger, Logger>(new ContainerControlledLifetimeManager());
}
}
Затем приложение-точка входа выполняет следующее:
public class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.AddNewExtension<EnterpriseLibraryCoreExtension>();
Container.AddNewExtension<LoggingUnityExtension>();
// ...
}
// ...
}
Теперь они зарегистрировали Enterprise Library и API для библиотеки регистрации. Это очень просто для приложения с точкой входа с этим методом, который должен иметь любой разработчик библиотеки в качестве цели.
Ответ 3
Выполнение этого из вызывающего приложения ставит большую нагрузку на вызывающее приложение. Оставляя возможность опустить инициализацию и попасть в беду.
Я бы сделал это в библиотеке классов, например, в статическом конструкторе.
Ответ 4
O.K Создайте библиотеку с именем Project.Ioc. Установите Unity здесь. Ссылка на другие слои на библиотеку Ioc. И Ioc-библиотека для уровня представления. Создайте класс с именем UnityHelper.
/// <summary>
/// Bind the given interface in request scope
/// </summary>
public static class IocExtensions
{
public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
}
public static void BindInSingletonScope<T1, T2>(this IUnityContainer container) where T2 : T1
{
container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
}
}
/// <summary>
/// The injection for Unity
/// </summary>
public static class UnityHelper
{
public static IUnityContainer Start()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new Unity.Mvc4.UnityDependencyResolver(container));
return container;
}
/// <summary>
/// Inject
/// </summary>
/// <returns></returns>
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// Database context, one per request, ensure it is disposed
container.BindInRequestScope<IMVCForumContext, MVCForumContext>();
container.BindInRequestScope<IUnitOfWorkManager, UnitOfWorkManager>();
//Bind the various domain model services and repositories that e.g. our controllers require
container.BindInRequestScope<ITopicService, TopicService>();
container.BindInRequestScope<ITopicTagRepository, TopicTagRepository>();
//container.BindInRequestScope<ISessionHelper, SessionHelper>();
return container;
}
}
Посмотрите проект MvcForum. Существует библиотека классов MvcForm.Ioc. Библиотека получает другие ссылки на Layer. Существует только один класс под названием UnityHelper.
https://github.com/leen3o/mvcforum
Надеюсь, это то, что вы ищите.