asp.net-coreasp.net-core-mvc.net-corecoreclr

Do we need interfaces for dependency injection?


I have an ASP.NET Core application. The application has few helper classes that does some work. Each class has different signature method. I see lot of .net core examples online that create interface for each class and then register types with DI framework. For example

 public interface IStorage
 {
    Task Download(string file);
 }

 public class Storage
 {
    public Task Download(string file)
    {
    }
 }

 public interface IOcr
 {
     Task Process();
 }

 public class Ocr:IOcr
 {
    public Task Process()
    {

    }
 }

Basically for each interface there is only one class. Then i register these types with DI as

 services.AddScoped<IStorage, Storage>();
 services.AddScoped<IOcr,Ocr>();

But i can register type without having interfaces so interfaces here look redundant. eg

 services.AddScoped<Storage>();
 services.AddScoped<Ocr>();

So do i really need interfaces?


Solution

  • No, you don't need interfaces for dependency injection. But dependency injection is much more useful with them!

    As you noticed, you can register concrete types with the service collection and ASP.NET Core will inject them into your classes without problems. The benefit you get by injecting them over simply creating instances with new Storage() is service lifetime management (transient vs. scoped vs. singleton).

    That's useful, but only part of the power of using DI. As @DavidG pointed out, the big reason why interfaces are so often paired with DI is because of testing. Making your consumer classes depend on interfaces (abstractions) instead of other concrete classes makes them much easier to test.

    For example, you could create a MockStorage that implements IStorage for use during testing, and your consumer class shouldn't be able to tell the difference. Or, you can use a mocking framework to easily create a mocked IStorage on the fly. Doing the same thing with concrete classes is much harder. Interfaces make it easy to replace implementations without changing the abstraction.