Dependency Injection – Containers

Just as I promised I would do another part about containers so I will keep my word πŸ™‚ Here is the next part πŸ™‚ Today with very useful tools, although some think that unnecessary (but this is a topic for another article), but we will dispel these doubts in this article πŸ™‚ Ladies and gentlemen, get to know the containers πŸ™‚


Admission

In the previous article we parted in a lot of stress πŸ™‚ But it was the intended effect, how tests can make the design more difficult … NOT TRUE !!! This results only through ignorance. We had three issues to solve.

  • Big constructors – if we had 10 dependencies in the GameServer class, and in each dependency, there would be a lot of other dependencies that would be completely unreadable, we would have to write everything from the finger, I wouldn’t like to do it …
  • We also wanted to remove the new word even from the client level which also makes it easier for us to keep the project, we know of the last SOLID rule the less new the better πŸ™‚
  • And the last point connected with the second point, the most important one. We want the project to be compiled even if we do not have an interface implemented. And for the project to be compiled, we have to delete new word. We want to write tests and not run the project, but why write tests if they will not even start? Tough matter…

All the above problems are solved by containers, but first let’s explain what containers are.

With dependencies in classes it is like with matzo-dolls, they are like bint in bint πŸ™‚ , you can write these relationships with your finger, BUT it’s damn boring, if the class has dependencies and if in these dependencies there are further dependencies.

You can imagine a site that uses controllers, gets data from the database, has to handle a lot of different requests and so on … I do not recommend writing it all with from finger … there are better ways.

In short, a container is just a library with ready-made functions to implement dependency injection, so that life can be easier πŸ™‚

I highly recommend using containers to solve many problems, what you will see immediately πŸ™‚

And what container will we use? They is a lot of of them (the most important ones will be described in the next article), but today we will write our own container to better understand the ideas of containers.

In the real world I strongly advise you not to write your own container for large projects, but we will do it as part of learning, our container will do the simplest things required only for registering components.

And what are the main tasks of the container? There are two πŸ™‚ registration of the class, or its interface, so that the container knows about it, that such a class is at all in the project and creating an instance of this class.


Container testing

Let’s see what the simplest container looks like, as we know unit tests, you can say that project documentation, let’s see the tests first πŸ™‚

I have created some classes without logic for these tests, but as these classes are in tests, these classes do not have to have any logic πŸ™‚

As you can see in the tests, first we check whether this container registers classes as it should. Now let’s see the tests, which also check when the container does not register classes, if something is missing we throw away the right exception πŸ™‚

v

These tests that throw exceptions have these exceptions not very aptly described and do not fit too much to describe the problem and not only the correctness of names is a problem, when we move to the container production code we will a little improve these tests πŸ™‚ But it will be at the point “Additions to the container” at the end of the article.


Container … What can you do for me?

So what are the containers for? Five minutes into this or that will not change anything, it’s better not to complicate your life …

This is not entirely true. πŸ™‚ Everything will be clear soon πŸ™‚ Let’s see what the production code of our container looks like. Just like that πŸ™‚

As you can see, nothing extraordinary here. We can only register the same class or class with an interface and create instances of registered classes this container. As you can deduce from the code, the Reslove () method creates us instances of the class that we previously registered in the container.

Naturally, she realizes that one can pick on to a billion things. It’s true that our container does not have many things that have normal containers, but as I wrote earlier this container is only for demonstration purposes πŸ™‚

Okay, how everything is understood, let’s see what gives us the possession of such a container. What was our goal? To run tests without the implementation of the ICharacterRace interface, make the constructor more readable and to get rid of the new even from the client level.

So let’s see the changes that lead us to this goal. Only the GameServer and WebServer classes have changed.

Let’s see the GameServer class first

The only change is that instead of the constructor we have something like this:

You could say that the ResolveInterfaces() method is our constructor, but as you can see, it is much more readable πŸ™‚

And in tests for the GameServer class, we register the dependencies as in the Main() function the same way πŸ™‚

And what changes are in the WebServer class? We added one method and changed the main function Main()

I added the Shutdown() method only for a demonstration that if we used containers in a large project, we would have to clean our container so that it would not have all instances of classes that it created that would terribly memory eaten up.

And what happened in Main()? We register the interfaces of our classes we use, create an instance of the GameServer class and call the ResloveInterfaces() method. Of course, we still do not have an implemented ICharacterRace interface, so when we run it will explode and only the ash will be πŸ™‚ But if it compiles what we care about? We can continue to implement the tests and we do not want to run the project.

It is worth mentioning that there is also the rule three calls patterns that is, we should use the container only in three places at its start, at the end and when transferring control to the application (usually it is creating objects classes needed to run the application) , the idea is rather simple, some also call this RRR, Register Resolve Release.

I highly recommend reading also a short article by Mark Seemann about RRR, in other words, three class patterns https://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasepattern/


Additions to the container

As part of the addition to our container, we will add the registration of objects as singletons, other containers such as Autofac or Unity also have this functionality, I also added additional tests and improved the ones that we spoke earlier πŸ™‚

Let’s start with the tests. I divided the tests into classes so that it would be known after the class name what they test and for readability.

So that in each class, in turn, do not create our container object each time, I added something like this at the beginning of the tests:

The BeforeEach() method is performed before each test and AfterEach() as the name says after each test.

In general, we have four classes with tests. Let’s start with the first ContainerTest

In short, in this class we check whether all classes, dependencies are register as it should.

One more thing to these tests is needed as well as to previous tests we have sample classes, some empty ones with some random dependencies. We use them for all of these tests. Here they are πŸ™‚ Great πŸ™‚

During this time, let’s move to the next test class. ContainerResolveTest πŸ™‚

Here we also check if everything registers as it should, but we mainly check if the class types match and check if the objects are registered correctly using generics types πŸ™‚

Let’s see the singleton testing class. There is only one test, the class is called the SingletonContainerRegisterTest and the test looks like this:

As you can see, we also check if singleton registering is done properly.

Now let’s see the class throwing exceptions, so the same as earlier in the article, what I promised we would improve. It’s that these exceptions like something goes wrong to throw it out properly.

Now it looks better, but we had to create this TypeNotRegisteredException class in a container to make it work with sense.

That’s it, when it comes to testing, let’s finally go to the container class, let’s see what has changed there.

We only changed the Resolve() method and added object registration as a singleton.

That’s almost the whole code when it comes to registering singletons. Well, we just have to add one more line at the top of the class:

We need to have where to store singleton objects about the Func delegate may be a separate article, in short it is a delegate in which you can specify the parameters of input and output types to start with this article is cool πŸ™‚
https://www.tutorialsteacher.com/csharp/csharp-func-delegate

Now let’s see the Resolve() method.

In the first if-we check whether the passed class type is already passed as singleton, if so, we return this class as singleton, if not, check if the passed class is registered at all, if not, we throw an exception and pass it to the TypeNotRegisteredException class, which I will show.

Next, if the class is registered, we check if the registered class has any dependencies, if so, we create instances of these dependencies. The classes throwing an exception, they look like this:

And that’s probably all when it comes to changes.

As part of the tests, I created a singleton object and added the CountNumberOfCalling() method to the object being created, which counts calls to this method in the Main () function. That’s how it looks

CountNumberOfCalling() method

If this is singleton, the second time in the message it should display 2.

As you can see, this is also happening πŸ™‚

Phew good is probably all we just added some tests and registering singletons and yet it is a lot of code πŸ™‚ Of course, the link with the whole code to github in the summary πŸ™‚


Summary

In the next article will also be about containers, but already these professional I will describe more thoroughly what they can do and what they have, what our container does not have, see you πŸ™‚

Link to github with the whole code from this article: https://github.com/Slaw145/DependencyInjectionContainers

This content also you can find on medium: https://medium.com/@sawomirkowalski/dependency-injection-containers-c4c1b7dd5e89

As a standard, I remind you about the newsletter, which I send notifications about new entries and additional information about the IT world in general.

And NECESSERILY join the DevmanCommunity community on fb, part of the community is in one place 

– site on fb: Devman.pl-Slawomir Kowalski

– group on fb: DevmanCommunity

Ask, comment underneath at the end of the post, share it, rate it, whatever you want πŸ™‚

 
If that post was useful for you share it with your friends :)

Post a comment

avatar
  Subscribe  
Notify about