Search code examples
.netasp.net-mvcdependency-injectionautofac

Autofac: Performance of Injecting whole AggregateService Instead of Concrete Service


Supposing I have a controller that is accepting AggregatedService DI registered in container in Autofac:

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;
  }
}

After some time i have created another controler: SomeAnotherController which requires one of the services that was registered in AggregateService (IFirstService as an example).

What would be better solution:

  1. Inject IMyAggregateService to SomeAnotherController and use instance of FirstService

or

  1. Register FirstService as a separate Type in autofac and inject just this service to SomeAnotherController

Regarding solution 1) I know that there is a dynamic proxy created for agregated services but is the type actually resolved when we invode a method on a property of AgregatedService or it is done when injecting IAgregateService to constuctor?

1 or 2 would be better solution in terms of performance?


Solution

  • From a strictly performance perspective it's going to depend on several things, like:

    • What's the lifetime scope of the aggregate service (singleton, per-request, etc.)?
    • What's the lifetime scope of the individual services?
    • How "expensive" is it to create the individual services?

    ...and so on. There's not a concrete answer. For example, if everything was registered as singletons, the perf will be the same either way - all the singletons will be created, cached, and looked up from the cache. On the other hand, if the aggregate service is instance-per-dependency, it will re-create the instance every time you ask for one, which is inherently more expensive than using a cached instance.

    However, from a patterns perspective you should only inject what you need in the controller. By injecting the whole aggregate service in the second controller, you're effectively saying, from an API perspective, that you must have all four things in the aggregate service even though you only use the first one. That leaves you with a somewhat confusing API, especially when it comes to refactoring and unit tests. It's almost like service location, just with "several strongly-typed entries in the list of services to locate."

    Your best bet is to just inject what you need into the second controller. The strong likelihood is that it'll be better perf anyway, but more importantly you'll have a better API that will be easier to use and refactor in the long term. It's win-win.