Click here to Skip to main content
15,881,794 members
Articles / Programming Languages / C#

Dependency Inversion Principle, IoC Container, and Dependency Injection: Part 5

Rate me:
Please Sign up or sign in to vote.
4.80/5 (7 votes)
23 Apr 2020CPOL5 min read 7.5K   8   2
What is UnityContainer and the different ways of registering dependencies
This is the final part of a series of articles on Dependency Injection. In this part, I will explain different features provided by UnitContainer and how to register a dependency. I will also create a demo application to show how to register and resolve a dependency using UnityContainer.

Introduction

This is the fifth and final part of my article on Dependency Inversion Principle and Dependency Injection. In the previous part, I implemented a custom container with very limited functionalities which can be used to register the dependencies and resolve when you need the instance of the dependency. Now there are many tools available to implement Dependency Injection such as UnityContainer, StructureMap, Windsor Castle, NInject and many more. In this part, I will explain different features provided by UnitContainer and how to register the dependencies and how to resolve the registered dependencies.

If you are a direct visitor to this part, you may find it difficult to understand the code. So please go through the previous parts before you start reading this post. For easy navigation to previous articles, I have provided the links below:

Overview

The Unity Container (Unity) is a full featured, extensible dependency injection container. It facilitates building loosely coupled applications and provides developers with the following advantages:

  • Simplified object creation, especially for hierarchical object structures and dependencies
  • Abstraction of requirements; this allows developers to specify dependencies at run time or in configuration and simplify management of crosscutting concerns
  • Increased flexibility by deferring component configuration to the container
  • Service location capability; this allows clients to store or cache the container
  • Instance and type interception
  • Registration by convention

via [https://github.com/unitycontainer/unity]

Dependency Registration

Registering a dependency lets the IoC container know the concrete implementation of a dependency. For example, if we want to get the instance of KeyboardReader when we request to resolve IReader dependency, we need to register the dependency IReader which resolves an instance of KeyboardReader class. The following is an example of dependency registration using Unity container.

C#
IUnityContainer container = new UnityContainer();

container.RegisterType<IReader, KeyboardReader>();

With the above registration, while resolving type IReader [container.Resolve<IReader>()], will return an instance of KeyboardReader.

UnityContainer supports dependency registration in the following ways:

Instance Registration

By doing Instance Registration, we tell the IoC container that when someone requests to resolve a dependency, then the registered instance will be returned. Instance registration is helpful in a situation where you want to register your dependency in a specific state. The RegisterInstance() method is used for registering an instance in a container.

C#
var keyboardReader = new KeyboardReader();

container.RegisterInstance(keyboardReader);

With the above registration, while resolving type KeyboardReader [container.Resolve<KeyboardReader>()], will return the registered instance.

Instance can be registered in IoC container with a name. The example is given below:

C#
var keyboardReaderA = new KeyboardReader();
var keyboardReaderB = new KeyboardReader();

container.RegisterInstance("InstanceA", keyboardReaderA);
container.RegisterInstance("InstanceB", keyboardReaderB);

With the above registration, while resolving type KeyboardReader, we need to provide the name, as there is no registration that exists without a name. So in the above case, while resolving type KeyboardReader using container.Resolve(KeyboardReader, "InstanceA") will return the keyboarderReaderA instance, and while resolving type KeyboardReader using container.Resolve(KeyboardReader, "InstanceB") will return the keyboardReaderB.

Instance Registration also supports type mapping. It means an instance can be registered against an type (class or interface) so that while resolving the type, the registered instance will be returned to the caller. The example is given below:

C#
var keyboardReader = new KeyboardReader();

container.RegisterInstance<IReader>(keyboardReader);

With the above registration, while resolving type KeyboardReader [container.Resolve<IReader>()], will return the registered keyboardReader instance.

Factory Registration

Using Factory Registration, we can register a dependency based on an output of a function call. It provides more control while registering the instance.

C#
var keyboardReader = new KeyboardReader();

container.RegisterFactory<IReader>(fn => new KeyboardReader());

Type Registration

Type Registration is the widely used registration. In this type of registration, we need to provide the contract type and a concrete type, where resolving the contract type will produce an instance of a concrete type. The minimum requirement of a Typed Registration is the type itself. The following in an example of a registration:

C#
container.RegisterType<KeyboardReader>();

With the above registration, while resolving type KeyboardReader [container.Resolve<KeyboardReader>()], will return an instance of KeyboardReader.

Following is another example of registration where we can provide a contract type and its concrete type.

C#
container.RegisterType<IReader, KeyboardReader>(); // default registration

With the above registration, while resolving type KeyboardReader [container.Resolve<IReader>()], will return an instance of KeyboardReader.

We can also provide a name while registering a type:

C#
container.RegisterType<IReader, KeyboardReader>("Keyboard");

With the above registration to resolve the dependency, we need to use container.Resolve<IReader>("Keyboard").

Note: The default value of a name is null. When we register a type without passing any name, such kind of registration is called as default registration.

Sample Application

Let's create a console application using Visual Studio. In this demo application, I have used Visual Studio 2019. But you can use any version of Visual Studio (Visual Studio 2012 onwards).

Image 1

Right-click on the project and click on "Manage NuGet Packages...". Manage NuGet Package is used to add the 3rd party libraries to the application.

Image 2

In the Manage NuGet Package window, select Browse option and search for Unity and Install the package. At the time of writing the article, the latest version of Unity was 5.11.6. But you can use any stable for the demo application.

Image 3

Add the following lines of code in Program.cs file:

C#
using System;
using Unity;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IReader, KeyboardRader>();
            var reader = container.Resolve<IReader>();
            var readText = reader.Read();
            Console.WriteLine($"The output is : {readText}");
            Console.ReadLine();
        }
    }
    
    interface IReader
    {
        string Read();
    }

    class KeyboardRader : IReader
    {
        public string Read()
        {
            return "Reading from keyboard...";
        }
    }
}

Your sample application is ready to run. Press F5 to run the console application.

You will get the following output:

Image 4

As you can notice, we have registered the type IReader for a KeyboardReader concrete type using Typed registration. Hence, when we try to resolve the type IReader, we will get the instance of KeyboardReader. And calling the Read() method will return "Reading from keyboard...", which is printed on the console.

UnityContainer provides many more functionalities, which I will be covering in my next article. Also, I will show you what are the different ways to inject dependencies.

Summary

In this part of the article, I explained what is UnityContainer, how to register a dependency and created a demo application to show the registering and resolving a dependency using UnityContainer.

History

  • 23rd April, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
PAREXEL International
India India
Life is short. So enjoy each and every moment of life.
And necessarily keep smiling. Smile | :)

Comments and Discussions

 
QuestionGood articles - so far Pin
Garth J Lancaster24-Apr-20 16:57
professionalGarth J Lancaster24-Apr-20 16:57 
AnswerRe: Good articles - so far Pin
Chinmaya C28-Apr-20 15:44
Chinmaya C28-Apr-20 15:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.