Dependency Injection (DI) is a design pattern to enhance the modularity and maintainability of software systems, it facilitates the management of dependencies between objects. In this blog we will deep dive into Dependency Injection and how you can implement it in C# with clear examples.
What is Dependency Injection?
The primary purpose of Dependency Injection is to decouple the object creation from the object (client) that uses them. It involves supplying an object (a client) with its dependencies (services or objects that it uses) externally instead of creating them directly inside the class.
Let’s take an example to understand how dependency helps modularity and easier testing.
Example for Dependency Injection Design Pattern:
Let’s take an example of designing a logging system that writes input string into a File, we want to make it more flexible so that it can be further extended to log input string in Database, Event or Console etc without making any further changes to the main logic.
Without using Dependency Injection in C#:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System; namespace NoDependencyInjection { internal class Program { static void Main(string[] args) { LoggingService loggingService = new LoggingService(); loggingService.LogMessage("No Dependency Injection"); } } /// <summary> /// Concrete FileLogger /// </summary> public class FileLogger { public void Log(string message) { Console.WriteLine("FileLogger"); Console.WriteLine("Log the message in File : " + message); } } /// <summary> /// Concrete LoggingService Class /// </summary> public class LoggingService { //Tight coupling to FileLogger private FileLogger _logger = new FileLogger(); public void LogMessage(string message) { _logger.Log(message); } } } |
In the above example we haven’t used any dependency injection concept at all, when we run the above code then it generates below output.

- In the above sample code, LoggingService is tightly coupled with the FileLogger.
|
1 2 3 4 5 6 7 8 9 10 |
public class LoggingService { //Tight coupling to FileLogger private FileLogger _logger = new FileLogger(); public void LogMessage(string message) { _logger.Log(message); } } |
- This piece of code is very hard to extend, if we want to implement DBLogging or EventLogging then LoggingService class would need a change to accommodate it.
- Testing this piece code will also be a challenge since its tightly coupled with FileLogging, it will be hard to test for other test scenarios.
Using Dependency Injection in C#:
Let’s rewrite above scenario using Dependency Injection concept.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
using System; namespace DependencyInjection { internal class Program { static void Main(string[] args) { ILogging logger = new FileLogger(); LoggingService loggingService = new LoggingService(logger); loggingService.LogMessage("Dependency Injection through Constructor"); logger = new DbLogger(); loggingService = new LoggingService(logger); loggingService.LogMessage("Dependency Injection through Constructor"); } } /// Interface ILogging public interface ILogging { /// Method to log message void Log(string message); } /// <summary> /// Concrete TextLogger that implmenets the ILogging /// </summary> public class FileLogger : ILogging { public void Log(string message) { Console.WriteLine("FileLogger"); Console.WriteLine("Log the message in File : " + message); } } public class DbLogger : ILogging { public void Log(string message) { Console.WriteLine("DbLogger"); Console.WriteLine("Log the message in Database: " + message); } } /// <summary> /// Concrete LoggingService Class, that injects the Logger class through constructor /// </summary> public class LoggingService { private readonly ILogging _logging; /// Constructor injection public LoggingService(ILogging logging) { _logging = logging; } public void LogMessage(string message) { _logging.Log(message); } } } |
When we run the above code then it generates below output.

- In this example, LoggingService is not tightly coupled, we are able to inject FileLogging and DbLogging through the constructor.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class LoggingService { private readonly ILogging _logging; /// Constructor injection public LoggingService(ILogging logging) { _logging = logging; } public void LogMessage(string message) { _logging.Log(message); } } |
- We can also extend this to inject any new Logging mode, like Event or Console logging from Client without making any modification to the LoggingService class.
Types of Dependency Injection
There are three ways of injecting dependencies:
- Constructor Injection: The dependencies are injected through the class constructor.
- Property Injection: The dependencies are set through the public properties of the class.
- Method Injection: The dependencies are injected through the parameters of the class methods.
Constructor Injection:
Constructor injection is where the required dependencies are injected through the constructor, In the above example constructor LoggingService(ILogging logging) is used to inject the dependencies. Let’s check below code snippet for same.
Example – 1:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/// <summary> /// Concrete LoggingService Class, that injects the Logger class through constructor /// </summary> public class LoggingService { private readonly ILogging _logging; /// Constructor injection public LoggingService(ILogging logging) { _logging = logging; } public void LogMessage(string message) { _logging.Log(message); } } |
Property Injection
Property injection involves public properties used to inject dependencies.
Example – 2:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
using System; namespace DependencyInjection { internal class Program { static void Main(string[] args) { LoggingService loggingService = new LoggingService(); loggingService.LoggingServiceInject = new FileLogger(); loggingService.LogMessage("Dependency Injection through Property Injection."); loggingService = new LoggingService(); loggingService.LoggingServiceInject = new DbLogger(); loggingService.LogMessage("Dependency Injection through Property Injection."); } } /// Interface ILogging public interface ILogging { /// Method to log message void Log(string message); } /// <summary> /// Concrete FileLogger that implmenets the ILogging /// </summary> public class FileLogger : ILogging { public void Log(string message) { Console.WriteLine("FileLogger"); Console.WriteLine("Log the message in File : " + message); } } /// <summary> /// Concrete DbLogger that implmenets the ILogging /// </summary> public class DbLogger : ILogging { public void Log(string message) { Console.WriteLine("DbLogger"); Console.WriteLine("Log the message in Database: " + message); } } /// <summary> /// Concrete LoggingService Class, that injects the Logger class through property /// </summary> public class LoggingService { //Declare a property to inject the dependencies public ILogging LoggingServiceInject { get; set; } public void LogMessage(string message) { LoggingServiceInject.Log(message); } } } |
- In the above code sample, public property LoggingServiceInject { get; set; } is used to inject the dependencies.
|
1 |
public ILogging LoggingServiceInject { get; set; } |
- From the Main method we are accessing the public property and setting the FileLogger and DbLogger dependencies as follows.
|
1 2 3 4 5 6 7 8 9 10 |
static void Main(string[] args) { LoggingService loggingService = new LoggingService(); loggingService.LoggingServiceInject = new FileLogger();//File logging loggingService.LogMessage("Dependency Injection through Property Injection."); loggingService = new LoggingService(); loggingService.LoggingServiceInject = new DbLogger();//Db logging loggingService.LogMessage("Dependency Injection through Property Injection."); } |
Method Injection:
Method injection is where the dependency is provided as a parameter to the method that requires it.
Example – 3:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
using System; namespace DependencyInjection { internal class Program { static void Main(string[] args) { ILogging logger = new FileLogger(); LoggingService loggingService = new LoggingService(); loggingService.LogMessage("Dependency Injection through Method Injection.", logger);//File Logging logger = new DbLogger(); loggingService.LogMessage("Dependency Injection through Method Injection.", logger);//Db logging } } /// Interface ILogging public interface ILogging { /// Method to log message void Log(string message); } /// <summary> /// Concrete FileLogger that implmenets the ILogging /// </summary> public class FileLogger : ILogging { public void Log(string message) { Console.WriteLine("FileLogger"); Console.WriteLine("Log the message in File : " + message); } } /// <summary> /// Concrete DbLogger that implmenets the ILogging /// </summary> public class DbLogger : ILogging { public void Log(string message) { Console.WriteLine("DbLogger"); Console.WriteLine("Log the message in Database: " + message); } } /// <summary> /// Concrete LoggingService Class, that injects the Logger class through property /// </summary> public class LoggingService { //Inject the dependencies through the method parameter public void LogMessage(string message, ILogging _LoggingService) { _LoggingService.Log(message); } } } |
- In the above code sample, method LogMessage(string message, ILogging _LoggingService) is used to inject the dependencies.
|
1 2 3 4 5 6 7 8 |
public class LoggingService { //Inject the dependencies through the method parameter public void LogMessage(string message, ILogging _LoggingService) { _LoggingService.Log(message); } } |
- From the Main method we are accessing the method and injecting the instance of FileLogger and DbLogger dependencies as follows.
|
1 2 3 4 5 6 7 8 9 |
static void Main(string[] args) { ILogging logger = new FileLogger(); LoggingService loggingService = new LoggingService(); loggingService.LogMessage("Dependency Injection through Method", logger);//File Logging logger = new DbLogger(); loggingService.LogMessage("Dependency Injection through Method", logger);//Db logging } |
Benefits of Dependency Injection?
Dependency Injection comes with several benefits:
- Decoupling: This decoupling enhances the flexibility to change dependencies without modifying the classes that use them.
- Ease of Testing: It’s easier to replace implementations with mock objects that simplifies unit testing.
- Code Maintainability: By separating concerns, the code becomes easier to understand and maintain.
- Flexibility and Scalability: You can change the implementation of a dependency without changing the classes that use it.
Conclusion
Dependency Injection in C# provides a clean separation of concerns where components are easily manageable, testable, and maintainable. This helps to create more modular applications and reduce the dependencies among application components.
Thanks for checking this out 🙂 please visit some of the other blogs design pattern.
ASP.NET MVC Pattern as Web Development
