寻找将温莎生活方式带入图书馆的方式
Looking for way to pass Windsor lifestyle into a library
我们有一个 Web api 项目,它引用了一个库,而这个库又在许多不同的系统之间共享。
该库公开了一个 "RegisterDependancies(IWindsorContainer container)" 函数,调用该函数时将为该特定库注册所有依赖项。
因此,当 Web api 应用程序启动时,它会进行自己的注册,然后调用共享库,类似于以下伪代码:
public void SetupWindsor(){
IWindsorContainer container = new WindsorContainer();
container.Register(Component.For<iFoo>().ImplementedBy<Foo>());
SharedLibrary.RegisterDependancies(container);
}
共享库函数看起来有点像这样:
public void RegisterDependancies(IWindsorContainer container)
{
container.Register(Component.For<iBar>().ImplementedBy<Bar>());
//In this instance Bar is internal so could not be registered by the api project.
}
我们现在希望网络 api 项目使用 PerWebRequest 生活方式,但其他系统可能希望使用不同的生活方式(这个决定将取决于编写客户端应用程序的人 - 将使用共享库在控制台和 windows 应用程序中 - 因此 perwebrequest 不适合他们使用)
我们想改变 RegisterDependancies 方法,以便我们可以传入生活方式。
是否可以使用 PerWebRequest 生活方式来做到这一点?我们中的一些人看了一眼,却不知道该怎么做 - 尽管过去曾做过类似的事情,但没有出现统一问题。
我们正在寻找一种方法来解决所描述的问题,或者如果有更好的方法来解决这个问题也会有所帮助。
编辑澄清一下,共享库将接口 IBar 定义为 public 但 class Bar 是内部的,因此 API 无法进行注册 - 除非有一些魔法我不知道的温莎
您可以使用LifeStyle.Is(LifestyleType)
在组件注册上设置生活方式
像这样的东西可以让你传递生命周期。
public void RegisterDependencies(IWindsorContainer container, Castle.Core.LifestyleType lifestyleType)
{
container.Register(Component.For<IBar>().ImplementedBy<Bar>().LifeStyle.Is(lifestyleType));
}
或者,看看按惯例向集会注册,这将允许从 API 项目中控制生活方式,而无需 public 实施
https://github.com/castleproject/Windsor/blob/master/docs/registering-components-by-conventions.md
the shared library defines the interface IBar as public but the class Bar as internal so the API cannot do the registration
让我们暂时研究一下该设计决策。虽然没有外部调用者可以创建 Bar
对象,但他们 可以 创建 IBar
对象:
IWindsorContainer container = new WindsorContainer();
SharedLibrary.RegisterDependancies(container);
IBar bar = container.Resolve<IBar>();
保留 Bar
class internal
可能有多种原因,但既然您已经可以像上面那样 运行 代码,为什么不简单地让共享图书馆公开工厂?
IBar bar = SharedLibrary.CreateBar();
那会简单得多,并且可以将共享库与容器分离。一般来说,这是我能给出的关于依赖注入和可重用库的最佳建议:使用依赖注入模式,而不是容器。请参阅我的文章 DI-Friendly Library 了解更多详情。
如果您仍想在宿主项目(例如 Wep API 项目)中使用 DI 容器,您可以针对该静态工厂方法注册IBar
。
内部 classes
人们想要保留一些 classes internal
是有正当理由的,但我经常看到代码库中 classes 是 internal
的原因并不明显原因。我对数十年 C# 代码的经验是,classes 无缘无故 internal
的情况远远超过有充分理由的情况。
Bar
真的必须是内部的吗?为什么?
从 OP 可以清楚地看出 IBar
是由 Bar
实现的。这 可能 是将问题简化为要点的人工制品(顺便说一句,干得好),但我的印象是 Bar
是 唯一的 class 实现了 IBar
。是这样吗?
如果是这样,Bar
class 必须公开 IBar
定义的方法。这样,class的API就已经是public了,为什么要隐藏class呢?那么,唯一隐藏的是构造函数...
完美风暴
有时,当我提出上述建议时,我会得到这样的回应,这不是问题所在。问题是关于如何改变温莎城堡的生活方式(顺便说一句,you can)。
另一方面,这个问题几乎是完美的(小)风暴,说明了为什么可重用库不应该依赖 DI 容器:
- 该库应该可以在不止一种环境中使用(网络、控制台、桌面等)
- 图书馆依赖温莎城堡
- 接口是 public,但实现 class 不是
这使事情变得复杂 - 因此这里出现了关于 Stack Overflow 的问题。
我最好的建议是保持简单。移除对 Castle Windsor 的依赖将使库的开发和重用更容易,而不是更难。
如果您将大多数库 class 设为 public.
,则使用该库会更容易
我们有一个 Web api 项目,它引用了一个库,而这个库又在许多不同的系统之间共享。
该库公开了一个 "RegisterDependancies(IWindsorContainer container)" 函数,调用该函数时将为该特定库注册所有依赖项。
因此,当 Web api 应用程序启动时,它会进行自己的注册,然后调用共享库,类似于以下伪代码:
public void SetupWindsor(){
IWindsorContainer container = new WindsorContainer();
container.Register(Component.For<iFoo>().ImplementedBy<Foo>());
SharedLibrary.RegisterDependancies(container);
}
共享库函数看起来有点像这样:
public void RegisterDependancies(IWindsorContainer container)
{
container.Register(Component.For<iBar>().ImplementedBy<Bar>());
//In this instance Bar is internal so could not be registered by the api project.
}
我们现在希望网络 api 项目使用 PerWebRequest 生活方式,但其他系统可能希望使用不同的生活方式(这个决定将取决于编写客户端应用程序的人 - 将使用共享库在控制台和 windows 应用程序中 - 因此 perwebrequest 不适合他们使用)
我们想改变 RegisterDependancies 方法,以便我们可以传入生活方式。
是否可以使用 PerWebRequest 生活方式来做到这一点?我们中的一些人看了一眼,却不知道该怎么做 - 尽管过去曾做过类似的事情,但没有出现统一问题。
我们正在寻找一种方法来解决所描述的问题,或者如果有更好的方法来解决这个问题也会有所帮助。
编辑澄清一下,共享库将接口 IBar 定义为 public 但 class Bar 是内部的,因此 API 无法进行注册 - 除非有一些魔法我不知道的温莎
您可以使用LifeStyle.Is(LifestyleType)
像这样的东西可以让你传递生命周期。
public void RegisterDependencies(IWindsorContainer container, Castle.Core.LifestyleType lifestyleType)
{
container.Register(Component.For<IBar>().ImplementedBy<Bar>().LifeStyle.Is(lifestyleType));
}
或者,看看按惯例向集会注册,这将允许从 API 项目中控制生活方式,而无需 public 实施 https://github.com/castleproject/Windsor/blob/master/docs/registering-components-by-conventions.md
the shared library defines the interface IBar as public but the class Bar as internal so the API cannot do the registration
让我们暂时研究一下该设计决策。虽然没有外部调用者可以创建 Bar
对象,但他们 可以 创建 IBar
对象:
IWindsorContainer container = new WindsorContainer();
SharedLibrary.RegisterDependancies(container);
IBar bar = container.Resolve<IBar>();
保留 Bar
class internal
可能有多种原因,但既然您已经可以像上面那样 运行 代码,为什么不简单地让共享图书馆公开工厂?
IBar bar = SharedLibrary.CreateBar();
那会简单得多,并且可以将共享库与容器分离。一般来说,这是我能给出的关于依赖注入和可重用库的最佳建议:使用依赖注入模式,而不是容器。请参阅我的文章 DI-Friendly Library 了解更多详情。
如果您仍想在宿主项目(例如 Wep API 项目)中使用 DI 容器,您可以针对该静态工厂方法注册IBar
。
内部 classes
人们想要保留一些 classes internal
是有正当理由的,但我经常看到代码库中 classes 是 internal
的原因并不明显原因。我对数十年 C# 代码的经验是,classes 无缘无故 internal
的情况远远超过有充分理由的情况。
Bar
真的必须是内部的吗?为什么?
从 OP 可以清楚地看出 IBar
是由 Bar
实现的。这 可能 是将问题简化为要点的人工制品(顺便说一句,干得好),但我的印象是 Bar
是 唯一的 class 实现了 IBar
。是这样吗?
如果是这样,Bar
class 必须公开 IBar
定义的方法。这样,class的API就已经是public了,为什么要隐藏class呢?那么,唯一隐藏的是构造函数...
完美风暴
有时,当我提出上述建议时,我会得到这样的回应,这不是问题所在。问题是关于如何改变温莎城堡的生活方式(顺便说一句,you can)。
另一方面,这个问题几乎是完美的(小)风暴,说明了为什么可重用库不应该依赖 DI 容器:
- 该库应该可以在不止一种环境中使用(网络、控制台、桌面等)
- 图书馆依赖温莎城堡
- 接口是 public,但实现 class 不是
这使事情变得复杂 - 因此这里出现了关于 Stack Overflow 的问题。
我最好的建议是保持简单。移除对 Castle Windsor 的依赖将使库的开发和重用更容易,而不是更难。
如果您将大多数库 class 设为 public.
,则使用该库会更容易