Showing posts with label DI. Show all posts
Showing posts with label DI. Show all posts

Oct 16, 2015

Dependency Injection (DI) vs. Inversion of Control (IOC)

The main goal of Inversion of control and Dependency Injection is to remove dependencies of an application. This makes the system more decoupled and maintainable.
First let’s try to understand IOC (Inversion of control). If you go back to old computer programming days, program flow used to run in its own control. For instance let’s consider a simple chat application flow as shown in the below flow diagram.
  1. End user sends chat message.
  2. Application waits for the message from the other end.
  3. If no message is found it goes to Step 2 or else moves to Step 4.
  4. Displays the message.
  5. User continues with his work ahead.
Now if you analyze the program flow closely, it’s sequential. The program is in control of himself. Inversion of control means the program delegates control to someone else who will drive the flow. For instance if we make the chat application event based then the flow of the program will go something as below:-
  1. End user sends chat message.
  2. User continues with his work ahead.
  3. Application listens to events. If a message arrives event is activated and message is received and displayed.
If you see the program flow it’s not sequential, its event based. So now the control is inverted. So rather than the internal program controlling the flow, events drive the program flow. Event flow approach is more flexible as their no direct invocation which leads to more flexibility.

IOC (Inversion of control) is a general parent term while DI (Dependency injection) is a subset of IOC. IOC is a concept where the flow of application is inverted. So for example rather than the caller calling the method.

 

Inversion of control :- It’s a generic term and implemented in several ways (events, delegates etc).
Dependency injection :- DI is a subtype of IOC and is implemented by constructor injection, setter injection or method injection.

Jun 25, 2015

Constructor Dependency Injection Pattern Implementation in C#

Introduction

Dependency Injection (DI) is a pattern where objects are not responsible for creating their own dependencies. Dependency injection is a way to remove hard-coded dependencies among objects, making it easier to replace an object's dependencies, either for testing (using mock objects in unit test) or to change run-time behavior.
Before understanding Dependency Injection, you should be familiar with the two concepts of Object Oriented Programming, one is tight coupling and another is loose coupling, so let's see each one by one.

Tight Coupling: When a class is dependent on a concrete dependency, it is said to be tightly coupled to that class. A tightly coupled object is dependent on another object; that means changing one object in a tightly coupled application often requires changes to a number of other objects. It is not difficult when an application is small but in an enterprise level application, it is too difficult to make the changes.
Loose Coupling: It means two objects are independent and an object can use another object without being dependent on it. It is a design goal that seeks to reduce the inter- dependencies among components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Now in short, Dependency Injection is a pattern that makes objects loosely coupled instead of tightly coupled. In this tip, you will be the first to introduce tight coupling and thereafter you will introduce loose coupling using the Constructor Dependency Injection Pattern. So let's see that.

Using the Code

To understand the concept of Dependency Injection, create an example that is the Error Log Management. The Error Log Management example describes how to create an error log for the application. There are two types of log management, one is using a text file and the other uses an event viewer.
First of all, create an interface IErrorLogger that has one method to write the error log. This interface will be inherited by other log classes.
using System;  
namespace DependencyInjection  
{  
    public interface IErrorLogger  
    {  
        void LogMessage(Exception ex);  
    }  
}
Now create a class, FileLogger class, that inherits the IErrorLogger interface. This class writes an error log message to a text file.
using System;  
using System.Configuration;  
using System.IO; 
  
namespace DependencyInjection  
{  
    public class FileLogger : IErrorLogger  
    {  
        public void LogMessage(Exception ex)  
        {  
            string folderPath = ConfigurationManager.AppSettings["ErrorFolder"];  
            if (!(Directory.Exists(folderPath)))  
            {  
                Directory.CreateDirectory(folderPath);  
            }  
            FileStream objFileStrome = new FileStream(folderPath + "errlog.txt", FileMode.Append, FileAccess.Write);  
            StreamWriter objStreamWriter = new StreamWriter(objFileStrome);  
            objStreamWriter.Write("Message: " + ex.Message);  
            objStreamWriter.Write("StackTrace: " + ex.StackTrace);  
            objStreamWriter.Write("Date/Time: " + DateTime.Now.ToString());  
            objStreamWriter.Write("============================================");  
            objStreamWriter.Close();  
            objFileStrome.Close();  
        }  
    }
Now create an EventViewerLogger class that inherits the IErrorLogger interface. This class writes an error log message in the event viewer.
using System;  
using System.Configuration;  
using System.Diagnostics;  
  
namespace DependencyInjection  
{  
    public class EventViewerLogger : IErrorLogger  
    {  
        public void LogMessage(Exception ex)  
        {  
            EventLog objEventLog = new EventLog();  
            string sourceName = ConfigurationManager.AppSettings["App"];  
            string logName = ConfigurationManager.AppSettings["LogName"];  
            if (!(EventLog.SourceExists(sourceName)))  
            {  
                EventLog.CreateEventSource(sourceName, logName);  
            }  
            objEventLog.Source = sourceName;  
            string message = String.Format("Message: {0} \n StackTrace: 
            {1} \n Date/Time: {2} ", ex.Message, ex.StackTrace, DateTime.Now.ToString());  
            objEventLog.WriteEntry(message, EventLogEntryType.Error);  
        }  
    }  
}
Now we create another class to understand the concept of tight coupling. The Operation class has an interface, an IErrorLogger instance, created by the FileLogger class. In other words, the Operation class object is tightly coupled with the FileLogger class.
using System;  
  
namespace DependencyInjection  
{  
   public class Operation  
    {  
       IErrorLogger logger = new FileLogger();  
       public void Division()  
       {  
           try  
           {  
               int firstNumber = 15, secondNumber = 0, result;  
               result = firstNumber / secondNumber;  
               Console.WriteLine("Result is :{0}", result);  
           }  
           catch (DivideByZeroException ex)  
           {  
               logger.LogMessage(ex);  
           }  
       }  
    }  
} 
The code above works, but it's not the best design because it is tightly coupled with FileLogger. When you want to use another IErrorLogger implementation class, then you need to change it. That is not depending on the Open Closed Principle of Object Oriented Programming.
Now call your class method in your application startup class and you get a log in the text file so your start up class code is below:
using System;  
namespace DependencyInjection  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Operation objOperation = new Operation();  
            objOperation.Division();  
            Console.Read();  
        }  
    }  
} 
Let's run the application. You will get an exception in the log file such as in Figure 1.1.
Error Log in txt File
Figure 1.1 Error Log in txt File
To solve this problem, you should use constructor dependency injection in which an IErrorLogger is injected into the object.

Constructor Dependency Injection Pattern

This is the most commonly used Dependency Pattern in Object Oriented Programming. The Constructor Injection uses a parameter to inject dependencies so there is normally one parameterized constructor always. So in this constructor dependency, the object has no default constructor and you need to pass specified values at the time of creation to initiate the object.
You can say that your design is loosely coupled with the use of constructor dependency injection.
Now create a class OperationEvent. That class has a parameter constructor. This constructor will be used to inject dependencies in the object. Let's see the following code.
using System;  
  
namespace DependencyInjection  
{  
    public class OperationEvent  
    {  
        IErrorLogger logger;  
  
        public OperationEvent(IErrorLogger logger)  
        {  
            this.logger = logger;  
        }  
  
        public void Division()  
        {  
            try  
            {  
                int firstNumber = 15, secondNumber = 0, result;  
                result = firstNumber / secondNumber;  
                Console.WriteLine("Result is :{0}", result);  
            }  
            catch (DivideByZeroException ex)  
            {  
                logger.LogMessage(ex);  
            }  
        }  
    }  
} 
By the preceding, you have noticed that an OperationEvent object is neither dependent on an FileLogger object nor an EventViewerLogger object so you can inject either FileLogger dependencies or EventViwerLogger dependencies at run time. Let's see the startup class in which we inject EventViewerLogger dependencies in an OperationEvent object using constructor dependency injection.
using System;  
  
namespace DependencyInjection  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            OperationEvent objOperationEvent = new OperationEvent(new EventViewerLogger());  
            objOperationEvent.Division();  
            Console.Read();  
        }  
    }  
}
Let's run the application and you get the results as in Figure 1.2 .
Log Errors in Event Viewer.
Figure 1.2 Log Errors in Event Viewer.
Source :Code Project..!!