Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Inversion of Control, Binding Interface to Multiple Implementations

4.55/5 (7 votes)
16 Oct 2014CPOL3 min read 16.5K   122  
How to implement Inversion of Control ( IoC) using Ninject .NET container

Introduction

In software projects, we often come across scenarios where we have to implement separate concrete classes for a given interface. Let’s deliberate this with a real life example. Consider a virtual store that supplies electrical equipment. The store receives the equipment from various vendors. The store decides to implement a web service to retrieve the data and designs the service interface and concrete implementation. However, it is found that there are altogether 50 vendors and they have to write 50 separate services. This solution will be a maintenance nightmare, how to resolve it?

Image 1

Background

Inversion of Control ( IoC) usually is limited to one class per interface. The binding process usually enforces a one-to-one correspondence. What if the application uses different classes that implement the same interface for different purposes?

Solution with Ninject

Using Ninject, you can bind an interface to concrete implementations at runtime. For example, the virtual store can have all these vendors (i.e., concrete class each) sharing an interface derived from a common one. At run time, the application determines the specific interface, searches for the corresponding implementation using a dictionary and allows Ninject to map the interface to the concrete class.

Using the Code

Code Explanation

With Ninject, your type bindings are collected into groups called modules. Each of these modules represents an independent segment of your application. They can be organized however you like. Modules just need to implement the NinjectModule interface as shown below.

C#
Bind<ILaunchServiceHelper>().To<LaunchServiceHelper>();
  Bind<IVendorA>().To<VendorA>();                 
  Bind<IVendorB>().To<VendorB>();

Once you create modules, you load them into a container called the kernel. As the name suggests, the kernel is the core of your application. To request an instance of a type from Ninject, you call the kernel's Get() method

C#
var kernel = new StandardKernel(new VendorServiceModule());
  _ServiceHelper = kernel.Get<ILaunchServiceHelper>();

Ninject Magic

The main logic of the application is based on a dictionary. The dictionary consists of pair of VendorName and Interface. If you have 50 vendors, there will be 50 pairs. When the application runs, it checks if the selected vendor is presented in the dictionary. If the vendor is found, the Ninject module magically brings the corresponding class. All you need is to ensure that the corresponding concrete class is present in the solution.

C#
_vendorDictionary.ContainsKey(show) ? _vendorDictionary[show].ImportData(out  serviceoutput) : 
    show.ToString() + " is not mapped to a class" 

In the code sample above, ImportData is part of the Ninject interface called ILaunchServiceHelper. If vendor is found (in the dictionary), this interface checks the chain of dependency to determine if the concrete class is present and dynamically instantiates the vendor object.

In our implementation, VendorA and VendorB each implement ImportData method. We have implemented a HttpWebRequest to http://www.contoso.com to simulate a web service call. VendorA is using ResponseStream while VendorB is using GetResponse – to show that the service calls are different.

The application doesn’t know which vendor is being called, it knows only at runtime – when the Vendor name is retrieved from the configuration file. It is the Ninject which knows how to find and bind the Vendor interface and Vendor implementation. It is a convenient approach; the vendor list can quickly grow large and difficult to manage. With Ninject, you can selectively bind to one of the implementations and the approach is quite simple.

Points of Interest

The sample project can be enhanced to run in Windows task scheduler. Suppose you are expecting to access VendorA on Monday, Tuesday and Friday and VendorB on Wednesday and Thursday. You can schedule the same with task scheduler by attaching to the specific Vendor. You can also implement a repeating task like calling the Vendor service every hour.

History

  • 17th October, 2014: Initial version

License

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