web-dev-qa-db-fra.com

IoC dans la bibliothèque de classe. Où amorcer

J'utilise une bibliothèque de classes pouvant être réutilisée par d'autres composants. Dans cette bibliothèque de classes, j'utilise l'unité pour l'injection de dépendance. Pour cette bibliothèque de classes, je crée un projet de test. L'appelant obtient également un projet de test. Une chose que je ne sais pas, c'est l'emplacement des reliures. Devrais-je incorporer ceci dans la bibliothèque de classe ou devrais-je le faire à partir de l'application appelante?

28
Patrick

C'est un problème intéressant. Comment pouvez-vous créer des dépendances avec des assemblages réutilisables n’ayant pas de point d’entrée? J'aimerais vraiment voir la réponse des autres.

L’injection de dépendance est la responsabilité de l’ensemble entry-point Assembly. Cependant, si vous avez beaucoup de classes et d'assemblées ayant chacune besoin d'ID, il est possible qu'elles soient laissées de côté pour certaines classes/assemblées et la tâche devient fastidieuse.

Solution One

Utilisation de la convention sur la configuration. Vous vous en tenez à une règle de classe Foo mettant en œuvre IFoo, etc. De nombreux frameworks DI ont les moyens de le configurer à l'aide de conventions.

Solution deux

La solution ci-dessus ne résout pas tous les problèmes car il faut parfois paramétrer la configuration de l'injection. Voici comment j'ai résolu le problème (en particulier pour les assemblys chargés parMEFet ceci pour AutoFac):

Création d'une interface IIocInstaller où le conteneur (ou le générateur est passé)

public interface IIocInstaller
{
    void Setup(ContainerBuilder builder);
}

Création d'un attribut Assembly signalant les assemblages nécessitant un DI:

[AttributeUsage(AttributeTargets.Assembly)]
public class ExportAssemblyAttribute : Attribute
{
}

Dans chaque assemblée, je crée une classe qui configure DI:

[Assembly: ExportAssembly]
namespace This.That
{

    [Export(typeof(IIocInstaller))]
    public class IocInstaller : IIocInstaller
    {
        public void Setup(ContainerBuilder builder)
        {
            ....
        }
    }
}

Ensuite, dans le point d’entrée, j’ai un code commun qui examine tous les assemblys chargés (y compris ceux de MEFed) dotés de l’attribut Assembly, puis cherche le type implémentant la variable IIocInstaller, puis appelle le programme d’installation sur eux.

7
Aliostad

Je sais qu'une réponse a été choisie, mais je pense qu'une partie d'Unity est en train d'être négligée. Comme il s’agissait d’une question spécifique à Unity, j’ai voulu signaler la classe de base UnityContainerExtension qui implémente IUnityContainerExtensionConfigurator. C’est là que la bibliothèque d’API doit s’étendre pour que l’application point d’entrée propriétaire du conteneur dispose d’un moyen simple de s’assurer que votre bibliothèque est correctement enregistrée avec le conteneur, Comment.

Cela est utilisé par les bibliothèques d'entreprise Microsoft à cette fin. 

Je vais utiliser une bibliothèque de journalisation comme simple:

public class LoggingUnityExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        Container.RegisterType<ILogger, Logger>(new ContainerControlledLifetimeManager());
    }
}

Ensuite, l'application de point d'entrée fait ceci:

public class Bootstrapper : UnityBootstrapper
{
    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();

        Container.AddNewExtension<EnterpriseLibraryCoreExtension>();
        Container.AddNewExtension<LoggingUnityExtension>();
        // ... 
    }

    // ...
}

Maintenant, ils ont enregistré Enterprise Library et l'API pour la bibliothèque de journalisation. C'est très simple pour l'application de point d'entrée avec cette méthode, qui est l'objectif de tout développeur de bibliothèque.

25
Rodney S. Foley

Le faire à partir de l'application appelante alourdit l'application. Laissant la chance d'omettre l'initialisation et avoir des ennuis.

Je le ferais dans la bibliothèque de classe, par exemple dans un constructeur statique.

2
Ventsyslav Raikov

O.K Créer une bibliothèque nommée Project.Ioc. Installez Unity ici. Référencez les autres couches à la bibliothèque Ioc. Et Ioc Library à la couche de présentation. Créez une classe nommée 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;
    }
}

Découvrez le projet MvcForum. Il existe une bibliothèque de classes MvcForm.Ioc. La bibliothèque obtient d'autres références de couche. Il n'y a qu'une seule classe nommée UnityHelper.

https://github.com/leen3o/mvcforum

j'espère que c'est ce que vous cherchez.

0
Taşyürek Gökşah