Click here to Skip to main content
Click here to Skip to main content

Dependency Injection for .NET using a Dynamic Service Locator with Dynamic Proxy Injection

By , 8 Mar 2008
Rate this:
Please Sign up or sign in to vote.

Introduction

All of us have written code at some time that we wanted to share or reuse in other projects. The more you write code, the more you realize that you need a faster way to reuse your code. One of the problems is that sometimes you want to have the same functionality across several projects (reading data from a database, authenticating users, sending emails, sending SMS messages, and encrypting/decrypting data) but the implementation is different from one project to another. One project might be reading its data from MySQL, another project might be reading its data from MS SQL Server. One project might send SMS messages through SMTP, another project might send SMS messages through SMPP. So, we want to be able to do this in the most efficient way, we want our components to be like Lego parts, putting pieces together and building the big model from the small parts with minimum effort.

Inversion of Control is a generic concept in programming that generally describes any pattern that inverts the control in some way. One pattern that falls under Inversion of Control is Dependency Injection. Please check this well written article on Inversion of Control/Dependency Injection/Service Locator by Martin Fowler.

Outline of the article

The article will start with a small paragraph explaining the keywords used. Next, an example will be presented to enable us to understand the problem and how it can be solved by the Dependency Injection pattern.

Once the example is presented and the pattern is understood, a .NET solution is presented that gives us the ability to separate implementation from functionality, and the attached code with this article is visited.

The solution is taken a step further to present to the reader a dynamic proxy generator that helps inject proxy objects in between the services and the components in a very easy fashion. Dynamic proxy injection can be used for a lot of uses; for debugging, for logging, for better testing, for security control, for remote execution, and the list is endless.

Next, a clear step by step paragraph is presented showing how to use the code in your projects. Readers who are interested in just using the code should jump to this paragraph directly. Finally, we will revisit the benefits of this small framework and give a conclusion to the article.

Keywords

  • Component: Any piece of code that needs the services of other code that we call services.
  • Service: A piece of code that is given as a service to components.
  • Functionality/Contract/Interface: This presents the set of methods and properties that define a service; these sets of methods define the way you interact with the code, giving the developer an idea of what the service does without knowing how it does it.
  • Implementation: The way a service does what it is supposed to do, the details of the code is the implementation. The same service could be implemented differently depending on the environment or deployment. For example, a service to send SMS could have two implementations, one that sends them using SMTP protocol, and one that uses SMPP protocol.

Example

As with all articles trying to explain a point, the example will be as simple and trivial as possible to help explain the ideas in this article without complicating the code unnecessarily.

Suppose you are writing an application that needs to authenticate users to log in. The authentication mechanism you are using will be reading the list of users/passwords from a local database that you have. So, the functionality here would be to authenticate users, and the implementation in this case would be reading the users from the users table from your own database. Suppose another party wants to make use of your application/code and wants to deploy it at their site. However, they do not want to keep another set of user accounts, they want to get their user's credentials from their own database table that they already have. Or, they might even have a Windows domain and they want to authenticate users from an Active Directory.

Commonly, you would have to go into your code and change or rewrite that part where you are authenticating users to satisfy the target implementation. Instead, what we will try to do is separate the functionality from the implementation. The functionality here being a simple function that takes a username and a password and returns if the login information is accepted or not. The implementation would be different from one deployment to another. An object oriented programming concept that helps us separate functionality from implementation is the abstract class, also known as a pure virtual class, or an interface. C# has both of these, so we will go ahead and work with the interface. By grouping the methods that you want in an Interface, you would create an Interface (or a contract) with a set of methods that serve the functionality that you need. The interface simply dictates the functions that should exist and what parameters the functions take and return (also called the method’s signature). In our simple example, it will be a simple method called AuthenticateUser that takes a username and a password and returns a simple Boolean value to indicate whether or not the user /password combination is valid. Next, you will create a class that inherits from this interface. When you inherit from the interface, the compiler will force you to provide code to fill in the functions that you are deriving your class from, hence forcing the implementation. The code that you fill in defines the actual implementation for the methods in the interface. Let us take a look at the code attached with this article.

public interface IAuthenticate
{
    bool AuthenticateUser(string username, string password);
}

public class SampleAuthenticate : IAuthenticate
{
    public bool AuthenticateUser(string username, string password)
    {
        return (username == "username" && password == "password");
    }
}

Now, instead of the code working directly with the class SampleAuthenticate and depending on it, we will write our code to work with the interface IAuthenticate. This way, the code will compile and depend on the interface and not the class or the object that has the implementation written in it. And then, whenever the interface is needed in your code, you have to create an instance of a class that derives (implements) from the needed interface. The code that creates the object that implements the needed interface can be thought of as injecting the implementation. Hence, you are Injecting the Dependency, instead of having your code depend on the class directly. Take a look at the file Form.cs and the method loginButton_Click. Instead of your component controlling which code it wants to use, the decision on which code (the specific implementation of this interface) is now not done by the component itself but by some code outside this component, hence a form of Inversion of control. Now, if you need to authenticate your users using Active directory or any other implementation, all you need to do is to create another class that also inherits from IAuthenticateUsers. Later on, we decide which implementation we want by changing which class to inject. All you would need to change is a small area of code that creates the object that will be responsible for servicing the needed interface.

Dependency Injection is usually achieved in several ways, constructor injection, setter injection, and even interface injection. The most common way is by using constructor injection. This is the case where any code in your application that needs to authenticate users will provide in its constructor a parameter to IAuthenticateUsers and for all the other interfaces it needs. Then, in the code, when you want to create an instance of this class, you will have to pass in to its constructor whichever object you want as long as it implements the asked for interface; Inversion of Control.

When we separated the functionality (interface) from the implementation (the class inheriting from the interface), we decoupled the code that needs to authenticate users (the what) from the code that knows how to authenticate users (the how). Usually, when using the Dependency Injection pattern, there is a piece of code that decides which objects will be served when interfaces are asked for; this class or code is referred to as a service locator as it locates a service (creates the appropriate class that implements a specific interface) and hands the service via the interface to the code asking for it. The service locator will know, for each interface needed, which class to create, or said differently, for each service needed, which implementation is provided. To further decouple things, we transfer the Dependency Injection from the compile time world to the runtime world. The service locator will need to read the links from a configuration entity such as a file or the Registry at runtime. Our service locator will now be called a dynamic service locator as it can do its linking at runtime. If you take a look at the following code in loginButton_Click:

IAuthenticate iAuthenticate = 
  (IAuthenticate)DynamicServiceLocator.DynamicServiceLocator.
    CreateImplementerByInterfaceName(typeof(IAuthenticate));

The CreateImplementerByInterfaceName method takes the interfaces needed and returns an object that implements the requested interface.

I hope at this point in the article, the idea behind Dependency Injection and its benefits is becoming clearer for the reader.

Dynamic proxy generator

Our dynamic service locator is able to create a class (actually code it) at runtime. This dynamic class will implement the interface needed, and it will encapsulate the original service. This class, the proxy class, will sit in the middle between the service seeker and the service locator, and will intercept the calls. Doing this is also very easy with the presented framework here. All you need to do is add a few lines of configuration to our configuration file; see the step by step guide for the configuration details.

A step by step guide to using the code

  1. Create the functionalities needed by defining the interfaces that you need in your code.
  2. Create one or more implementations needed by writing classes that inherit from the interfaces you have created.
  3. Whenever your code needs to work with an instance of an interface, use the method DynamicServiceLocator.CreateImplementerByInterfaceName and pass it the interface that you want.
  4. You need to modify the App.Config file with this:
    • Under <configuration>, under <configSections>, add the following section configuration:
    • <section name="
        DynamicServiceLocator"
        type="DynamicServiceLocator.DynamicServiceLocatorConfiguration,
        DynamicServiceLocator" 
        allowDefinition="MachineToApplication" />
    • Under <configuration>, add the following XML node:
    • <DynamicServiceLocator>
    • Inside the <DynamicServiceLocator> tag, add one or more implementation tags, like this one:
    • <add 
        InterfaceName="DependencyInjectionFor.NET.Contracts.IAuthenticate, 
                       DependencyInjectionFor.NET" 
        InterfaceAssembly="" 
        ImplementerClass="DependencyInjectionFor.NET.Implementers.SampleAuthenticate, 
                          DependencyInjectionFor.NET" 
        ImplementerAssembly="" />
      • InterfaceName: has the type of the interface needed as a full type name (the full name of the interface, the name of the default namespace of the assembly).
      • InterfaceAssembly: is empty if the interface needed is in the same main assembly of yours; if not, then specify the full assembly name like “example.dll”. If you want to inject a proxy object, then you have to create a class that implements from IDynamicProxy and you have to add two values to the above tag: InjectIDynamicProxyClass = "the full type name, the assembly namespace", and the InjectAssembly is the assembly that has your proxy class.

Under the hood

When you call the DynamicServiceLocator and ask it for an interface, the dynamic service locator (DSL) will locate the entry of the interface from the App.Config file. Then the DSL will try to load the type (InterfaceName) from the already loaded assemblies in your current process; if it does not find it, then it will try to load the assembly (InterfaceAssembly) dynamically from its filename, and if successful, will try to seek the type inside the loaded assembly. Similarly, it will try to load the implementer class (ImplementerClass, ImplementerAssembly). After it loads both the interface and the implementer object, it makes sure that is actually implements the wanted interface and returns the object back. If App.Config specifies a proxy class for the specified interface (InjectIDynamicProxyClass, InjectAssembly), it will try to load the proxy object and put in the middle, between the service seeker and the actual service.

Conclusion

Using the Dependency Injection pattern, it can turn your programming habits into small fully decoupled components that can be put together like Lego pieces that fall right into place every time. This will maximize your code reuse by quickly integrating your previously written components. It will maximize your code's reliability by decoupling your components in a very clear manner from your projects and by eliminating code duplication across your projects. The framework presented here is one that allows you to use the dependency injection pattern for the .NET environment. There are other frameworks out there, but none to my knowledge integrates dynamic proxy generation with dependency injection. The framework's ability to inject dynamic proxy objects leverages the full power of dependency injection.

Comments are very much welcomed. I hope my article will benefit a lot of developers out there.

License

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

About the Author

Ralph Varjabedian
Technical Lead
Lebanon Lebanon
No Biography provided

Comments and Discussions

 
GeneralAlso using Spring .NET PinmemberMaruf Maniruzzaman10-Mar-08 19:32 
QuestionHow would you compare this to LinFu PinmemberDewey8-Mar-08 11:12 
AnswerRe: How would you compare this to LinFu PinmemberRalph Varjabedian8-Mar-08 12:49 
GeneralSmall adjustment to app.config PinmemberComplexityChaos8-Mar-08 8:20 
GeneralRe: Small adjustment to app.config PinmemberRalph Varjabedian8-Mar-08 11:02 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 8 Mar 2008
Article Copyright 2008 by Ralph Varjabedian
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid