Autofac:注入整个 AggregateService 而不是具体服务的性能

Autofac: Performance of Injecting whole AggregateService Instead of Concrete Service

假设我有一个控制器接受在 Autofac 的容器中注册的 AggregatedService DI:

public interface IMyAggregateService
{
  IFirstService FirstService { get; }
  ISecondService SecondService { get; }
  IThirdService ThirdService { get; }
  IFourthService FourthService { get; }
}

public class SomeController
{
  private readonly IMyAggregateService _aggregateService;

  public SomeController(IMyAggregateService aggregateService)
  {
    _aggregateService = aggregateService;
  }
}

一段时间后,我创建了另一个控制器:SomeAnotherController,它需要在 AggregateService 中注册的服务之一(例如 IFirstService)。

什么是更好的解决方案:

  1. IMyAggregateService 注入 SomeAnotherController 并使用 FirstService
  2. 的实例

  1. 在 autofac 中将 FirstService 注册为单独的类型,并将此服务注入 SomeAnotherController

关于解决方案 1) 我知道有一个为聚合服务创建的动态代理,但是当我们在 AggregatedService 的 属性 上调用方法时实际解析的类型,或者在将 IAgregateService 注入 constuctor 时完成的类型?

就性能而言,1 或 2 是更好的解决方案吗?

严格的性能角度来看这将取决于几件事,例如:

  • 聚合服务的生命周期范围是多少(单例、按请求等)?
  • 各项服务的生命周期范围是多少?
  • 创建个人服务有多“昂贵”?

...等等。没有具体的答案。例如,如果 everything 被注册为单例,则两种方式的性能都相同——所有单例都将被创建、缓存并从缓存中查找。另一方面,如果聚合服务是每个依赖实例,它会在您每次请求时重新创建实例,这本质上比使用缓存实例更昂贵。

但是,从模式的角度来看,您应该只在控制器中注入您需要的。通过在第二个控制器中注入整个聚合服务,从 API 的角度来看,你实际上是在说你 必须在聚合服务中拥有所有四个东西 即使你只使用第一个。这让您有些困惑 API,尤其是涉及到重构和单元测试时。它几乎就像服务定位,只是“要定位的服务列表中的几个强类型条目”。

你最好的选择是将你需要的东西注入第二个控制器。很有可能无论如何它都会有更好的性能,但更重要的是你将拥有更好的 API 从长远来看将更易于使用和重构。这是双赢的。