Architecture and Dependency Injection in .NET Framework
April 14, 2020
One way to achieve a good separation of concerns in our code is by use of Dependency Injection (DI). Reusability and readability of our code becomes more and more important when dealing with larger projects, and starting with good project architecture is a great first step. It can help with writing code that is predictable and maintainable for the rest of your team and lead to fewer headaches in the long run.
DI using interface also makes setting up testing and mocking a lot easier, as we can inject a separate instance that implements the expected interface instead of our actual code.
ASP.NET core seems to follow an 'inject everything' paradigm using it's Startup.cs
file for dependency resolution, which makes setting up DI in a project nice and easy. Framework however requires a bit more setup.
Architecture
For our API we will be using the following folder structure when setting out our files:
- Models
- Controllers
- Interfaces
- Services
When building a Web API, I usually divide up the code into sets of operations that apply to a model (separation of concerns). This is usually as simple as CRUD operations on a table in a database. At a high level, we have our model that defines the table, a service that performs the data operations, the interface that describes the service layer, and the controller that gives our client access to these operations. We would then have a set of these files per model that we need to operate on.
I quite like this architecture as it's nice and simple and can be used as a basis for a readable and maintainable project.
Burgers
As a simple example we will be implementing a controller that retrieves a list of Burgers from a table in a database.
The above files set up a rudimentary endpoint that returns a list of burgers from the database (example using Entity Framework).
The issue we are seeing here is that each of our services and db contexts need to be instantiated each time they are called. This means we would need to new up a service to be defined for each separate method it's involved in. This causes a lot of bloat and repetition in the code (DRY), which makes readability and maintainability an issue.
Dependency Injection
To help with our issue, we turn to DI. In this example we will be able to refactor to inject our DBContext
and BurgerService
classes for consumption when our service and controller are instantiated.
With the above changes, we now have reusable and maintainable injection of our services that can be consumed easily by our controller and service methods. However, if we run this code we will be greeted with an error as our API currently doesn't know how to resolve our dependencies. Unlike dotnet core, where resolution is enabled by default, in Framework, we need to configure a dependency container to assist with resolving our dependencies.
Unity
Unity is an open source dependency injection container originally developed by Microsoft. By adding and configuring it in our project, it will automatically tell our application how to resolve our dependencies.
To do so, we need to tell the application to load Unity, and then provide it with a list of dependencies to resolve.
Install Unity through NuGet and then configure as follows:
Create a new file (in App_Start works well):
Now when we run our Web API, the correct constructors will be resolved, and we will be able to CRUD all the burgers we want.