|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionAll 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 articleThe 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
ExampleAs 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 users 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 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 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 IAuthenticate iAuthenticate = (IAuthenticate)
DynamicServiceLocator.DynamicServiceLocator.
CreateImplementerByInterfaceName(typeof(IAuthenticate));
The I hope at this point in the article, the idea behind dependency injection and its benefits is becoming clearer for the reader. Dynamic proxy generatorOur 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
Under the hoodWhen 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. ConclusionUsing 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 codes 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 .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.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||