DEV Community

Sam Ferree
Sam Ferree

Posted on

Explicit Registration in ASP.NET Core DI

Sometimes you'll want a little more control over how your objects are composed than the IServiceCollection API gives you. You can always fall back to explicit registration.

The AddTransient/Scoped/Singleton methods all have an overload that takes a Func as a factory method to use when an instance is needed.

When is this useful? let's say you have the following objects

public interface IPing
{
  void Ping(string msg);
}

public class ConsolePing : IPing
{
  public void Ping(string msg) =>
    Console.WriteLine(msg);
}

public class LogPing : IPing
{
  public void Ping(string msg) =>
    Log.Info(msg);
}

So you have to different implementations of IPing, then for different services you wanted to inject different implementations, but still only take a dependency on the interface for test mocking.

public class ServiceA
{
  private readonly IPing _pinger;
  public ServiceA(IPing pinger) => _pinger = pinger;
}

public class ServiceB
{
  private readonly IPing _pinger;
  public ServiceB(IPing pinger) => _pinger = pinger;
}

How do you register ServiceA and ServiceB so that A gets the ConsolePinger, and B gets the LogPinger? Use the overload registration that takes in a factory method.

The factory method needs to return an instance of the service you are registering, but it takes as a parameter a service provider that can be used to obtain any dependencies.

public void ConfigureService(IServiceCollection services)
{
  services.AddTransient<ConsolePing>();
  services.AddTransient<LogPing>();
  services.AddTransient<ServiceA>(provider =>
  {
    var consolePinger = provider.GetRequiredService<ConsolePing>();
    return new ServiceA(consolePinger);
  });

  // if you can also omit the generic parameter
  services.AddTransient(provider =>
  {
    var logPinger = provider.GetRequiredService<LogPing>();
    return new ServiceB(logPinger);
  });
}

Discussion (0)