0

What is the benefit of using services.AddSingleton<SomeService, SomeServiceImplementation>() instead of services.AddSingleton<SomeServiceImplementation>() ?

For example i've got an sample Interface

interface ISampleInterface
{
   void DoSomething();
}

And a Sample-Class:

class SampleClass : ISampleInterface
{
  public void DoSomething()
  {
    console.write("hi");
  }
}

No i do services.AddSingleton<SampleClass>()

Why or when to use services.AddSingleton<ISampleInterface, SampleClass>() ?

Thanks for your help! :-)

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
JoeGER94
  • 177
  • 3
  • 14
  • 2
    _"Why or when to use"_ frankly, always with rare exceptions. If you do, then you can inject the interface to other services. And that decouples the dependency. You could then easily swap in another implementation of that interface with one part of one line of code in need for change. It also enables for easier mocking in unit tests. – Fildor Oct 15 '20 at 06:41
  • [Possible duplicate of this question: interfaces - What's the point?](https://stackoverflow.com/questions/6802573/interfaces-whats-the-point) - It's not 100% identical, but this question seems to be asking the same question in a roundabout way. – ProgrammingLlama Oct 15 '20 at 06:50
  • @John, no. Its not the same Question. I know what a Interface is. I just dont see a benefit of the function .AddService(T,S) instead of .AddService(T) – JoeGER94 Oct 15 '20 at 07:02
  • 1
    If you didn't have `.AddService(T,S)`, how would you register an implementation as its interface? – ProgrammingLlama Oct 15 '20 at 07:03
  • https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions.addsingleton?view=dotnet-plat-ext-3.1#Microsoft_Extensions_DependencyInjection_ServiceCollectionServiceExtensions_AddSingleton__2_Microsoft_Extensions_DependencyInjection_IServiceCollection_ Instead of: services.AddSingleton() when SamplesClass:ISampleInterface – JoeGER94 Oct 15 '20 at 07:30

1 Answers1

10

services.AddSingleton<SampleInterface, SampleClass>() allows you to register different implementations for the same interface without modifying the rest of your code.

Change implementations with minimal effort

Suppose you have an ILogger interface and implementation that log eg to the browser's console or send the log entry to different services eg ConsoleLogger, MyServiceLogger or PrometheusLogger. If you registered only the implementation, with eg services.AddSingleton<ConsoleLogger>() you'd have to change all of your classes each time you changed a logger implementation.

You'd have to go to each page and change

@inject ConsoleLogger logger;

to

@inject MyServiceLogger logger;

Forget about specifying the logger at runtime too. You'd have to deploy the application each time you wanted to use a new logging service.

By registering the interface and a specific implementation, all of your classes can keep using ILogger<T> and never know that the implementation has changed.

Implementation selection at runtime

You could even change the implementation at runtime, based on environment variables, configuration, or any other logic you want, eg :

if (app.IsDevelopment)
{
    services.AddSingleton<ILogger,ConsoleLogger>();
}
else
{
    services.AddSingleton<ILogger,MyServiceLogger>();
}

Unit Testing

In unit tests you could use a null logger - in fact the Logging middleware has a NullLogger class just for this reason, in the core Abstractions package.

Or you could wrap your test framework's output methods into an ILogger implementation and use that, without modifying the code. xUnit for example uses the ITestOutputHelper interface for this. You could create an XUnitlogger that forwards calls to this interface:

public class XUnitLogger:ILogger
{
   private readonly ITestOutputHelper _output;
   public XUnitLogger(ITestOutputHelper output)
   {
       _output=output;
   }
   ...
   void Log(...)
   {
       _output.WriteLine(...);
   }
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236