Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to "wire up" Dependency Injection in ASP.NET MVC?

I thought the whole reason for Interfaces, Polymorphism, and a pattern like Inversion of Control via Dependency Injection was to avoid tight coupling, separation, modularity, and so on.

Why then do I have to explicitly "wire up" an Interface to a concrete class like in ASP.NET? Won't me having the registry be some sort of coupling? Like,

services.AddTransient<ILogger, DatabaseLogger>();

What if I take a logger, ILogger, and create a file and database class that implement that interface.

In my IoC,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    public interface ILogger
    {
        void logThis(string message);

    }
    public class DatabaseLogger : ILogger
    {
        public void logThis(string message)
        {
            //INSERT INTO table.....
            System.Console.WriteLine("inserted into a databse table");
        }

    }
    public class FileLogger : ILogger
    {
        public void logThis(string message)
        {
            System.Console.WriteLine("logged via file");
        }

    }
    public class DemoClass
    {
        public ILogger myLogger;


        public DemoClass(ILogger myLogger)
        {
            this.myLogger = myLogger;
        }
        public void logThis(string message)
        {
            this.myLogger.logThis(message);
        }

    }
    class Program
    {

        static void Main(string[] args)
        {
            DemoClass myDemo = new DemoClass(new DatabaseLogger());  //Isn't this Dependency Injection?
            myDemo.logThis("this is a message");
            Console.ReadLine();

        }
    }
}

So why do I have to register or "wire up" anything? Isn't this Dependency Injection via the Constructor (Do I have fundamental misunderstanding)? I could put any logger in there that implemented ILogger.

Would I create two of these?

services.AddTransient<ILogger, DatabaseLogger>();
services.AddTransient<ILogger, FileLogger>();
like image 959
johnny Avatar asked Dec 19 '16 21:12

johnny


1 Answers

You would actually abstract it a bit further. In your code, you would create a factory.

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Example Factory Method

So you would in essence have the following:

// Interface:
public interface ILogger : IDisposable
{
     void Log<TEntity>(TEntity entity);
}

// Concrete Implementation:
public class DatabaseLogger : ILogger
{
     public void Log<TEntity>(TEntity entity)
     {
          throw new NotImplementedException();
     }
}

public class TextLogger : ILogger
{
     public void Log<TEntity>(TEntity entity)
     {
          throw new NotImplementedException();
     }
}

With the current way this is defined, you would receive the following IEnumerable<ILogger> when you wired both dependencies to your container. But, to correctly wrap this we would do the following:

public interface ILoggerFactory
{
     ILogger CreateDbLogger();

     ILogger CreateLogger();
}

public class LoggerFactory : ILoggerFactory
{
     public ILogger CreateDbLogger() => new DatabaseLogger();   

     public ILogger CreateLogger() =>   new TextLogger();
}

So when we register our Factory within our dependency injection, we would simply write services.AddTransient<ILoggerFactory, LoggerFactory>();. When you inject the factory, you would simply be able to use:

public class Example
{
     public ILoggerFactory Factory { get; }
     public Example(ILoggerFactory factory)
     {
          Factory = factory;
     }


     // Utilize in a method.
     using(var logger = Factory.CreateDbLogger())
          logger.Log(...);

     // Utilize in a method.
     using(var logger = Factory.CreateLogger())
          logger.Log(...);
}

Now, this can introduce over exposure. But hopefully this clarifies a usage with Dependency Injection which is utilized frequently. You can read a bit more on it by typing "Factory Pattern" or "Factory Method".

like image 195
Greg Avatar answered Sep 22 '22 01:09

Greg