NuGet 包库中的依赖注入

Dependency Injection in NuGet package library

这建立在这个问题中讨论的概念之上 How to manage Castle Windsor dependencies in a nuget library.

我正在开发一个使用 Castle.Windsor 进行 DI 并引用多个自定义 NuGet 包的项目。我已经在通过 NuGet 引用的 class 库之一(我们称之为 MyNugetLib)中安装了 Castle.Windsor,并且我在该库中的 IWindsorContainer 上定义了一个扩展方法,用于注册本地服务。

public static class WindsorContainerExtensions
{
    public static void RegisterMyNugetLibServices(this IWindsorContainer container)
    {
        container.RegisterLocalServices();
    }
    
    private static void RegisterLocalServices(this IWindsorContainer container)
    {
        container.Register(...)
    }
}

引用此 NuGet 包的项目(我们称之为 MyProj)也使用 Windsor,在安装程序中它调用 NuGet 包中定义的扩展方法。这一切都有效。 我的问题是如何将 Windsor 容器引用从 MyProj 传递给 MyNugetLib?我已经尝试在我需要的 class 的构造函数中注入 IWindsorContainer,但是这个 class 使用延迟实例化如下:

private static readonly Lazy<MyClass> LazyInstance = new Lazy<MyClass>(() => new MyClass());
    
private MyClass() {}

public static MyClass Instance => LazyInstance.Value;

从 MyProj 中调用如下:

Lib.MyClass.Instance

我设法完成这项工作的唯一方法是在 MyClass 中公开一个 public 属性,它在 MyProj 中用于设置 WindsorContainer

public IWindsorContainer DIContainer { get; set; }

在我的项目中

Lib.MyClass.DIContainer = MyProj.WindsorContainer

我不是特别喜欢这个。有更好的方法吗?


更新:(感谢 insane_developer 的建议)

真正的问题是:如何在 Lazy 构造函数中注入依赖项?如果我能做到这一点,那么我就可以从 MyNugetLib 中删除对 Windsor 的依赖。

所以我会

private IService1 service1;
private IService2 service2;

private MyClass(IService1 myService1, IService2 myService2) 
{
    this.service1 = myService1;
    this.service2 = myService2
}

public static MyClass Instance => LazyInstance.Value;

private static readonly Lazy<MyClass> LazyInstance = new Lazy<MyClass>(() => new MyClass(???));

如何编写上面的 func 以便它在我的构造函数中注入依赖项?

我从未使用过 Castle.Windsor 但我认为它会像其他容器一样。您实际上不需要将对容器的引用传递给您的库。您应该能够在主应用程序中配置所有映射,该应用程序引用了您的库。如果你按照你的建议去做,你将对 Castle.Windsor 产生具体的依赖,这不是一个好主意。

感谢@insane_developer 的建议,我能够以更简洁的方式完成此操作。 问题是 MyNugetLib 使用的是使用 Lazy<T> 创建的静态单例。无法在这些构造函数中注入依赖项,因此我试图找出一种将引用传递给 DI 容器的好方法。然而,这可能会完成,它引入了对 MyNugetLib 中的 DI 包的直接依赖,这不是很好。更好的解决方案是在 MyNugetLib 中始终如一地使用依赖注入,使用静态单例重构 类 以拥有具有注入依赖项的普通构造函数,并从主应用程序 (MyProj) 注册这些依赖项。为了做到这一点,我不得不重构 MyProj 使用一些 MyNugetLib 类 的方式,这样它就不再通过静态属性引用单例,而是通过注入的依赖项,这些依赖项在主 DI 容器中注册为单例并作为惰性依赖项注入。 这就是我所做的(概念上的)。

namespace MyNugetLib.DI
{
    public interface IMyNugetLibSingleton {}

    public interface IMyNugetLibTransient {}
}

namespace MyNugetLib
{
    public interface IMyClass : IMyNugetLibSingleton 
    {
        MyType DoSomething();
    }

    public interface IMyService : IMyNugetLibTransient 
    {
        MyOtherType DoSomethingElse();
    }

    public MyService : IMyService 
    {
        MyOtherType DoSomethingElse() 
        {
            // do something important
        }
    }

    public MyClass : IMyClass 
    {
        private IMyService myService;

        public MyClass(IMyService myInjectedService) 
        {
            this.myService = myInjectedService;
        }

        MyType DoSomething() 
        {
            // doing something important using this.myService
            this.myService.DoSomethingElse();
        }
    }
}

然后,在 MyProj

namespace MyProj
{
    public class WindsorInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            // enable registration of lazy services
            container.Register(Component.For<ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>());
            
            container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibSingleton)).BasedOn<MyNugetLib.DI.IMyNugetLibSingleton>().WithService.FromInterface().LifestyleSingleton());
            
            container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibTransient)).BasedOn<MyNugetLib.DI.IMyNugetLibTransient>().WithService.FromInterface().LifestyleTransient());
            
            // register local services
        }
    }
    
    public class MyLocalClass : IMyLocalClass
    {
        private Lazy<MyNugetLib.IMyClass> myNugetLibLazyService
        
        public MyLocalClass(Lazy<MyNugetLib.IMyClass> lazyService)
        {
            this.myNugetLibService = lazyService;
        }
        
        internal MyLocalType DoSomethingHere() 
        {
            this.myNugetLibService.Value.DoSomething();
            // etc
        }
    }
}

使用 IMyNugetLibSingletonIMyNugetLibTransient 我可以注册所有 类 并通过一个 register 语句实现这些。 我现在已将“惰性”从 MyNugetLib 移至 MyProj。注入的依赖项 myNugetLibLazyService 仅在需要时才解析。 MyNugetLib 的依赖项现在可以根据消费者的选择使用任何 DI 容器来解决。

我对这个解决方案很满意,但如果有人有更好的想法,我仍然乐于接受建议。