wake-up-neo.com

IoC in der Klassenbibliothek. Wo zu booten?

Ich verwende eine Klassenbibliothek, die von anderen Komponenten wiederverwendet werden kann. In dieser Klassenbibliothek verwende ich Unity für die Abhängigkeitsinjektion. Für diese Klassenbibliothek erstelle ich ein Testprojekt. Der Anrufer erhält auch ein Testprojekt. Ich bin mir nicht sicher, wo die Bindungen liegen. Sollte ich dies in die Klassenbibliothek aufnehmen oder sollte ich dies von der aufrufenden Anwendung aus tun?

28
Patrick

Das ist ein interessantes Problem. Wie können Abhängigkeiten wiederverwendbare Assemblys eingefügt werden, die keinen Einstiegspunkt haben. Ich würde gerne die Antwort anderer Leute sehen.

Abhängigkeitseinspritzung liegt in der Verantwortung der Eintrittsstelle Assembly . Wenn Sie jedoch über viele Klassen und Assemblys verfügen, die jeweils DI benötigen, ist es möglich, dass sie für einige Klassen/Assemblys aufgehoben werden, und die Aufgabe wird schwierig.

Lösung eins

Konvention über Konfiguration verwenden. Sie halten sich an eine Regel der Klasse Foo, die IFoo usw. implementiert. Viele DI-Frameworks verfügen über die Mittel, um sie mithilfe von Konventionen einzurichten.

Lösung zwei

Die obige Lösung löst nicht alle Probleme, da Sie manchmal das Setup der Injektion parametrieren müssen. So habe ich das Problem gelöst (insbesondere für die vonMEFgeladenen Assemblys und dies gilt für AutoFac):

Erstellt eine Schnittstelle IIocInstaller, in der Container (oder Builder) übergeben wird

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

Erstellt ein Assembly-Attribut, das Assemblys kennzeichnet, die DI benötigen:

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

In jeder Assembly erstelle ich eine Klasse, die DI einrichtet:

[Assembly: ExportAssembly]
namespace This.That
{

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

Im Einstiegspunkt habe ich einen allgemeinen Code, der alle geladenen Assemblys (einschließlich MEFed-Assemblys) mit dem Assembly-Attribut durchsucht, dann nach dem Typ sucht, der die Variable IIocInstaller implementiert, und dann Setup für sie aufrufen.

7
Aliostad

Ich weiß, dass eine Antwort gewählt wurde, jedoch denke ich, dass ein Teil von Unity übersehen wird. Da dies eine spezifische Unity-Frage war, dachte ich, ich weise auf die UnityContainerExtension-Basisklasse hin, die den IUnityContainerExtensionConfigurator implementiert. Hier können Sie die API-Bibliothek erweitern, um es der Einstiegspunktanwendung, der der Container gehört, zu vereinfachen, um auf einfache Weise sicherzustellen, dass Ihre Bibliothek korrekt im Container registriert wird, und dem API-Besitzer die Kontrolle darüber zu geben, was registriert wird Wie.

Dies wird von den Microsoft Enterprise Libraries für diesen Zweck verwendet. 

Ich werde eine Protokollierungsbibliothek als einfaches verwenden:

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

Dann führt die Einstiegspunktanwendung Folgendes aus:

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

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

    // ...
}

Jetzt haben sie die Enterprise Library und die API für die Logging-Bibliothek registriert. Es ist sehr einfach für die Einstiegspunktanwendung mit dieser Methode, die jeder Bibliotheksentwickler zum Ziel haben sollte.

25
Rodney S. Foley

Wenn Sie es von der aufrufenden Anwendung aus ausführen, wird die aufrufende Anwendung mehr belastet. Lassen Sie die Chance, die Initialisierung wegzulassen und in Schwierigkeiten zu geraten.

Ich würde es in der Klassenbibliothek tun, zum Beispiel in einem statischen Konstruktor.

2

O.K Erstellen Sie eine Bibliothek mit dem Namen Project.Ioc. Installiere Unity hier. Verweisen Sie die anderen Ebenen auf die Ioc-Bibliothek. Und Ioc Library zur Präsentationsschicht. Erstellen Sie eine Klasse mit dem Namen 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;
    }
}

Schauen Sie sich das MvcForum-Projekt an. Es gibt eine MvcForm.Ioc-Klassenbibliothek. Die Bibliothek erhält andere Layer-Referenzen. Es gibt nur eine Klasse namens UnityHelper.

https://github.com/leen3o/mvcforum

ich hoffe, das ist was Sie suchen.

0