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
)。
什么是更好的解决方案:
- 将
IMyAggregateService
注入 SomeAnotherController
并使用 FirstService 的实例
或
- 在 autofac 中将 FirstService 注册为单独的类型,并将此服务注入
SomeAnotherController
关于解决方案 1) 我知道有一个为聚合服务创建的动态代理,但是当我们在 AggregatedService 的 属性 上调用方法时实际解析的类型,或者在将 IAgregateService 注入 constuctor 时完成的类型?
就性能而言,1 或 2 是更好的解决方案吗?
从严格的性能角度来看这将取决于几件事,例如:
- 聚合服务的生命周期范围是多少(单例、按请求等)?
- 各项服务的生命周期范围是多少?
- 创建个人服务有多“昂贵”?
...等等。没有具体的答案。例如,如果 everything 被注册为单例,则两种方式的性能都相同——所有单例都将被创建、缓存并从缓存中查找。另一方面,如果聚合服务是每个依赖实例,它会在您每次请求时重新创建实例,这本质上比使用缓存实例更昂贵。
但是,从模式的角度来看,您应该只在控制器中注入您需要的。通过在第二个控制器中注入整个聚合服务,从 API 的角度来看,你实际上是在说你 必须在聚合服务中拥有所有四个东西 即使你只使用第一个。这让您有些困惑 API,尤其是涉及到重构和单元测试时。它几乎就像服务定位,只是“要定位的服务列表中的几个强类型条目”。
你最好的选择是将你需要的东西注入第二个控制器。很有可能无论如何它都会有更好的性能,但更重要的是你将拥有更好的 API 从长远来看将更易于使用和重构。这是双赢的。
假设我有一个控制器接受在 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
)。
什么是更好的解决方案:
- 将
IMyAggregateService
注入SomeAnotherController
并使用 FirstService 的实例
或
- 在 autofac 中将 FirstService 注册为单独的类型,并将此服务注入
SomeAnotherController
关于解决方案 1) 我知道有一个为聚合服务创建的动态代理,但是当我们在 AggregatedService 的 属性 上调用方法时实际解析的类型,或者在将 IAgregateService 注入 constuctor 时完成的类型?
就性能而言,1 或 2 是更好的解决方案吗?
从严格的性能角度来看这将取决于几件事,例如:
- 聚合服务的生命周期范围是多少(单例、按请求等)?
- 各项服务的生命周期范围是多少?
- 创建个人服务有多“昂贵”?
...等等。没有具体的答案。例如,如果 everything 被注册为单例,则两种方式的性能都相同——所有单例都将被创建、缓存并从缓存中查找。另一方面,如果聚合服务是每个依赖实例,它会在您每次请求时重新创建实例,这本质上比使用缓存实例更昂贵。
但是,从模式的角度来看,您应该只在控制器中注入您需要的。通过在第二个控制器中注入整个聚合服务,从 API 的角度来看,你实际上是在说你 必须在聚合服务中拥有所有四个东西 即使你只使用第一个。这让您有些困惑 API,尤其是涉及到重构和单元测试时。它几乎就像服务定位,只是“要定位的服务列表中的几个强类型条目”。
你最好的选择是将你需要的东西注入第二个控制器。很有可能无论如何它都会有更好的性能,但更重要的是你将拥有更好的 API 从长远来看将更易于使用和重构。这是双赢的。