Dependency Injection — professional containers

I’m after a long break :) prepares for a presentation about CQRS, which will be recorded in Gdansk, I will post it on the blog :) And all the time work on the startup is boiling :) But let’s get to the point :) as promised in the previous article, next will be about these professional containers, it’s worth to use them because the possibilities are big :) We’re going :)

Admission

The question “Why not use my own container?” I answered in the previous article about containers in the introduction.

Well not quite the best … 🙂

In this article I will describe a few containers of their advantages, disadvantages and basic functionalities, with such a selection of IoC containers, writing your own container is simply pointless …

And what should doing such a container? This is what I will describe on specific examples of containers :)


Pros and cons of containers

The main advantage of containers is definitely that they facilitate the creation of class instances with prior registration, so that the container knows about their existence.

The next advantage is that they make it easier to write tests (which is very important to me), as I showed in the previous article 🙂

And the main disadvantage is that the containers at the beginning are difficult to understand, unfortunately … Some people think that containers are unnecessary because they only make it difficult to understand the application. However, with time, when you get to the point, it will be easy 🙂 I will try to make it easy to read this article 🙂


Ninject

The first in the queue is Ninject written by Nate Kohari.

So what should a self-respecting container have?

For sure, it should be able to download all classes of a given interface to be able to display it later using IEnumerable we will do it using Ninject 🙂

The first thing we should do is to delete everything that was associated with our container from the previous article and in the Main() function in the WebServer class do something like:

IKernel kernel = new StandardKernel(new Bindings());
gameServer = kernel.Get();
IEnumerable characters = kernel.GetAll();
foreach (ICharacter character in characters)
{
Console.WriteLine(character.GetType().Name + " has " + character.Strength + " strength");
}

Inside the Ninject, so in the kernel, we create an instance of the Bindings class in which all classes registered by us are present.

Next, we download all instances of the ICharacter interface to the IEnumerable collection and display them in the foreach loop.

It is also known that in the ResolveInterfaces() method, which serves as our constructor in the GameServer class, we must get the classes that we previously registered.

public void ResolveInterfaces(IKernel kernel)
{
loginvalidator = kernel.Get();
passwordvalidator = kernel.Get();
characterskillpoints = kernel.Get();
       // characterrace = kernel.Get();
}

And what are the changes in the tests? There is very little change. Only the TestSetup() method in the GameServerClassTest class is changed.

[SetUp]
public void TestSetup()
{
characterRaceMock = new Mock();
characterMock = new Mock();
       character = characterMock.Object;
       IKernel kernel = new StandardKernel(new Bindings());
gameserver = kernel.Get();
       gameserver.ResolveInterfaces(kernel);
}

We pass this merits, that is how classes are registered. Let’s see the Bindings class

namespace DIContainers.ContainerClasses
{
public class Bindings : NinjectModule
{
public override void Load()
{
Bind().To();
Bind().To();
Bind().To();
            Bind().To();
Bind().To();
Bind().To();
Bind().To();
}
}
}

All classes are registered here.

The final result looks like this:

There is one problem in the Bindings class. This way of registering is not the best, what if we had … thirty classes and thirty different interfaces? A bit of sham … You would have to write all classes in turn …

But wait … will not a self-respecting container be able to register all classes in the system? I will answer this question soon because I will show on the example of the StructureMap container 🙂


StructureMap

Answering the above question — Yes, it should be possible, but it will show how to do it using the container as in the title of this point 🙂

We change the code in the same places as in the previous example. Let’s start with the Main() function.

We have this code:

var container = new Container(_ =>
{
_.Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
});
gameServer = container.GetInstance();

And that’s enough to register all classes. And creating an instance of the GameServer class is other tale we just need to call the ResolveInterfaces() method, which also changes to something like this:

public void ResolveInterfaces(IContainer container)
{
using (var nested = container.GetNestedContainer())
{
loginvalidator = nested.GetInstance();
passwordvalidator = nested.GetInstance();
characterskillpoints = nested.GetInstance();
            //characterrace = nested.GetInstance();
}
}

In the production code, luckily, you can do everything automatically. Only in the tests we have to give the classes we want to register.

[SetUp]
public void TestSetup()
{
characterRaceMock = new Mock();
characterMock = new Mock();
        character = characterMock.Object;
        var container = new Container(_ =>
{
_.Scan(x =>
{
x.TheCallingAssembly();
x.LookForRegistries();
});
            _.For().Use();
_.For().Use();
_.For().Use();
});
        gameserver = container.GetInstance();
        gameserver.ResolveInterfaces(container);
}

And of course the result 🙂

Let’s move to container called the Castle Windsor


Castle Windsor

Here I will show only how to use it. First, let’s see the changes in the Main() function

IWindsorContainer container = new WindsorContainer();
container.Register(Component.For().ImplementedBy());
container.Register(Component.For().ImplementedBy());
container.Register(Component.For().ImplementedBy());
container.Register(Component.For());
gameServer = container.Resolve();
gameServer = new GameServer();

So first we register dependencies, and create GameServer instances. Here we also have to register the GameServer class itself to create its instance.

There are such changes in the ResolveInterfaces() method:

public void ResolveInterfaces(IWindsorContainer container)
{
loginvalidator = container.Resolve();
passwordvalidator = container.Resolve();
characterskillpoints = container.Resolve();
        //characterrace = container.Resolve();
}

In tests, just put the same as in the Main () function without any changes 🙂

We’re still creating instances of classes all the time, but can we manage their life cycle? So, for example, tell the container to create only one instance of the object, or treat the instance as a singleton.

By the way, another great advantage of containers is the ability to work efficiently with them. For example, you can see how Castle Windsor debugging works. Nice 🙂 https://github.com/castleproject/Windsor/blob/master/docs/debugger-views.md

Our container from the previous article has always created a new object instance which in larger systems is unacceptable, ignoring the fact that we should always clean our container at the end of the application, because the created instances are forever in the container if we do not clean them. 🙂

We will manage the life cycle of our facilities using the Unity container.

Of course, all these containers are from the .Net platform in other platforms there are other containers.


Unity

One by one, before we manage the object lifecycle, we first register the objects in the Main() function in this way:

IUnityContainer container = new UnityContainer();
container.RegisterType(new TransientLifetimeManager());
container.RegisterType(new ContainerControlledLifetimeManager());
container.RegisterType(new HierarchicalLifetimeManager());

Those objects that we gave as arguments to the registering methods determine whether the object will be a singleton or whether it will be a singleton of a registered class that will not share an instance with the so-called parent container. It may seem confusing, but soon it will become clear first let’s see how we will check whether the object is singleton or not.

In the LoginValidator class, I created a public variable and method, something like this:

namespace DIContainers
{
//ILoginValidator interface
    public class LoginValidator : ILoginValidator
{
public int instances;
        //other logic
        public void CountNumberOfCalling()
{
instances += 1;
Console.WriteLine("Number of calling this method in object "+ this.GetType().Name + " : "+instances);
}
}
}

The same in the CharacterSkillPoints classes, PasswordValidator.

We will call the CountNumberOfCalling() method, if the object is a singleton, we should display a number greater than 1 on the console.

Let’s start with the first TransientLifetimeManager object, type in something like this under the class registration:

var class3 = container.Resolve();
class3.CountNumberOfCalling();
var class4 = container.Resolve();
class4.CountNumberOfCalling();

Of course, to make it work, we still need to create a GameServer object:

gameServer = container.Resolve();

And change the ResolveInterfaces() method.

public void ResolveInterfaces(IUnityContainer container)
{
loginvalidator = container.Resolve();
passwordvalidator = container.Resolve();
characterskillpoints = container.Resolve();
}

The result is this:

So we see that if we give the TransientLifetimeManager object as an argument, it will always create a new instance of the class.

Let’s move to the next ContainerControlledLifetimeManager this object will create singletons for us. So the Main () function:

var class1 = container.Resolve();
class1.CountNumberOfCalling();
var class2 = container.Resolve();
class2.CountNumberOfCalling();

As we can see the CountNumberOfCalling() method has been called twice in the same object, si it is a singleton 🙂

Let’s move to the last HierarchicalLifetimeManager object works the same as the previous one, only one difference is that you can create a container child using this object, which also creates a singleton, but it will not share the instance with own container. The example should be more understandable. 🙂

var class5 = container.Resolve();
class5.CountNumberOfCalling();
var class6 = container.Resolve();
class6.CountNumberOfCalling();
var childContainer = container.CreateChildContainer();
var class7 = childContainer.Resolve();
class7.CountNumberOfCalling();
var class8 = childContainer.Resolve();
class8.CountNumberOfCalling();

We create a singleton instance and then a container child and use it to create another singleton.

The result is this:

And that’s more or less the management of object life cycles looks like, let’s go over the last container I use and use most often 🙂


Autofac

Let’s see the basic use of Autofac, let’s start with the Main() function:

var builder = new ContainerBuilder();
builder.RegisterType().As();
builder.RegisterType().As();
builder.RegisterType().As();
 builder.RegisterType();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
gameserver = scope.Resolve();
}

And changes in the ResolveInterfaces() method

public void ResolveInterfaces(IContainer container)
{
using (var scope = container.BeginLifetimeScope())
{
loginvalidator = scope.Resolve();
passwordvalidator = scope.Resolve();
characterskillpoints = scope.Resolve();
}
}

The changes in the tests are the same as in the Main() function.

But this is not the end of the advantages of ready containers, another advantage is, for example, that you can register the factories giving as a dependence of Func<Interface> or a delegate. In this way, we can create a relationship when it is really needed and also do not expose the container to the components being created. Let me give you an example 🙂

First, we create a class with a delegate:

public class DelegateClass
{
public delegate DelegateClass Factory(string @string);
      public DelegateClass(string @string)
{
this.@string = @string;
}
      public string @string { get; private set; }
      public string getSymbol()
{
return @string;
}
}

Through this delegate, we will create our DelegateClass class in the Main() function.

var builder = new ContainerBuilder();
builder.RegisterType();
var container = builder.Build();
var delegateClassFactory = container.Resolve();
var delegateClass = delegateClassFactory("ABC");
Console.WriteLine(delegateClass.getSymbol());

In Main, we create a delegate instance and pass the appropriate argument. The result is this:

The next article will be entirely about Autofac, so about this point will be more detail already using Func in the next article, not only delegates 🙂


Other advantages of containers

Well, are all the advantages of containers? Of course not 🙂

Containers allow us to use aspect programming. Everywhere in which companies I was aspect programming was used to a greater or lesser extent. In short, aspect programming involves separating the logic of eg caching or logging from business logic. It’s so in a nutshell. Personally, I think this is a very interesting solution, it is definitely worth the interest.

Here is a bit about aspect programming: https://dzone.com/articles/aspect-oriented-programming-in-c-using-dispatchpro

Ready containers certainly work faster than ours. And they are written for years in teams of really experienced programmers.


Which container should I choose?

Well, certainly not speed, I do not care whether I will have a class instance created in a few or a dozen milliseconds …

Rather, I think to pay the most attention to the possibilities and the syntax of the container. For example, the Register and Resolve methods can be implemented in as many different ways as there are programmers on the ground, but in some containers, in my opinion, the syntax is too complicated …

And always remember to also change the code for the container you use w in tests :)


Summary

In the next article I will describe more precisely the Autofac container, which is the one I use most often 🙂

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

This content also you can find on my blog devman.pl: http://devman.pl/programtech/dependency-injection-professional-containers/

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 :)