Dependency Injection - Simple Example C#

Suppose we have logging and message sending classes in our sample application as follows.


DBLogger class that can be used for database logging


public class DBLogger
{
    public void WriteLog(string message)
    {
        Console.WriteLine("DBLogger : " + message);
    }   
}

MailSender class that can be used for mail sending


public class MailSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine("MailSender : " + message);
    }
}

We can develop a class named Processor, which contains the main flow of our sample application as follows.


public class Processor
{
    public void Process()
    {
        DBLogger logger = new DBLogger();
        logger.WriteLog("Hello World");

        MailSender sender = new MailSender();
        sender.SendMessage("Hello World");
    }
}

Finally, we will run our application as a simple console application.


class Program
{
    static void Main(string[] args)
    {
        Processor processor = new Processor();
        processor.Process();

        Console.ReadKey();
    }
}

If we talk about the scenario we simulated briefly, our class named processor is responsible for managing the main flow of the application. This class is the business layer. In the application flow, firstly, DBLogger class logs to the database. Then mail is sent using the MailSender class. After running the application, we will get a screenshot as follows.


dependencyinjection_1.PNG

So far, we developed our application assuming that all requests are fixed in a classical way. Let's assume that we have given our application to another company and that this company uses the file system for logging and does not want to receive messages via mail and prefers the SMS system.


First of all, what we will do is to develop components that will log into the file and send messages via SMS.


public class FileLogger
{
    public void WriteLog(string message)
    {
        Console.WriteLine("FileLogger : " + message);
    }
}

public class SMSSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine("SMSSender : " + message);
    }
}

We have completed our developments. Now it's time to add these parts into your workflow.


public class Processor
{
    public void Process()
    {
        //DBLogger logger = new DBLogger();
        FileLogger logger = new FileLogger();
        logger.WriteLog("Hello World");

        //MailSender sender = new MailSender();
        SMSSender sender = new SMSSender();
        sender.SendMessage("Hello World");
    }
}

We are commenting on the part that logs to the database and the part that sends the mail in our workflow. We added the newly developed parts to the application, so we met the needs.


If another company wants file logging and mail messaging, are we going to comment on the required parts and build our application again!


Something is going wrong!


Dependency Injection


tightly coupled When we look at the application we have done above, we see that our application is tightly coupled to a group of classes.


So what we can do?


At this point, the first improvement that comes to mind is to manage these processes through an interface.


public interface IMessageSender
{
    void SendMessage(string message);
}

public interface ILogger
{
    void WriteLog(string message);
}

public class DBLogger : ILogger
{
    public void WriteLog(string message)
    {
        Console.WriteLine("DBLogger : " + message);
    }   
}

public class MailSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine("MailSender : " + message);
    }
}

public class FileLogger : ILogger
{
    public void WriteLog(string message)
    {
        Console.WriteLine("FileLogger : " + message);
    }
}

public class SMSSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine("SMSSender : " + message);
    }
}

In the our class named Processor where our workflow is located, we can dynamically change the flow of our application as we want.


public class Processor
{
    private ILogger logger;
    private IMessageSender sender;

    public Processor(ILogger _logger, IMessageSender _sender)
    {
        logger = _logger;
        sender = _sender;
    }

    public void Process()
    {
        logger.WriteLog("Hello World");
        sender.SendMessage("Hello World");
    }
}

From the config file, we get the parameters to create the logging and message sending objects.


Add System.Configuration in the Reference folder


public static class Class1
{
    public static IMessageSender CreateMessageSender()
    {
        string temp = System.Configuration.ConfigurationManager.AppSettings["messageType"].ToString();
        switch(temp)
        {
            case "SMS":
                return new SMSSender();
            case "Mail":
                return new MailSender();
            default:
                return null;
        }
    }

    public static ILogger CreateLogger()
    {
        string temp = System.Configuration.ConfigurationManager.AppSettings["logType"].ToString();
        switch (temp)
        {
            case "DB":
                return new DBLogger();
            case "File":
                return new FileLogger();
            default:
                return null;
        }
    }
}

Now it is time to create the logging and message sending objects and run the flow dynamically.


class Program
{
    static void Main(string[] args)
    {

        Processor processor = new Processor(Class1.CreateLogger(), Class1.CreateMessageSender());
        processor.Process();

        Console.ReadKey();
    }
}

App.config


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="messageType" value="SMS"/>
    <add key="logType" value="File"/>
  </appSettings>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
</configuration>

With Dependency Injection, we can change the flows that the application will run dynamically by injecting externally.


dependencyinjection_2.PNG