Learn how to use dependency injections and interfaces in .NET
It is quite common to have an object that depends on another object to do its function, especially in an object-oriented environment like .NET. For instance, your constructor depends on your data context object. However, it can cause problems to always have to build dependencies first and then the objects that depend on them next. Also what if two classes need to access different versions of the dependency for example we might want to use the data context class both in a testing class and in the actual project but when using it in the testing context, we might want to set it up in such a way that we don't actually affect the database we could do this by adjusting the controller class but it would be easier if we could make that class initially more flexible.
The solution to these problems is dependency injections where rather than creating a dependency that a class depends on we give the class an interface to tell it what type of object to expect and then create a service that allows us to create dependencies as needed and inject them into the class.
Open the simple hello world project you made last week. Within MyWebApi (or whatever you named the project) add a models directory and create a Book.cs file within it that looks like this
We now need to install Microsoft EntityFrameworkCore to help set up a quick in-memory database. Like so
Then we make a data folder and inside make a BookContext.cs file that will look like so
This is moving towards a simple in-memory database containing two books with randomly generated IDs. First, we will need to update our Program.cs file to use them.
Start by installing the following package
Then update the Program.cs file to look like what follows.
This should give our BookContext the power to create in-memory databases and ensure they are created on app build.
Now let's update our controller to be a book controller that returns a list of books.
Give it a quick swagger test, and then let's look at a part of this code in more detail.
The constructor for this class (line 4) requires BookContext to function. This means these two objects are now tightly linked and we can't easily change one without changing the other.
To allow us more flexibility we are going to create something called an interface that we can feed in instead. An interface lets the constructor know what to expect but will not be as absolute as actually giving it the class.
The first step to do that is to go into our data directory and make a new file called IBookContext that looks like this.
This creates an interface and tells the class passed this that at run time it can expect something that contains a DbSet of books rather than the specific class passed to it before. Now we just need to tell all the other parts of our program to look for the interface rather than the object.
Let's start with the BookContext file itself.
If we make this change the BookContext can now inherit from both DbContext and IBookContext.
Now we want to update our Program.cs file so that when the context is built it knows it can take anything that matches the interface requirements
Finally, we do what we wanted to all along which is to make our book controller independent from the BookContext class by putting our interface in the constructor.
Besides making your work easier by having these two things looser it will also give you the ability to if you created an xUnit testing environment (like the one in the challenge repo), write code like this that substitutes fake data for the book context.
Note this part which would not be possible if the Book controller relied on a BookContext