How to Use Dependency Injection with EF Core In-Memory Database and Invoking Dependencies
In the last article in this series, I will show you two straightforward things: first, how to use the EntityFramework Core in memory and how to invoke an injected dependency without using the class constructor!
But why wouldn't you inject the dependency on the constructor, as I showed in the previous articles? Well, sometimes, it is necessary to use alternative mechanisms to simplify the development and have access to the objects!
EntityFramework Core
For many years I wrote about EF, but as there was a long delay in the development of EF Core, I ended up using other ORMs in my projects. But now EF Core is fascinating, and I went back to using it on a massive project!
So, I decided to complement this series by showing an extremely useful feature of EF Core, which is the in-memory database.
But why so useful? Imagine that you develop using a "development" database or even local on your machine, which is perfectly normal. Still, over time this database can get "dirty," or with "bad" data, so we have to clean and start all over again.
Then think that you can keep an entire database in memory, performing the same operations that you would do in the typical database, but without saving anything anywhere except in the memory.
This feature is very valuable for unit tests, and I really hope you are writing tests!
For this example we are going to create an ASP.NET Core WebAPI project.
Creating the EF Core Context
The first thing we will do is create a class (table) and the context.
We will have a simple Client
class :
Now let's get to the Context
:
Our context has nothing much, except a SeedData()
method that I am using to fill the Client
table in memory.
Remember that I am using a memory database, so to have data, I need to fill this database when I start the context!
Configuring Startup.cs
Now let's configure the services in the Startup class:
See that we are adding a context with the option UseInMemoryDataBase()
To use this method, you will need the following Entity packages:
Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.InMemory
The InMemory
package allows you to have a database in memory. See that you can exchange UseInMemoryDataBase()
for UseSqlServer()
or any other database provider, and everything is still working!
When I write unit tests, I create an InMemory()
context, and in the real application, I use a database! That makes my job much easier!
So we are injecting an Entity Framework context into our project through AddDbContext()
, and also two other classes: IHttpContextAccessor
and IsendEmail
(IEnvioEmail
), using Singleton and Scoped, which I showed in the previous article.
IHttpContextAccessor
allows us to access the ASP.NET Core Http Context anywhere it is injected, and IEnvioEmail
is an example class that I created to simulate the sending of email.
See here the interface IEnvioEmail
and the class EnviarEmail
:
This class "simulates" sending an email, I imagine you will implement a real class for this!
Working with Injection in the Controller
Now that we have our environment set up, let's create a controller to work with this data. We will create ClientController.cs
, which will have two actions: Get()
to bring all customers and Email()
to "simulate" the sending of email.
Let's go to the code:
Okay, we have a lot of things going on here, and I will explain:
In the controller constructor we are receiving some objects by injection:
ILogger logger
= ASP.NET Core logAplicacaoContext db
= Entity Framework contextIHttpContextAccessor httpContextAccessor
= Http Context of the application
All are assigned to variables within the controller. So let's go to the methods that interest us.
The Get()
method returns all database customers, which in our case are only in memory!
The other method, Email()
, is the one that we are going to show the "invocation" of a dependency without the constructor.
Understanding the scenario
That is more common than you think! In our project, we need to send an email, and the email class is in dependency injection (we set it up in Startup.cs
), but we don't put it in the controller constructor because it's a little-used method, and in this case, it doesn't justify it hypothetically! Or it is simply injected into another class, which is even more common! In any case, we do not have this class directly available.
So, let's "materialize" the object, looking for it in the dependency injector, see how simple it is:
var email = _httpContextAccessor.HttpContext.RequestServices.GetService<IEnvioEmail> ();
Let's understand:
_httpContextAccessor
is the application's Http context, which has HttpContext
and Request
, which is the request for the page.
We use RequestServices.GetServices<IEnvioEmail>()
which basically "asks" for the dependency injector to "give" us the object corresponding to the IEnvioEmail
interface.
That is very cool because you are "injecting" an object by hand. You are taking an object that is already created and bringing it to the variable email
.
And now, let use the email!
Running the application, we will have the following result:
Now calling the email:
Conclusion
The dependency injection mechanism allows us to simplify development greatly! But use with care, as everything in excess is harmful!
Special thanks to my friend Rafael Almeida, with whom I "argue" frequently about EntityFramework!!! These discussions have already generated improvements in EF Core, such as WithNoLock()
.
As always, the example code is on my Github.
Hugs, and see you soon!