Подтвердить что ты не робот

IoC в библиотеке классов. Где загружать

Я использую библиотеку классов, которые могут быть повторно использованы другими компонентами. В этой библиотеке классов я использую единство для инъекций зависимостей. Для этой библиотеки классов я создаю тестовый проект. Вызывающий также получает тестовый проект. Единственное, о чем я не сомневаюсь, это расположение привязок. Должен ли я включить это в библиотеку классов или должен ли я сделать это из вызывающего приложения?

4b9b3361

Ответ 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

Надеюсь, это то, что вы ищите.