Loading ...

Dependency Injection And Factory Design in .NET

Who is online?  0 guests and 0 members
home  »  articles  »  Dependency Injection And Factory Design

Dependency Injection And Factory Design

(3462)
0
/5
Avg: 0/5: (0 votes)
Published: 2/3/2009 by  Vivek Thakur

Introduction

Dependency Injection and Factory design patterns are very common and provide great flexibility in software development.
Though most programmers have read these patterns but they may not grasp the concepts completely unless they see these patterns in action in real projects.

The aim of this article is to provide a detailed explanation on how loose coupling and “plug-and-play” architecture is achieved using these patterns with the help of an open source project I have developed called NeekProtect.

Background

NeekProtect is a simple and user friendly file and folder encryption program to be used on Win 32 platform. It is developed using C# on using Visual Studio 2005. It currently does not use any database.

Now many would ask: why another encryption program? The reason: I was not satisfied with NeoCrypt (another opens source encryption program) as it lacked interactive GUI and was limited in the sense it used a custom library for its encryption algorithms and algorithms can become outdated (3DES was super ceded by Rijndael).
I wanted a flexible "plug-n-play" system where the user can plug his own custom algorithm and make NeekProtect use it by just adding some info in a config file.

My article focuses on this particular requirement and how I achieved it by making use of some famous design patterns,including Dependency Injection and Factory design.

Dependency Injection And Factory Design

Dependency Injection design pattern is “a form of” Inversion of Control design applied in many frameworks such as PicoContainer. It gives the flexibility of attaching custom implementation like a “plugin” without modifying existing software. Dependency Injection can be achieved using Constructor, Setter or Interface Injection. Since Martin Fowler has already written an excellent article on this topic, I would not reproduce it and instead give the link so that the reader can go through the same:

http://www.martinfowler.com/articles/injection.html

Factory Design is a creational pattern is a way through which we delegate the responsibility of object
creation of a particular class to some other “factory class”. For more details please refer:
 
http://en.wikipedia.org/wiki/Factory_method_pattern

Application of Design Patterns

Starting with NeekProtect’s design, since I wanted “plug-and-play” flexibility, I authored an interface
first so that others can implement their own algorithmic implementations by defining these methods in their own custom way:

namespace NeekProtect
{
    /// <summary>
    /// This interface is the contract which implementation classes
    /// need to follow for writing custom encryption methods.
    /// </summary>
    public interface IEncryptionAlgorithm
    {
        /// <summary>
        /// Property to get/set password
        /// </summary>
        string Password
        {
            get;
            set;
        }

        /// <summary>
        /// Property to get/set the Raw Input byte array
        /// </summary>
        byte[] RawInput
        {
            get;
            set;
        }

        /// <summary>
        /// Set optional salt value
        /// </summary>
        byte[] Salt
        {
            set;
        }

        /// <summary>
        /// Set KeySize
        /// </summary>
        int KeySize
        {
            set;
        }

        /// <summary>
        /// Encrypts the raw input
        /// </summary>
        /// <returns>Encrypted byte array</returns>
        byte[] Encrypt();

        /// <summary>
        /// Decrypts the byte array
        /// </summary>
        /// <returns>Decrypted bytes</returns>
        byte[] Decrypt();

        /// <summary>
        /// Checks the user entered password. The password is stored in the
        /// encrypted byte array and is first compared before decryption.
        /// </summary>
        /// <returns>true if password is correct</returns>
        bool CheckPassword();
       
    }//end interface
}//end namespacenamespace NeekProtect
{
    /// <summary>
    /// This interface is the contract which implementation classes
    /// need to follow for writing custom encryption methods.
    /// </summary>
    public interface IEncryptionAlgorithm
    {
        /// <summary>
        /// Property to get/set password
        /// </summary>
        string Password
        {
            get;
            set;
        }

        /// <summary>
        /// Property to get/set the Raw Input byte array
        /// </summary>
        byte[] RawInput
        {
            get;
            set;
        }

        /// <summary>
        /// Set optional salt value
        /// </summary>
        byte[] Salt
        {
            set;
        }

        /// <summary>
        /// Set KeySize
        /// </summary>
        int KeySize
        {
            set;
        }

        /// <summary>
        /// Encrypts the raw input
        /// </summary>
        /// <returns>Encrypted byte array</returns>
        byte[] Encrypt();

        /// <summary>
        /// Decrypts the byte array
        /// </summary>
        /// <returns>Decrypted bytes</returns>
        byte[] Decrypt();

        /// <summary>
        /// Checks the user entered password. The password is stored in the
        /// encrypted byte array and is first compared before decryption.
        /// </summary>
        /// <returns>true if password is correct</returns>
        bool CheckPassword();
       
    }//end interface
}//end namespace

Now I first created an XOR based encryption class which implemented this interface:

public class XOREncryption : IEncryptionAlgorithm

I implemented the encryption and decryption methods along with the propertied defined in the IEncryptionAlgorithm interface as:

/// <summary>
/// Main encryption method
        /// </summary>
        /// <returns>Array of bytes containing encrypted output</returns>
        public byte[] Encrypt()
        {
            ///<remarks>
            ///Output byte array
            ///</remarks>
            byte[] encryptedBytes = new byte[_rawInput.Length];
            byte[] keyBytes = ASCIIEncoding.ASCII.GetBytes(_key);
            //hard coded salt value
            _salt = new byte[] {0x11, 0x78, 0x22, 0xFF, 0xAC, 0x5C,
                                0x78, 0x4E, 0x7D, 0x45, 0xEF, 0xF1};
              …..//implementation
         }

I completed this class with other methods and properties defined by the interface (see the source code).
Then I created another encryption algorithm implementation:

public class RijndaelEncryption : IEncryptionAlgorithm
{
       //implement IEncryptionAlgorithm properties and methods
}

So now I have two implementations ready and the question is how do I dynamically instantiate one of these in the GUI?

For that, I used Factory Design Pattern and created a Factory class as:

namespace NeekProtect
{
    /// <summary>
    /// This factory class is responsible for creation of concerete
    /// instances of different algorithm implementations.
    /// </summary>
    public sealed class AlgorithmFactory
    {
        /// <summary>
        /// Private constrcutor so as to avoid instance creation
        /// </summary>
        private AlgorithmFactory()
        { }

        /// <summary>B
        /// Static method which the client will call to get
        /// the current concrete implementation specified in the
        /// configuration settings file
        /// </summary>
        public static IEncryptionAlgorithm GetSpecifiedAlgorithm()
        {
            string algoType = System.Configuration.ConfigurationSettings.AppSettings["algo"];
            IEncryptionAlgorithm algoInstance;

            if (string.IsNullOrEmpty(algoType))
            {
                ///<remarks>
                ///Use default XOR encryption
                ///</remarks>
algoInstance = Activator.CreateInstance(Type.GetType("NeekProtect.XOREncryption,NeekProtect"))
                     as IEncryptionAlgorithm;
            }
            else
            {
                algoInstance = Activator.CreateInstance(Type.GetType(algoType)) as IEncryptionAlgorithm;
            }
            ///<remarks>
            ///Return the appropriate IEncryptionAlgorithm concrete instance
            ///</remarks>
            return algoInstance;
        }
    }//end class
}//end namespace

This factory class is sealed because I don’t see any one ineheriting it for any reason. Then I made its
constructor private so that its instance cannot be created at all and made all methods static. Why static? Because AlgorithmFactory is behacing like a Helper class helping the clients get an instance of appropriate Algorithm implementation class.
See the static GetSpecifiedAlgorithm() method: it returns an instance of IEncryptionAlgorithm. This is where I used an important Design principle: “Always program to interfaces”. Since each encryption algorithm class implements IEncryptionAlgorithm, so the supertype of each implementation is same: IEncryptionAlgorithm.
So I don’t care about the actual implementation class as long as the class implements the same interface.

 This gets me the type specified in the application config file:

string algoType = System.Configuration.ConfigurationSettings.AppSettings["algo"];

In the config file, the following entry is made (under appSettings):

<add key="algo" value="NeekProtect.XOREncryption,NeekProtect"/>

In the value, we specify the fully qualified class name and the assembly name in which the class is present,separated by a comma.We need this entry as we will dynamically load the assembly using Activator.CreateInstance as:

IEncryptionAlgorithm algoInstance;
algoInstance = Activator.CreateInstance(Type.GetType(algoTyp)) as IEncryptionAlgorithm;

Note: If no entry is specified in the config file then XOREncryption class is used as default
(see the code for AlgorithmFactory)algoInstance is then returned to the client caller.

Lets see the client now and how it uses this instance. The class EncryptionEngine is our client here:

/// <summary>
/// This class prepares the byte array and sets files and directories to
/// be encrypted and calls the relevant encryption/decryption algorithm
/// </summary>
    public class EncryptionEngine
{ ….}

This class has a method:

private void EncryptFile(string fullPath, string password)
   {
               IEncryptionAlgorithm x = AlgorithmFactory.GetSpecifiedAlgorithm();
                x.Password = password;
                x.KeySize = 128;
                string ext = Path.GetExtension(fullPath);
                byte[] extByte = Encoding.ASCII.GetBytes(ext);
                byte[] inputByte = File.ReadAllBytes(fullPath);
                MemoryStream m = new MemoryStream();
                m.Write(inputByte, 0, inputByte.Length);
                m.Write(extByte, 0, extByte.Length);
                x.RawInput = m.ToArray();
                byte[] o = x.Encrypt();
                …..//other stuff
}

So I call the AlgorithmFactory’s static method GetSpecifiedAlgorithm() which returns me an instance of the class specified in the config file. Here I don’t care how does the instance is returned, I just need
an instance of IEncryptionAlgorithm so that I can encrypt the input file. This is again an example of
programming to interfaces. In the above code, there is no mention of the 2 encryption classes I have coded earlier: XOREncryption and RijndaelEncryption. I only use IEncryptionAlgorithm in this code and this gives me the flexilbity to use any custom alorithm as long as it imeplements EncryptionAlgorithm. Lets suppose a user installs NeekProtect and is not satisfied by my provided two alogrithms. Assume he wished to use 3DES algorithm to use with NeekProtect. What does he do?

Answer: Create his own 3DESEncryption class and implement all methods and proeprties specified in
the IEncryptionAlgorithm interface as:

public class 3DESEncryption: IEncryptionAlgorithm
{
       //implement IEncryptionAlgorithm properties and methods
}

Now compile it and place the resultant assembly in the folder where NeekProtect is installed
(for e.g.: C:\Program Files\Vivek Thakur\NeekProtect 1.1b).
In the same folder, open and edit the XML configuration file (usually its named as NeekProtect.GUI.exe.config) and create/overwrite the value of the key “algo” as:

<add key="algo" value="MyCustomAlgo.3DESEncryption, MyCustomAlgo "/>

(for the sake of illustration, I have assumed the namespace to be MyCustomAlgo)

Now the Factory class will return this instance to be used in NeekProtect. So we see how "plugin" type functionality can be achieved using Dependency Injection.

Summary

Using simple design patterns can help create flexible software which is also easy to maintain and also reduce costs. By the help of this article I wanted to explain how this flexibility can be achieved in
real world programs. Also if there are any suggestions on improving this design, I would love to hear them.

 

Comments (no comments yet)

Confirm

Product Spotlight

ASP.NET Hosting Spotlight

Most Recent Articles

 

Product Spotlight

ASP.NET Hosting Spotlight

Quick Vote

What kind of email newsletter would you prefer to receive from CodeAsp.Net?