Professional Documents
Culture Documents
Solid 1
Solid 1
NET Core
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
In this article, we’re going to talk about dependency injection, one of the most frequently used design patterns out there.
There are many tutorials about dependency injection, but in this one, we’re going to focus on understanding why the
dependency injection is used and how to use it properly in ASP.NET Core.
The source code for this article can be found on the Dependency Injection in ASP.NET Core Applications repo on GitHub.
Dependency Injection (often called just DI) is a software design pattern that helps us create loosely coupled
applications. It is an implementation of the Inversion of Control (IoC) principle, and Dependency Inversion Principle (D
in SOLID).
The Inversion of Control principle is a design pattern in which the control flow of the application is reversed. We can use it
to our benefit to decouple the parts of our application. This might sound a bit odd, but we’ll see how it works in a moment.
Dependency Injection is just one way of implementing the Inversion of Control principle. Inversion of Control can be
achieved via other means like delegates, events, or other design patterns like factory method for example.
The Inversion of Control also states that objects should not create other objects they depend on. These should be injected via
external service or container.
You can read more about the Dependency Inversion Principle in our SOLID principles series.
In a more graphical way, here’s how the typical workflow looks like:
In a lot of applications, the compile-time dependencies flow in the same direction as the runtime execution. This is wrong
because dependencies should be oriented towards the abstraction and not implementation. Class A is referencing a
method from Class B, and Class B is referencing the method from Class C. This creates a direct dependency graph that
should be avoided at all costs.
Constructor injection is by far the most used type of Dependency Injection. Dependency injection is built in ASP.NET
Core, and we’re encouraged by the framework to use it. Actually, we might even find it hard not since it’s deeply integrated
into the framework.
But let’s put all this theory to practice. We are going to create an example of a control flow without a DI first to see how it
looks like.
We’ll create a simple PlayerGenerator for a potential game. Let’s create a simple model first. We can create a Player class
and some enums to determine the gender and the hair color of that player:
This piece of code creates a random male or female human player character and uses some randomly generated values to
determine character details. It’s a really simple generator that has only one method, and its only purpose is to create new
players.
Now we can go to our GameController (renamed HomeController) and modify the Index() method:
We’re simply creating a new instance of the PlayerGenerator and calling the CreateNewPlayer() method to
create a new player and send it to the view.
The only thing remaining is to change the Index view a bit to show our new player details:
@{
ViewData["Title"] = "Game Page";
}
<div>
<h2>New Player Info</h2>
<p>Name: @Model.Name</p>
<p>Gender: @Model.Gender</p>
<p>Race: @Model.Race</p>
<p>Age: @Model.Age</p>
<p>Hair Color: @Model.HairColor</p>
<p>Strength: @Model.Strength</p>
</div>
Now if we run the application we should get a randomly created player character:
The Problem(s)
Since our controller is directly creating a PlayerGenerator instance, we’ve created several huge problems.
Our controller is no longer just the controller, so we’ve violated the Single Responsibility Principle. Controllers should not
create instances of other classes.
We’ve also produced a tightly coupled source code. Say for example we want to change the PlayerGenerator class
with another one, like BetterPlayerGenerator class which creates players in a completely different way. We would
need to change our controller too:
This is not ideal, and you see how this can propagate through the many different layers of applications easily.
We’ve also made the GameController harder to test. Since the PlayerGenerator is created inside the Index()
method, we can’t mock it. This would make our unit tests unreliable. We aren’t able to test the unit in this case, so the tests
wouldn’t even be the real unit tests. This would make them more like integration tests since we would be testing the
integration of PlayerGenerator and GameController.
Lastly, we’re creating dirty and unreadable code in the long run. Imagine if every dependency in the project is created this
way. We would have a lot of redundant code, and we would have to change an entire application whenever the slightest
change in logic is made.
So what can we do to improve this situation?
First, we need to create an interface IPlayerGenerator. We can do that manually, or we can go to PlayerGenerator
class and press Ctrl + . on the class name and click on the Extract Interface. The latter approach is faster, and it
automatically adds an inheritance to our classes:
Now we need to go to our GameController and use the Dependency Injection to add our dependency:
We’ve added our dependency via constructor injection, and we’ve assigned it to a private readonly field. This is a good
practice, as we’re preventing accidental assignment anywhere else outside the constructor.
Now we can simply call the _playerGenerator.CreateNewPlayer() method in the Index() method.
We get a nice big InvalidOperationException, stating that the service cannot be activated.
We can do that in our Startup class, by adding a single line in the ConfigureServices() method:
We’ve added the PlayerGenerator service to the service collection with AddScoped() method.
In short, scoped lifetime means that the instance is created on every request. For now, let’s leave it like this, but we’ll talk
more about dependency injection lifetimes.
The important thing is that the service registration is necessary and that we can add it as a transient, scoped or singleton
service to our IServiceCollection.
So what happens now if we want to introduce the BetterPlayerGenerator class now in our controller?
That’s it!
Although the BetterPlayerGenerator has a completely different player generation logic, it doesn’t affect our
controller.
That’s a much better way of doing it!
As we’ve already mentioned, there are three different registration lifetimes we can choose from when registering our
services.
These are:
Transient – We can use this for lightweight, stateless services. Each time the service is called, the new instance is
created
Scoped – The instance of the service is created once per request and within that request (scope) it is reused
Singleton – The instance is created only once
Conclusion
In this article, we’ve covered concepts like Dependency Injection, Inversion of Control, and Dependency Inversion
principle. We’ve learned how they are related and how the application control flow can be inverted by using dependency
injection.
We’ve also created a small example to see how we can apply dependency injection in ASP.NET Core application, and
we’ve seen how beneficial this approach can be.
Next time, we’ll talk more about different dependency injection lifecycles.
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
In this article, we are going to discuss an important concept of ASP.NET Core MVC – Dependency Injection.
If you’ve missed some of the previous articles in the series we recommend visiting the series page: ASP.NET Core MVC
Series.
To download this article’s source code visit: Dependency Injection in ASP.NET Core MVC.
Dependency Inversion is one of the core software design principles which we use to create modules that are loosely
coupled. While creating applications, we can achieve this using a technique called Dependency Injection.
Dependency Injection (DI) is the method of injecting the dependent modules into our classes.
We have discussed this in detail in one of our other article Dependency Inversion Principle. We’ve also discussed the
concept of Dependency Injection and how to implement it.
So, in this section, we are going to look at the support for Dependency Injection in an ASP.NET Core MVC application.
ASP.NET Core supports Dependency Injection(DI) between classes and their dependencies. MVC Controllers request
dependencies explicitly via constructors. Furthermore, ASP.NET Core has built-in support for dependency injection, hence
making the application easier to test and maintain.
We add services as a constructor parameter and the runtime resolves the service from the service container. We typically
define services using interfaces.
When we implement a repository pattern in the ASP.NET Core MVC application, we make use of Dependency Injection in
our controllers. We have explained how to implement a simple data repository in the article section Implementing a simple
data repository.
Let’s create an ASP.NET Core MVC application and implement a simple data repository as described in the article.
The next step is to add the service to the service container. We need to do that in the ConfigureServices() method in
the Startup.cs class:
services.AddScoped<IDataRepository<Employee>, EmployeeManager>();
Next, let’s create the EmployeeController with the Index() action method to get the list of all employees:
We can also inject a service directly into an action method without using a constructor injection. We can use the
[FromServices] attribute for that:
TheFromServices attribute specifies that an action parameter should be bound using the request services.
Great. We have learned how to use Dependency Injection to provide dependencies into a Controller.
Injecting services into views is a deviation from the MVC concept. But in some cases, we may have view-specific services
which return the data that we use only for populating the view elements. An example is a service that gives a set of values
that we need to display in a list control. In such scenarios, we can inject services directly into views. View injection can be
useful to populate options in UI elements, such as dropdown lists.
Consider a form to create a book that includes options for specifying a genre. Rendering the data using a standard MVC
approach would require the controller to request data access services for this set of options and then populate a Model or
ViewBag with the set of options to be bound.
An alternative approach is to inject the services directly into a view. This approach minimizes the amount of code required
by the controller as we move the view element construction logic into the view itself.
We can inject a service into a view using the @inject directive. @inject adds a property to our view and initialize it
using DI:
For the next step, let’s define a BooksLookupService for supplying the list data for Genres:
public class BooksLookupService
{
public List<string> GetGenres()
{
return new List<string>()
{
"Fiction",
"Thriller",
"Comedy",
"Autobiography"
};
}
}
Then let’s create a view and inject an instance of BooksLookupService into it:
@model WorkingWithDI.Models.Book
@inject WorkingWithDI.Models.Services.BooksLookupService BooksLookupService
@{
ViewData["Title"] = "Create";
var genres = BooksLookupService.GetGenres();
}
<h1>Create</h1>
<h4>Book</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div>
<label asp-for="Genre" class="control-label"></label>
<select asp-items="@(new SelectList(genres))" class="form-control" ></select>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-label"></label>
<input asp-for="PublishDate" class="form-control" />
<span asp-validation-for="PublishDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
As the last step, we need to register the types that we request through dependency injection in
Startup.ConfigureServices(). If a type is unregistered, it throws a runtime exception.
services.AddTransient<BooksLookupService>();
That’s it. Now let’s run the application and navigate to Create Books form:
We can see that the list of Genres is populated by getting the values from the BooksLookupService.
Excellent, we have learned how to inject a dependency directly into the view.
Conclusion
The principle of Dependency Inversion and how to achieve it using Dependency Injection
Injecting dependencies into Controllers
Injecting dependencies into Views of an ASP.NET Core MVC application
In the next part of this series, we are going to learn about unit testing in ASP.NET Core MVC.
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
The basic idea behind the Dependency Inversion Principle is that we should create the higher-level modules with its
complex logic in such a way to be reusable and unaffected by any change from the lower-level modules in our application.
To achieve this kind of behavior in our apps, we introduce abstraction which decouples higher from lower-level modules.
Having this idea in mind the Dependency Inversion Principle states that
High-level modules should not depend on low-level modules, both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
We are going to make all of this easier to understand with an example and additional explanations.
To download the source code for this project, check out the Dependency Inversion Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
The high-level modules describe those operations in our application that have more abstract nature and contain more
complex logic. These modules orchestrate low-level modules in our application.
The low-level modules contain more specific individual components focusing on details and smaller parts of the application.
These modules are used inside the high-level modules in our app.
What we need to understand when talking about DIP and these modules is that both, the high-level and low-level modules,
depend on abstractions. We can find different opinions about if the DIP inverts dependency between high and low-level
modules or not. Some agree with the first opinion and others prefer the second. But the common ground is that the DIP
creates a decoupled structure between high and low-level modules by introducing abstraction between them.
To continue, we are going to create one low-level class which keeps (in a simplified way) track of our employees:
Furthermore, we are going to create a higher-level class to perform some kind of statistical analysis on our employees:
With this kind of structure in our EmployeeManager class, we can’t make use of the _employess list in the
EmployeeStatistics class, so the obvious solution would be to expose that private list:
Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<
public class EmployeeStatistics
{
private readonly EmployeeManager _empManager;
public EmployeeStatistics(EmployeeManager empManager)
{
_empManager = empManager;
}
public int CountFemaleManagers () =>
_empManager.Employees.Count(emp => emp.Gender == Gender.Female && emp.Position == Position.Manager);
}
Even though this will work just fine, this is not what we consider a good code and it violates the DIP.
How is that?
Well, first of all, our EmployeeStatistics class has a strong relation (coupled) to the EmployeeManager class and we
can’t send any other object in the EmployeeStatistics constructor except the EmployeeManager object. The
second problem is that we are using the public property from the low-level class inside the high-level class. By doing so, our
low-level class can’t change its way of keeping track of employees. If we want to change its behavior to use a dictionary
instead of a list, we need to change the EmployeeStatistics class behavior for sure. And that’s something we want to
avoid if possible.
What we want is to decouple our two classes so the both of them depend on abstraction.
This looks much better now and it’s implemented by DIP rules. Now, our EmployeeStatistics class is not dependent
on the lower-level class and the EmployeeManager class can change its behavior about storing employees as well.
Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<
Finally, we can check the result by modifying Program.cs class:
class Program
{
static void Main(string[] args)
{
var empManager = new EmployeeManager();
empManager.AddEmployee(new Employee { Name = "Leen", Gender = Gender.Female, Position = Position.Manager });
empManager.AddEmployee(new Employee { Name = "Mike", Gender = Gender.Male, Position = Position.Administrator
});
var stats = new EmployeeStatistics(empManager);
Console.WriteLine($"Number of female managers in our company is: {stats.CountFemaleManagers()}");
}
}
Reducing the number of dependencies among modules is an important part of the process of creating an application. This is
something that we get if we implement DIP correctly. Our classes are not tightly coupled with the lower-tier objects and we
can easily reuse the logic from the high-tier modules.
So, the main reason why DIP is so important is the modularity and reusability of the application modules.
It is also important to mention that changing already implemented modules is risky. By depending on abstraction and not on
a concrete implementation, we can reduce that risk by not having to change high-level modules in our project.
Finally, DIP when applied correctly gives us the flexibility and stability at the level of the entire architecture of our
application. Our application will be able to evolve more securely and become stable and robust.
Conclusion
So to sum up, the Dependency Inversion Principle is the last part of the SOLID principles which introduce an abstraction
between high and low-level components inside our project to remove dependencies between them.
If someone asks: „Should I put an effort to implement the DIP into my code?“, our answer would be: „Yes you should“.
Loosely coupled code and reusable components should be our goal and responsibility when developing software
applications.
SOLID Principles in C#
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
SOLID principles represent a set of principles that, if implemented properly should improve our code significantly.
As with any other principle in life, we can misuse and overuse every SOLID principle to the point of being
counterproductive. Instead of getting an understandable, maintainable, and flexible code, we could end up with the code
that’s in worse shape than without SOLID.
So, careful consideration and implementing these SOLID principles only where needed is the key to a clean codebase.
The source code for this series of articles can be found in this GitHub repo. You can switch to different branches to get to
the different parts of the series.
We hope these articles will help you discern when and how to implement these principles the right way.
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
While developing a project, we strive to write maintainable and readable code (besides the working part �). To accomplish
this, each and every class should do its own task and do it well.
Yes, it is quite important for a class to have no more than one task. If it does, our code becomes harder to maintain, due to
the fact that it is responsible for the execution of several different tasks and thus being more likely to change in the future.
This is completely opposite of what the Single Responsibility Principle (SRP) states.
The Single Responsibility Principle states that our classes should have only one reason to change or in other words, it
should have only one responsibility.
Simple as that.
In this article, we are going to show you, through an example, how to create a code that abides by SRP rules. We will start
with the code which isn’t SRP compliant and then refactor it to be in accordance with SRP. To finish our example, we will
add a bit of reusability to our code, because we don’t want to repeat ourselves while coding.
To download the source code for this project, check out the Single Responsibility Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
Imagine if we have a task to create a work report feature that, once created, can be saved to a file and perhaps uploaded to
the cloud or used for some other purpose.
So we are going to start with a simple model class:
The next step is creating a WorkReport class which will handle all the required features for our project:
In this class, we are keeping track of our work report entries by adding and removing them to/from a list. Furthermore, we
are just overriding ToString() method to adjust it to our requirements.
Because we have our WorkReport class, it is quite fine to add our additional features to it, like saving to a file:
We can add even more features in this class, like the Load or UploadToCloud methods because they are all related to our
WorkReport, but, just because we can doesn’t mean we have to do it.
The first reason to change this class is if we want to modify the way we keep track of our entries. But if we want to save a
file in a different way, that is entirely a new reason to change our class. And imagine what this class would look like if we
added additional functionalities to it. We would have so many unrelated code parts in a single class.
The first thing we need to do is to separate the part of our code that is unlike others. In our case, that is obviously the
SaveToFile method, so we are going to move it to another class which is more appropriate:
Having done this, we have separated the concerns of each class thus making them more readable and maintainable as well.
As a result, if we want to change how we save a file, we only have one reason to do that and one place to do it, which is the
FileSaver class.
class Program
{
static void Main(string[] args)
{
var report = new WorkReport();
report.AddEntry(new WorkReportEntry { ProjectCode = "123Ds", ProjectName = "Project1", SpentHours = 5 });
report.AddEntry(new WorkReportEntry { ProjectCode = "987Fc", ProjectName = "Project2", SpentHours = 3 });
Console.WriteLine(report.ToString());
var saver = new FileSaver();
saver.SaveToFile(@"Reports", "WorkReport.txt", report);
}
}
Making the Code Even Better
If we look at our SaveToFile method, we see that it does its job which is saving a work report to a file, but can it do it
even better? This method is tightly coupled with the WorkReport class, but what if we want to create a Scheduler
class that keeps track of its scheduled tasks? We would still like to save it to a file.
Well, in that case, we are going to create some changes to our code:
After these modifications, we are going to have the same result, but now if we have a task to implement Scheduler, it is
going to be quite simple to implement that:
After we execute this code, we will have our file saved in a required location on a defined schedule.
We are going to leave it at that. Now every class we have is responsible for one thing and one thing only.
Our code has improved in several ways by implementing SRP. The first one being that it has become less complex. Because
we are trying to accomplish only one task in our class, they have become free of clutter and simple to read. As we reduce
code complexity, our code becomes readable and therefore maintainable.
As we could see from our example, if our class does its job well, we can reuse its logic in a project. Furthermore, with such
a code, testing becomes easier as well.
When we implement SRP in our code, our methods become highly related (coherent). It means that different methods are
joined to do one thing and to do it well.
Finally, our classes are less dependent on each other (decoupled) which is one of the most important things to achieve while
working on a project.
There is no strict rule which states what is that „one reason to change“ in our class. Everyone interprets this subjectively or
rather how he/she feels it should be implemented. The rules are not clear to where we should draw the line, so we can
potentially find different „right ways“ to implement the same feature.
But still, the bottom line is that no matter what someone thinks about what reason to change is, we should all strive to write
readable and maintainable code thus implementing Single Responsibility Principle in our own way.
One of the potential downsides is that in projects that are already written, is difficult to implement SRP. We don’t say that it
is not possible, just that it will take longer and take more resources as well.
Implementing SRP leads to writing compact classes with tiny methods as well. And on a first look, this looks great. But
having one big class decomposed into a lot of small classes creates an organizational risk. If those classes are not organized
and grouped well, it could actually increase the amount of work needed to change a system and to understand it which is
opposite of what we wanted to achieve in the first place.
Conclusion
Implementing the Single Responsibility Principle should be always in our mind while writing code. It can be tough to write
the code according to SRP right from scratch, but you can write your code iteratively and return to the parts that need
attention later. Refactoring is a common practice and nobody writes code perfectly right away. So refactor towards the SRP
later if you are not sure which class does what at that moment. It will help not only you but the other developers that need to
maintain your code later as well.
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
The Open Closed Principle (OCP) is the SOLID principle which states that the software entities (classes or methods) should
be open for extension but closed for modification.
Basically, we should strive to write a code that doesn’t require modification every time a customer changes its request.
Providing such a solution where we can extend the behavior of a class (with that additional customer’s request) and not
modify that class, should be our goal most of the time.
In this article, we will show you how to write the code by following the Open Closed Principle with two different examples.
Initially, none of the examples will obey the OCP rules, but right after the initial development, we are going to refactor the
code using the OCP.
To download the source code for this project, check out the Open Closed Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
Let’s imagine that we have a task where we need to calculate the total cost of all the developer salaries in a single company.
Of course, we are going to make this example simple and focus on the required topic.
Once we’ve created our model, we can transition to the salary calculation feature:
Now, all we have to do is to provide some data for this class and we are going to have our total costs calculated:
Of course, to satisfy this requirement, we are going to modify our CalculateTotalSalaries method like this:
Why is that?
Mainly, because we had to modify our existing class behavior which worked perfectly. Another thing is that if our boss
comes again and ask us to modify calculation for the junior dev’s as well, we would have to change our class again. This is
totally against of what OCP stands for.
It is obvious that we need to change something in our solution, so, let’s do it.
To create a code that abides by the Open Closed Principle, we are going to create an abstract class first:
As a continuation, we are going to create two classes which will inherit from the BaseSalaryCalculator class. Because it is
obvious that our calculation depends on the developer’s level, we are going to create our new classes in that manner:
This looks so much better because we won’t have to change any of our current classes if our boss comes with another
request about the intern payment calculation or any other as well.
All we have to do now is to add another class with its own calculation logic. So basically, our SalaryCalculator class
is now closed for modification and opened for an extension, which is exactly what OCP states.
class Program
{
static void Main(string[] args)
{
var devCalculations = new List<BaseSalaryCalculator>
{
new SeniorDevSalaryCalculator(new DeveloperReport {Id = 1, Name = "Dev1", Level = "Senior developer", HourlyRate =
30.5, WorkingHours = 160 }),
new JuniorDevSalaryCalculator(new DeveloperReport {Id = 2, Name = "Dev2", Level = "Junior developer", HourlyRate =
20, WorkingHours = 150 }),
new SeniorDevSalaryCalculator(new DeveloperReport {Id = 3, Name = "Dev3", Level = "Senior developer", HourlyRate =
30.5, WorkingHours = 180 })
};
var calculator = new SalaryCalculator(devCalculations);
Console.WriteLine($"Sum of all the developer salaries is {calculator.CalculateTotalSalaries()} dollars");
}
}
Let’s imagine for a moment that we have a task to write an application which gives us all the required information about
computer monitors in our shop, based on different criteria. We will introduce only two criteria here, the type of monitors
and the screen size. So let’s start with that:
Now, we need to implement our filtering functionality. For example, we want to filter by the monitor types:
class Program
{
static void Main(string[] args)
{
var monitors = new List<ComputerMonitor>
{
new ComputerMonitor { Name = "Samsung S345", Screen = Screen.CurvedScreen, Type = MonitorType.OLED },
new ComputerMonitor { Name = "Philips P532", Screen = Screen.WideScreen, Type = MonitorType.LCD },
new ComputerMonitor { Name = "LG L888", Screen = Screen.WideScreen, Type = MonitorType.LED },
new ComputerMonitor { Name = "Samsung S999", Screen = Screen.WideScreen, Type = MonitorType.OLED },
new ComputerMonitor { Name = "Dell D2J47", Screen = Screen.CurvedScreen, Type = MonitorType.LCD }
};
var filter = new MonitorFilter();
var lcdMonitors = filter.FilterByType(monitors, MonitorType.LCD);
Console.WriteLine("All LCD monitors");
foreach (var monitor in lcdMonitors)
{
Console.WriteLine($"Name: {monitor.Name}, Type: {monitor.Type}, Screen: {monitor.Screen}");
}
}
}
This is going to work just fine. But, after a couple of days, we receive a request that our customers want to have the filter by
Screen functionality as well.
So, in order to avoid existing class modification, let’s try another approach.
With the ISpecification interface, we can determine whether or not our criterion is satisfied and we can send it to the
Filter method from the IFilter interface.
To continue on, we are going to create a separate class for the monitor type specification:
After this modification, all we have to do is to write a class that implements IFilter interface. But because we already have
the MonitorFilter class, we are just going to modify it:
Right now, we are perfectly able to extend our MonitorFilter class without any further modification. So, if now we
have to implement the filter by screen feature, for example only widescreen monitors, we can do it with a new class:
Excellent.
With this project structure, we can even extend our filtering criterion to, for example, only OLED and widescreen monitors.
All we have to do is to create another specification class.
By implementing the OCP we are lowering the chance of producing bugs in our project.
For example, if we have a fully working and already tested class in production, by extending it instead of changing it, we
would definitely have a lesser impact on the rest of the system.
Therefore, we introduce another class to extend the behavior of the main class thus avoid the existing functionality
modification that other classes may rely upon.
Another benefit is that we only have to test and deploy the new features, which wouldn’t be the case if we had to change
existing functionality. Furthermore, if we decide that we don’t need this feature anymore (sometime in the future), all we
have to do is to revert just newly implemented change and that’s it.
Conclusion
We’ve seen how the OCP can help us create better and more maintainable code. But, as with everything else, we should be
cautious when implementing this principle.
Sometimes it’s just impossible to extend our class and all we are left to do is to modify existing functionality. We shouldn’t
be afraid to do it, it is quite normal, but at least we should try to make those changes as discrete as they can be.
So, we should develop our applications with the OCP in mind and we should strive to write extendable code as much as we
can because it leads to the maintainable, scalable and testable codebase.
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
The Liskov Substitution Principle (LSP) states that child class objects should be able to replace parent class objects without
compromising application integrity. What this means essentially, is that we should put an effort to create such derived class
objects which can replace objects of the base class without modifying its behavior. If we don’t, our application might end up
being broken.
To make things clear, we are going to use a simple „Sum Calculator“ example, which will help us to understand how to
implement the LSP better.
To download the source code for this project, check out the Liskov Substitution Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
Initial Project
In this example, we are going to have an array of numbers and a base functionality to sum all the numbers from that array.
But let’s say we need to sum just even or just odd numbers.
Now if we test this solution, whether we calculate the sum of all the numbers or the sum of just even numbers, we are going
to get the correct result for sure:
class Program
{
static void Main(string[] args)
{
var numbers = new int[] { 5, 7, 9, 8, 1, 6, 4 };
SumCalculator sum = new SumCalculator(numbers);
Console.WriteLine($"The sum of all the numbers: {sum.Calculate()}");
Console.WriteLine();
EvenNumbersSumCalculator evenSum = new EvenNumbersSumCalculator(numbers);
Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}");
}
}
As we can see, this is working just fine. But what is wrong with this solution then?
As we can see, we are not getting the expected result because our variable evenSum is of type SumCalculator which is
a higher order class (a base class). This means that the Count method from the SumCalculator will be executed. So,
this is not right, obviously, because our child class is not behaving as a substitute for the parent class.
Luckily, the solution is quite simple. All we have to do is to implement small modifications to both of our classes:
As a result, when we start our solution, everything works as expected and the sum of even numbers is 18 again.
So, let’s explain this behavior. If we have a child object reference stored in a parent object variable and call the
Calculate method, the compiler will use the Calculate method of the parent class. But right now because the
Calculate method is defined as „virtual“ and is overridden in the child class, that method in the child class will be used
instead.
Still, the behavior of our derived class has changed and it can’t replace the base class. So we need to upgrade this solution
by introducing the Calculator abstract class:
class Program
{
static void Main(string[] args)
{
var numbers = new int[] { 5, 7, 9, 8, 1, 6, 4 };
Calculator sum = new SumCalculator(numbers);
Console.WriteLine($"The sum of all the numbers: {sum.Calculate()}");
Console.WriteLine();
Calculator evenSum = new EvenNumbersSumCalculator(numbers);
Console.WriteLine($"The sum of all the even numbers: {evenSum.Calculate()}");
}
}
We will again have the same result, 40 for all the numbers and 18 for the even numbers. But now, we can see that we can
store any subclass reference into a base class variable and the behavior won’t change which is the goal of LSP.
By implementing the LSP, we are keeping our functionality intact and still having our subclasses act as a substitute to a base
class.
Also, we encourage the code reusability by implementing the LCP and having better project maintenance as well.
Conclusion
We can see that implementing the LSP is not that complicated but just the opposite. Most of us probably already
implemented this principle many times in our code without knowing its name because in the object-oriented world
Polymorphism is quite a big thing.
The Interface Segregation Principle states that no client should be forced to depend on methods it does not use. So, this is
the basic definition which we can read in many different articles, but what does this really mean?
Let’s imagine that we are starting a new feature on our project. We start with some code and from that code, an interface
emerges with the required declarations. Soon after, the customer decides that they want another feature that is similar to the
previous one and we decide to implement the same interface in another class. But now, as a consequence, we don’t need all
the methods from that interface, just some of them. Of course, we have to implement all the methods, which we shouldn’t
have to, and that’s the problem and where the ISP helps us a lot.
Basically, the ISP states that we should reduce code objects down to the smallest required implementation thus creating
interfaces with only required declarations. As a result, an interface that has a lot of different declarations should be split up
into smaller interfaces.
To download the source code for this project, check out the Interface Segregation Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
Starting Example
There are vehicles that we can drive, and there are those we can fly with. But there are cars we can drive and fly (yes those
are on sale). So, we want to create a code structure which supports all the actions for a single vehicle, and we are going to
start with an interface:
Now if we want to develop a behavior for a multifunctional car, this interface is going to be perfect for us:
This is working great. Our interface covers all the required actions.
But now, we want to implement the Car class and the Airplane class as well:
So, in order to fix this problem, we are going to do some refactoring to our code and write it in accordance to ISP.
As a result, our classes can implement only the methods they need:
We can even use a higher level interface if we want in a situation where a single class implements more than one interface:
Once we have our higher level interface, we can implement it in different ways. The first one is to implement the required
methods:
Or if we already have implemented the Car class and the Airplane class, we can use them inside our class by using the
decorator pattern:
We can see from the example above, that smaller interface is a lot easier to implement due to not having to implement
methods that our class doesn’t need.
Of course, due to the simplicity of our example, we can make a single interface with a single method inside it. But in real-
world projects, we often come up with an interface with multiple methods, which is perfectly normal as long as those
methods are highly related to each other. Therefore, we make sure that our class needs all these actions to complete its task.
Another benefit is that the Interface Segregation Principle increases the readability and maintainability of our code. We are
reducing our class implementation only to required actions without any additional or unnecessary code.
Conclusion
To sum this article up, we should put an effort into creating smaller interfaces while developing our project. Yes, we may
end up with a lot of different interfaces in the end but from our point of view, this is much better than having a few large
interfaces that can force us to implement non-required methods in our classes.
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
The basic idea behind the Dependency Inversion Principle is that we should create the higher-level modules with its
complex logic in such a way to be reusable and unaffected by any change from the lower-level modules in our application.
To achieve this kind of behavior in our apps, we introduce abstraction which decouples higher from lower-level modules.
Having this idea in mind the Dependency Inversion Principle states that
High-level modules should not depend on low-level modules, both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
We are going to make all of this easier to understand with an example and additional explanations.
To download the source code for this project, check out the Dependency Inversion Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
What are the High-Level and Low-Level Modules
The high-level modules describe those operations in our application that have more abstract nature and contain more
complex logic. These modules orchestrate low-level modules in our application.
The low-level modules contain more specific individual components focusing on details and smaller parts of the application.
These modules are used inside the high-level modules in our app.
What we need to understand when talking about DIP and these modules is that both, the high-level and low-level modules,
depend on abstractions. We can find different opinions about if the DIP inverts dependency between high and low-level
modules or not. Some agree with the first opinion and others prefer the second. But the common ground is that the DIP
creates a decoupled structure between high and low-level modules by introducing abstraction between them.
To continue, we are going to create one low-level class which keeps (in a simplified way) track of our employees:
Furthermore, we are going to create a higher-level class to perform some kind of statistical analysis on our employees:
With this kind of structure in our EmployeeManager class, we can’t make use of the _employess list in the
EmployeeStatistics class, so the obvious solution would be to expose that private list:
Even though this will work just fine, this is not what we consider a good code and it violates the DIP.
How is that?
Well, first of all, our EmployeeStatistics class has a strong relation (coupled) to the EmployeeManager class and we
can’t send any other object in the EmployeeStatistics constructor except the EmployeeManager object. The
second problem is that we are using the public property from the low-level class inside the high-level class. By doing so, our
low-level class can’t change its way of keeping track of employees. If we want to change its behavior to use a dictionary
instead of a list, we need to change the EmployeeStatistics class behavior for sure. And that’s something we want to
avoid if possible.
What we want is to decouple our two classes so the both of them depend on abstraction.
So, the first thing we need to do is to create the IEmployeeSearchable interface:
This looks much better now and it’s implemented by DIP rules. Now, our EmployeeStatistics class is not dependent
on the lower-level class and the EmployeeManager class can change its behavior about storing employees as well.
class Program
{
static void Main(string[] args)
{
var empManager = new EmployeeManager();
empManager.AddEmployee(new Employee { Name = "Leen", Gender = Gender.Female, Position = Position.Manager });
empManager.AddEmployee(new Employee { Name = "Mike", Gender = Gender.Male, Position = Position.Administrator
});
var stats = new EmployeeStatistics(empManager);
Console.WriteLine($"Number of female managers in our company is: {stats.CountFemaleManagers()}");
}
}
Benefits of Implementing the Dependency Inversion Principle
Reducing the number of dependencies among modules is an important part of the process of creating an application. This is
something that we get if we implement DIP correctly. Our classes are not tightly coupled with the lower-tier objects and we
can easily reuse the logic from the high-tier modules.
So, the main reason why DIP is so important is the modularity and reusability of the application modules.
It is also important to mention that changing already implemented modules is risky. By depending on abstraction and not on
a concrete implementation, we can reduce that risk by not having to change high-level modules in our project.
Finally, DIP when applied correctly gives us the flexibility and stability at the level of the entire architecture of our
application. Our application will be able to evolve more securely and become stable and robust.
Conclusion
So to sum up, the Dependency Inversion Principle is the last part of the SOLID principles which introduce an abstraction
between high and low-level components inside our project to remove dependencies between them.
If someone asks: „Should I put an effort to implement the DIP into my code?“, our answer would be: „Yes you should“.
Loosely coupled code and reusable components should be our goal and responsibility when developing software
applications.
SOLID Principles in C# – Dependency Inversion Principle
Want to build great APIs? Or become even better at it? Check our Ultimate ASP.NET Core Web API program and learn
how to create a full production-ready ASP.NET Core API using only the latest .NET technologies. Bonus materials
(Security book, Docker book, and other bonus files) are included in the Premium package!
The basic idea behind the Dependency Inversion Principle is that we should create the higher-level modules with its
complex logic in such a way to be reusable and unaffected by any change from the lower-level modules in our application.
To achieve this kind of behavior in our apps, we introduce abstraction which decouples higher from lower-level modules.
Having this idea in mind the Dependency Inversion Principle states that
High-level modules should not depend on low-level modules, both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
We are going to make all of this easier to understand with an example and additional explanations.
To download the source code for this project, check out the Dependency Inversion Principle Project Source Code.
To read about other SOLID principles, check out our SOLID Principles page.
The low-level modules contain more specific individual components focusing on details and smaller parts of the application.
These modules are used inside the high-level modules in our app.
What we need to understand when talking about DIP and these modules is that both, the high-level and low-level modules,
depend on abstractions. We can find different opinions about if the DIP inverts dependency between high and low-level
modules or not. Some agree with the first opinion and others prefer the second. But the common ground is that the DIP
creates a decoupled structure between high and low-level modules by introducing abstraction between them.
To continue, we are going to create one low-level class which keeps (in a simplified way) track of our employees:
Furthermore, we are going to create a higher-level class to perform some kind of statistical analysis on our employees:
With this kind of structure in our EmployeeManager class, we can’t make use of the _employess list in the
EmployeeStatistics class, so the obvious solution would be to expose that private list:
Even though this will work just fine, this is not what we consider a good code and it violates the DIP.
How is that?
Well, first of all, our EmployeeStatistics class has a strong relation (coupled) to the EmployeeManager class and we
can’t send any other object in the EmployeeStatistics constructor except the EmployeeManager object. The
second problem is that we are using the public property from the low-level class inside the high-level class. By doing so, our
low-level class can’t change its way of keeping track of employees. If we want to change its behavior to use a dictionary
instead of a list, we need to change the EmployeeStatistics class behavior for sure. And that’s something we want to
avoid if possible.
What we want is to decouple our two classes so the both of them depend on abstraction.
This looks much better now and it’s implemented by DIP rules. Now, our EmployeeStatistics class is not dependent
on the lower-level class and the EmployeeManager class can change its behavior about storing employees as well.
Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<
class Program
{
static void Main(string[] args)
{
var empManager = new EmployeeManager();
empManager.AddEmployee(new Employee { Name = "Leen", Gender = Gender.Female, Position = Position.Manager });
empManager.AddEmployee(new Employee { Name = "Mike", Gender = Gender.Male, Position = Position.Administrator
});
var stats = new EmployeeStatistics(empManager);
Console.WriteLine($"Number of female managers in our company is: {stats.CountFemaleManagers()}");
}
}
Benefits of Implementing the Dependency Inversion Principle
Reducing the number of dependencies among modules is an important part of the process of creating an application. This is
something that we get if we implement DIP correctly. Our classes are not tightly coupled with the lower-tier objects and we
can easily reuse the logic from the high-tier modules.
So, the main reason why DIP is so important is the modularity and reusability of the application modules.
It is also important to mention that changing already implemented modules is risky. By depending on abstraction and not on
a concrete implementation, we can reduce that risk by not having to change high-level modules in our project.
Finally, DIP when applied correctly gives us the flexibility and stability at the level of the entire architecture of our
application. Our application will be able to evolve more securely and become stable and robust.
Conclusion
So to sum up, the Dependency Inversion Principle is the last part of the SOLID principles which introduce an abstraction
between high and low-level components inside our project to remove dependencies between them.
If someone asks: „Should I put an effort to implement the DIP into my code?“, our answer would be: „Yes you should“.
Loosely coupled code and reusable components should be our goal and responsibility when developing software
applications.