首页 > 解决方案 > ServiceStack IoC/DI:在容器中注册类 - 如何注册所有实现特定接口的类

问题描述

我已经开始更仔细地研究 ServiceStack IoC/DI,到目前为止,它工作得非常好,例如,当我使用手动注册方法时:

container.AddScoped<IGeoService, GeoService>();

然后按预期填充我在服务中的属性:

public class MyNiceService : Service
{
    public IGeoService Geo { get; set; }
}

以上工作并Geo正确填充。

第一个想法是:

自动注册所有实现接口的类

最好,我想找到实现特定接口的所有类,并在容器中注册所有这些类,例如:

GetType().Assembly.GetTypes()
        .Where(x => x is IMyCoreService && x.IsClass && !x.IsAbstract)
        .Each(x => container.RegisterAutoWiredType(x));

但这失败了,public GeoService Geo { get; set; }然后为空。

我很感激一些意见,所以我以正确的方式做事:-)

标签: c#dependency-injectionservicestack

解决方案


不是一个真正的答案,而是一个专注于“为什么可以选择同时指定接口和具体类?”的部分答案。.

(反)例子

想象一下,除了您当前的代码之外,您还有这个类:

public class OtherGeoService : IGeoService { ... }

这个 DI 设置:

container.AddScoped<GeoService>();
container.AddScoped<OtherGeoService>();

那么问题就变成了“应该注入哪个类的实例IGeoService?” . 从 DI 框架的角度来看,这个问题没有简单的答案(尽管从您的角度来看可能),这就是为什么在大多数框架中回答这个问题是您的责任。所以通过写

container.AddScoped<IGeoService, GeoService>();

您基本上是在说“如果有人要求IGeoService,请给他们GeoService

同一枚硬币的第二面

另一方面,人们通常在 DI 容器中注册的许多类都实现了各种通用接口,例如IEnumerableIDisposableISerializable. 如果在动作1中有一些精心设计的实现选择算法,那么将很难确定(或至少不明显)将注入什么确切类型的对象。

回顾

我相信这是为什么大多数(如果不是全部)DI 框架需要这种“冗长”的依赖注册的两个主要原因。你只会得到你所要求的东西,而不是“技术上‘符合’你要求的下一个最好的东西”。请注意,该决定不受请求代码的控制,因此不违反IoC范式。

好的,但是为什么?

我知道,对于刚开始进入编程世界的开发人员来说,它对于日常使用来说似乎是过度设计的。我的意思是,问“为什么我要提供不止一个服务实现”是完全合理的。,归结为“如果它们只有一个实现,我为什么还要费心定义所有这些样板接口?” .

在许多(甚至可能是大多数)情况下,您不必这样做。但无论如何都有充分的理由这样做:

  • 它源于 SOLID 编程原则中的“O”。接口仅提供“服务可以做什么”的抽象,而不是“它究竟是如何做到的”的抽象。这样,您的服务就业务逻辑而言是明确分离的。起初这似乎不太可能,但很有可能在某些时候您将需要修改/替换应用程序的某些部分以满足新的需求。
  • 它在编写单元测试时非常方便。如果它是一个接口,您可以轻松地模拟一个依赖项。为了测试目的而模拟具体类要麻烦得多(如果可能的话)。2

1我个人认为不应该有这样的算法,或者至少你应该尽量不依赖它们。这样一来,您几乎可以轻松地切换 DI 框架,而不会产生任何副作用。

2人们普遍认为,单元测试不应影响被测单元的设计,即您不应仅仅为了允许或简化其测试而引入依赖项或公开任何功能。


推荐阅读