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
}
}
}
使用 IMyNugetLibSingleton
和 IMyNugetLibTransient
我可以注册所有 类 并通过一个 register
语句实现这些。
我现在已将“惰性”从 MyNugetLib 移至 MyProj。注入的依赖项 myNugetLibLazyService 仅在需要时才解析。 MyNugetLib 的依赖项现在可以根据消费者的选择使用任何 DI 容器来解决。
我对这个解决方案很满意,但如果有人有更好的想法,我仍然乐于接受建议。
这建立在这个问题中讨论的概念之上 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
}
}
}
使用 IMyNugetLibSingleton
和 IMyNugetLibTransient
我可以注册所有 类 并通过一个 register
语句实现这些。
我现在已将“惰性”从 MyNugetLib 移至 MyProj。注入的依赖项 myNugetLibLazyService 仅在需要时才解析。 MyNugetLib 的依赖项现在可以根据消费者的选择使用任何 DI 容器来解决。
我对这个解决方案很满意,但如果有人有更好的想法,我仍然乐于接受建议。