寻找将温莎生活方式带入图书馆的方式

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.

,则使用该库会更容易