Wednesday, 22 June 2011

How SQL injection works

Contents

Introduction

There was an era when children grew up reading comic strips but now comic strips have got some action and has evolved as the animated cartoon films.

Web sites initially started just to show some static information to the user on plain HTML pages with some graphics and colorful text. Soon the advent of technologies like CGI made it possible to have dynamic features attached to them. Sites were able to query an online database and fullfill requests. With the growing pace of the IT, soon websites got a powerful shot gun called online transaction. Now sites not only display dynamic data but are also capable of taking the orders from the customers and process them online.

This whole drama of accessing the database had the database accessing API at its heart. The input given by the end user (visitor) was processed by the back end SQL engine to perform CRUD operations on the database (CRUD - Create, Read, Update, and Delete).

How SQL injection works

SQL injection is no more exception to the golden rule �ALL INPUT IS EVIL�. SQL injection is nothing but, using the CRUD operation against the database in a way that it no more fulfills the desired results but give the attacker an opportunity to run his own SQL command against the database that too using the front end of your web site.

Well, mostly text box input is the best friend of the attacker. However any input going neatly to the database is not safe.

Let us take an example. The normal query like:

Collapse
Select * from customers

is safe for SQL injection. As we can see there is no user input involved in it. An interactive query like:

Collapse
select * from customers where customerID = 'ALFKI'

is an alarm for SQL injection if ALFKI is a user input. By user input I mean data got through the front end of your application. Let us assume some text box is there (it could be combo box also) where the end user can input customer name and in turn your application will show the result of a query after executing the query against a database.

In case it is a combo box, the attacker can first save your page in HTML format and then craft the combo box value field to make an attack. However, the best he can do is offline analysis of your page and then making an application which will send the GET or POST request directly to your application using the same name for the input controls to make his query string/ request, thus bypassing your front end script validations. It�s very easy to make this kind of application. An average programmer with one year of experience in web application development can make it.

So let us see one example of evil user input. If instead of typing the customer name in the text box, the user types the following string. Then the SQL Server running behind the scene will lock the server. This however depends upon how misconfigured the server is.

Collapse
a'  exec master.dbo.xp_cmdshell 'rundll32.exe user32.dll,LockWorkStation'

So if you want to make a site unavailable and the server is misconfigured then you can run the 'iisreset/Stop' command. Here is the complete input:

Collapse
a'  exec master.dbo.xp_cmdshell 'iisreset/Stop'

However this is just a hint. Actually the attacker will instead want to gain information stored inside your tables on the server to get access to the valuable data stored inside it. And real data is money. Think about this, if there is a badly designed application and an attacker is able to get information regarding credit card number or personal email address of your customer along with their personal information like home address, he might commit a physical crime there or sell the email to spammers.

Knock knock knock... "madam I am from abc.com and here is the order you placed on the site" on so and so date.. thus gaining physical access to the house of your customer.

How to find out which SQL server is on work

However, before breaking in to the site for access, an attacker needs to know which SQL engine is at the back end, and getting this out of a poorly designed system is a mere child's play. And before even trying, there is another way called guessing.

If your site has web page extensions like .asp, .aspx etc. then there is a high chance of SQL Server or MS Access. If the pages end as .jsp it could be an Oracle system at your end. If the pages are ending as .php, I guess it will be MySQL. However if my guess is wrong I can always go ahead and start doing the real work. Let us see how you can find out which SQL engine is at the back end. To identify the back end SQL server the minimum qualification required is beginner level experience with SQL. The general tool used to find out the SQL engine at the back end are the string concatenating characters and the comment characters.

  • For SQL Server: ALFKI and AL + FKI are same.
  • However, for Oracle, ALFKI and ALF || KI are the same.

So give the input as AL+FKI and if you get an error it means definitely the back end is not SQL Server. So now you can move on to the string concatenation syntax of other databases till you find out that you are getting the proper result.

Attackers generally work like a commando instead of an immature person with a gun in hand. They always put the correct tools ready near to them. What I mean to say is that an attacker will have text files ready with him, which will have the canned queries ready and the attack is a matter of quick copy and paste.

Using the SQL engine defined functions are also good examples of narrowing down the range, e.g., you can use the date functions to find out which server is at the back end: Sysdate for Oracle, Getdate for SQL Server.

Using the character used to end a SQL statement is also a good candidate for finding out the SQL engine at the backend.

We can not stop this kind of attacks because even showing an error page back to an attacker is like letting him know that the entered string was wrong. However the golden thumb of rule is in the error page don�t show the full detailed error message back, instead just say some error has occurred, and you can thus be saved from further damage the attacker is going to cause. Because, SQL injection attacks generally use the returned error messages to go a bit deep into the attacking process.

A few examples for SQL injection

Let us see what the few types of attacks which are popular are:

The common attacks are:

  1. Finding out the tables in a database.
  2. Finding out the column names in a database.
  3. Using the ORDER BY clause to find out the number of columns used in the database.

Being an admirer of Microsoft, I will use MS SQL Sever. This doesn�t mean it is week. But I feel at home while using MS SQL Server. First let us see a simple query to find out which tables are there in the database:.

Collapse
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES

This query returns the user defined tables in a database and an attacker can use this to find out the tables present in your system. To find out the columns present in your table, the next query which is used as sequel to this query is:

Collapse
SELECT  COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='customers'

You will be wandering how an attacker is going to directly execute these queries in your system. The answer is he can easily find out the number of columns returned in your result set and then do a Union with the returned result.

Simple commands like:

Collapse
UNION select table_name , null ,null ,null

are helpful in this case. Let us take the old query once again:

Collapse
select * from customers where customerID = 'ALFKI'

The vulnerable query will be:

Collapse
select * from customers where customerID = 'ALFKI'  union  SELECT table_name,null,null,null,null,null,null,null,null,             null,null FROM INFORMATION_SCHEMA.TABLES --'

Exploit string used [starting from the single quote sign below]:

Collapse
' union  SELECT table_name,null,null,null,null,null,null,null,       null,null,null FROM INFORMATION_SCHEMA.TABLES --

However you will be now astonished how an attacker can find out the number of nulls to be attached. So the answer is very simple: by looking at the output when a normal query produces result on the HTML page or by using the ORDERBY clause:

Collapse
select * from customers where customerID = 'ALFKI' Order by 1 --  select * from customers where customerID = 'ALFKI' Order by 15 --

will give an error to the attacker. However:

Collapse
select * from customers where customerID = 'ALFKI' Order by 11 --

will not give an error so the attacker now knows that there are only 11 columns in the result returned.

I will stop my discussion here itself, rest is on your imagination.

Some advanced forms of SQL injection (MS SQL Only)

Using the technique of SQL injection, a more advanced attack can be done. This can be done if we inject the SQL string containing the call to sp_addlinkedserverlogin. However this again depends upon the privileges to the account under which this SQL injection has run. Similarly, the openrowset, Openquery functions can provide an attacker a chance to guess your password using brute force techniques. For more details, see this.

Preventing SQL injection

The various techniques used to prevent SQL injections are:

  1. Parameterized query
  2. Stored procedure
  3. Regular expression to discard input string
  4. Quoteblock function
  5. Don�t show detailed error messages to the user.
  6. Have a less privileged user/role of your application in database.

SQL injections can be prevented. However there are myths about them (like if I am using stored procedure I am safe). One rule still follows: �Don't show detailed error messages to the user�. The basic mantra to prevent SQL injections is to let the string input as a string input to the SQL Server. This can be done by checking the string terminator character before giving the input to the server. Some techniques like using parameterized query and using stored procedures will do it free for you. However I would still suggest you to use the Quoteblock function inside them (MS SQL Server). The other prevention will be only carefully deciding the grant of the execute command to the service account which you are using to make the communication possible between the SQL server and the web server. One handy tip is not to use dynamic SQL in your application. Dynamic SQL is like (MS SQL).

Collapse
Sp_executesql(�string from the user�)

Or

Collapse
exec (�string from the user�)

I would like to add one more point here: don�t rely only on regular expressions and other string handling functions to discard the input, as SQL injection may come in encoded form instead of just plain human readable language.

Another way is getting a snort rule to work for you. However the discussion of snort rules and their implementation is out of the scope of this article. Snort rules help you in the detection of SQL injection intrusions happening in your network. Snort generally sends you an alert or logs the intrusion attempts.

In the next part, I will cover the details of Script injection, how attackers use it and how to prevent them.


Thursday, 10 February 2011

Objects Factory

Introduction

Developing dynamic, flexible, and maintainable applications these days is a neccesary, yet difficult task. Systems grow at exponential rates as companies require more and more advanced logic to run their businesses. The ability of a programmer to understand and maintain such systems diminishes as a systems complexity increases. The creative programmer can come up with ways to combat the difficulties in maintaining a complex system, but often those ways are ignored when new functionality must be developed in a very short time (which, as any programmer who has worked in the corporate world will know, is always the case....time doesn't exist, only the deadline).

There are many ways to make systems extensible. The best way is to take the time up front to design and plan, doing what you can to predict what additions to a system may be neccesary in the future, and plan for them. Quite often, systems are designed with placeholders or hooks that in the future will hold other, already known code. Since a deadline prevents that code from being developed initially, it must be added later on. Since the required functionality is already known, its fairly easy to plan for it and make the system ready for it. Prior knowledge of what future functionality a system may require is not always possible, though.

In the situations where you know the system will need to be extended, but what extensions will be neccesary are not known, the ability to plan for those extensions is greatly reduced. You can't build in fixed placeholders or hooks for the future functionality. If you do build in hooks, they must be generic, capable of loading code without prior knowledge of its inner workings. This article will outline one of the most useful tools for designing extensible systems, regardless of whether the neccesary extensions are already known or not.

Design Patterns

In the last 15-20 years, many innovations and improvements in the way programs, applications, and systems are developed. Old, monolithic, flat systems design has fallen in the face of n-tier systems, object oriented programming, inheritance and polymorphism, modular development, and design patterns. Greater strides in project management have been made to make better use of these better ways of thinking about development. This article focuses on the aspect of Design Patterns, and in particular, a specific pattern called a Class Factory.

Design Patterns arn't as tangible a thing as a class or method. A design pattern is more a way of thinking, about the code you intend to write and how that code will be used in a system. Design patterns help fuel creative thinking when planning all or part of a larger system, and can help save time by providing something of a template to begin working from. There are many design patterns that are well defined and frequently used today. The Facade pattern provides a template that allows one system to communicate with another whithout requiring changes in either. Similarly, the Adapter pattern provides a template that allows one class to talk with one or more classes of different design and communications methods. The Singleton pattern makes it possible to use a single instance of a class anywhere in a system. And the Abstract Factory, similar to the topic of this article, allows the creation and use of classes without knowing all the details of those classes, and without needing to directly instantiate those classes.

The Abstract Factory: Some History

This article will focus on the creation of a Class Factory, which is similar in concept to the Abstract Factory. The definition of an abstract factory is as follows:

"Provide an interface for creating families of related or dependent objects without specifying their concrete classes."

The development of an abstract factory requires a fair amount of forthought and planning to develop the neccesary infrastructure. Numerous classes, both abstract and concrete, are required to allow a client to create and use classes it does not have direct knowledge of. Before providing you with in-depth details of how an abstract factory works, take a moment to examine the following diagram. This diagram outlines the structure and interactions in an abstract class factory system:

The theory behind the Abstract Factory is simply "implicit use", as opposed to explicit use. A class that is marked as abstract is non-instantiable, an implicit representation of all the classes that derive from it. When one of those derived classes is instantiated with new, the class is being "explicitly used". With an abstract factory, the client can implicitly use any classes derived from the abstract products that are producable with the abstract factory. The client does not have explicit knowledge of either ProductA1 or ProductB1, and any additional functionality in those classes not defined in AbstractProductA or AbstractProductB will not be available to the client. MethodA and MethodB can be called, but MethodX and MethodY are unknown to the cleint. The client also never directly uses ConcreteFactory1 or ConcreteFactory2, rather using an abstract instance of their parent class, AbstractFactory.

Collapse
// Abstract Factory  public abstract class AbstractFactory {     public abstract AbstractProductA CreateProductA();     public abstract AbstractProductB CreateProductB(); }  // Contrete Factory #1  public class ConcreteFactory1: AbstractFactory {     public override AbstractProductA CreateProductA()     {         return new ProductA1();     }      public override AbstractProdictB CreateProductB()     {         return new ProductB1();     } }  // Concrete Factory #2  public class ConcreteFactory2: AbstractFactory {     public override AbstractProductA CreateProductA()     {         return new ProductA2();     }      public override AbstractProductB CreateProductB()     {         return new ProductB2();     } }  // Abstract product A  public abstract class AbstractProductA {     public abstract void MethodA(); }  // Abstract product B  public abstract class AbstractProductB {     public abstract void MethodB(); }  // Product A1  public class ProductA1: AbstractProductA {     public override void MethodA()     {         Console.WriteLine("ProductA1.MethodA() Called");     } }  // Product A2  public class ProductA2: AbstractProductA {     public override void MethodA()     {         Console.WriteLine("ProductA2.MethodA() Called");     } }  // Product B1  public class ProductB1: AbstractProductB {     public override void MethodB()     {         Console.WriteLine("ProductB1.MethodB() Called");     } }  // Product B2  public class ProductB2: AbstractProductB {     public override void MethodB()     {         Console.WriteLine("ProductB2.MethodB() Called");     } }  // Client class, consumer of products and   // user of Abstract Factory  public class Client {     public static void Main()     {         AbstractFactory factory;         AbstractProductA prodA;         AbstractProductB prodB;          // Create instances of products from factory A          factory = new ConcreteFactoryA();         prodA = factory.CreateProductA();         prodB = factory.CreateProductB();          prodA.MethodA();         prodB.MethodB();          // Create instances of products from factory B          factory = new ConcreteFactoryB();         prodA = factory.CreateProductA();         prodB = factory.CreateProductB();          prodA.MethodA();         prodB.MethodB();     } }         

The Class Factory: A .NET Improvement

While the Abstract Factory provides a very powerful framework for implicitly instantiating classes, its design is both arbitrary and rigid. The arbitrary nature of Abstract Factory allows the pattern to be used in any object oriented language, and its rigidity is a natural byproduct of that portability. In this article, I'll introduce the Class Factory, a design pattern based on the Abstract Factory, but tuned more to the .NET way of design and thinking. (NOTE: If any other patterns exist with the name "Class Factory" they are likely different than this pattern. This pattern is derived from a task I have had to go several times, and appropriately, I developed a pattern for that task.) The Class Factory will use many core .NET features such as reflection, interfaces, dynamic class creation, etc.

The goals of the Class Factory pattern are similar but also different than those of the Abstract Factory pattern. While the Abstract Factory aims to provide a way to instantiate objects implicityly from a strict class higherarchy, the Class Factory aims to provide a way to instantiate objects dynamically from an arbitrary class pool. Rather than requiring a specific root abstract class or classes, like the Abstract Factory, the Class Factory requires the implementation of one or more interfaces, using interface instances to allow access to each object, rather than an entire class instance. Another difference, and possibly an advantage, of the Class Factory is it requires no prior knowledge of the product classes whatsoever, relying on keys to instantiate classes. The goals of the Class Factory in .NET are:

  • Provide true "oblivious instantiation", where the clients have zero advanced knowledge of the product classes they are using.
  • Allow any class from any class higherarchy, from any location, to be used as a factory product.
  • Use only interface instances, rather than complete class instances, in clients.
  • Offer dynamic discovery, description, and instantiation of product classes.
  • Maintain memory efficiency, global accessability, and simplicity through the Singleton pattern.

The structure of the Class Factory pattern is as follows:

The first thing you will notice is that there are no root abstract classes. The clients make use of one or more interfaces, as well any product class that is to be used within the class factory. The class factory itself implements another design pattern, the Singleton. Only a single instance of the class factory is available, rather than one for each class that may use the factory. (NOTE: If neccesary, the class factory could be created as a normal class, rather than a singleton). One or more create methods are implemented in the class factory, each one returning an instance of the appropriate interface. When the class factory is first created (first call to the Instance property), an internal initialization call is made to dynamically discover available classes at runtime.

The Class Factory pattern in .NET provides more flexability than the Abstract Factory pattern. In an abstract factory, it is neccesary to create concrete classes and factories to perform your class creation, which also requires some prior knowledge at some level of the classes that need to be created. Thanks to an innovation in .NET, and made available in C#, is the concept of an interface. Similar to a class, an interface defines the neccesary functionality that a class must impliment, without the actual implementation. In C#, an interface may be used directly, but can only be instantiated when cast from a class that implements it. This allows the following:

  1. Simpler implementation of required functionality, in either a single class or a class higherarchy. No need to define a complete, abstract root class.
  2. Less rigid class requirements. Since an interface is simply a subset of a classes full "public interface", the requirement of one or more root abstract classes is eliminated.
  3. More than one interface can be implemented in a single class, allowing one class to be used from more than one class factory. This allows theproduct to be used as neccesary in the future.

The Class Factory pattern in .NET performs its object creation using Reflection, based on a key. The Reflection feature of .NET allows types stored in an assembly to be dynamically discovered, probed, and instantiated using the Assembly class, making the goal of true "oblivious instantiation" possible. The use of a key to publicly define, or name, product classes allows them to be discovered and created with the factory in any number of ways. Those ways can easily be extended by adding additional creation methods that use different types of keys to the factory. Depending on how you may need to use the class factory, a single product class can be defined with multiple keys, or may even be defined through some external means, such as an XML factory configuration file.

Through use of several advanced .NET features, and some of .NET's advanced object oriented technologies like interfaces, developing truely extensible systems that can be built modularly, quickly, and without prior knowledge of possible future enhancements, is within the realm of possability. The goals of oblivious instantiation, flexible class higherarchy structure, dynamic discovery and instantiation, and memory efficiency are easily attainable when you have a predefined template to work from.

Implementing the Pattern: ClassFactory class

A design pattern, while at best is just a definition, is quite useless unless its implemented. The Class Factory pattern, while looking somewhat intimidating, is quite simple to implement. This article will develop a theoretical class library that matches the diagram above, to help guide the user through the details of creating all the neccesary parts. As the core component of this pattern is the ClassFactory class itself, we'll start there. After we have developed a shell factory class, and implemented the Singleton pattern, we'll add the neccesary interfaces and product classes. Once those are complete, we'll move on to developing the client classes, and provide some examples as to how the factory can be used.

Before we start the ClassFactory class, you should know a little about the Singleton pattern. This pattern is extremely useful for utility classes or in situations where you need global access to a single object. The ClassFactory is, in essence, a utility class, facilitating the creation of objects by client. A Singleton, while a simple pattern, is difficult to create in most languages. One of the few languages that directly supports the creation of singletons is C#. Take a look at the following code:

Collapse
public class Singleton {     // Static, VOLATILE variable to store single instance      private static volatile Singleton m_instance;          // Static synchronization root object, for locking      private static object m_syncRoot = new object();          // Property to retrieve the only instance of the Singleton      public static Singleton Instance     {         get         {             // Check that the instance is null              if (m_instance == null)             {                 // Lock the object                  lock (m_syncRoot)                 {                     // Check to make sure its null                      if (m_instance == null)                     {                         m_instance = new Singleton();                     }                 }             }                          // Return the non-null instance of Singleton              return m_instance;         }     } }         

You will notice that the instance variable, syncroot object, and Instance property are all static, marking them as classifier-level members, rather than instance members. The instance variable, m_instance, is also marked as volatile, meaning that the .NET runtime guarantees the variable will always be up to date, and is always immediately written from any level of cache back to main system memory. In any multi-threaded environment, a non-volatile variable may be stored in any level of cache, allowing stale instances of that variable to be read from system memory by other threads. In a singleton, there must be no chance that a stale copy of the variable is read from anywhere.

Our class factory is, for memory efficiency and performance purposes, a singleton object. The pattern just described above will also be used in our class factory. When our class factory instance is created, we must initialize the factory, finding and describing all the possible product classes that can be created with it. The initialization routeen uses Reflection to retrieve an instance of the current assembly (the one that contains the currently executing code, which would be the Initialize() method of our ClassFactory class). The Assembly class allows dynamic discovery of all its content through probing the assemblies metadata. The initialization gets a list of all defined types, and checkes each non-abstract class for implementations of the neccesary interfaces. Any classes that implement IFactoryProduct and one or more of the IProductX interfaces will be mapped in the factory by their key. The base ClassFactory class is defined below, without any of its create methods:

Collapse
using System; using System.Collections.Specialized; using System.Reflection;          // ClassFactory singleton  public class ClassFactory {     #region Singleton Pattern     private static volatile ClassFactory m_instance;     private static object m_syncRoot = new object();          public static ClassFactory Instance     {         get         {             if (m_instance == null)             {                 lock (m_syncRoot)                 {                     if (m_instance == null)                     {                         m_instance = new Singleton();                     }                 }             }                          return m_instance;         }     }     #endregion          #region Constructor     private ClassFactory()     {         // Perform variable initializations          m_aProducts = new ListDictionary();         m_bProducts = new ListDictionary();         m_cProducts = new ListDictionary();                  // Initialize the factory          Initialize();     }     #endregion          #region Variables     // Key to type mappings for product creation      private ListDictionary m_aProducts;     private ListDictionary m_bProducts;     private ListDictionary m_cProducts;          // Cached reference to the containing assembly      private Assembly m_asm;     #endregion          #region Methods     // ...      #endregion          #region Helpers     // Find and map available product classes      private void Initialize()     {         // Get the assembly that contains this code          Assembly asm = Assembly.GetCallingAssembly();                  // Get a list of all the types in the assembly          Type[] allTypes = asm.GetTypes();         foreach (Type type in allTypes)         {             // Only scan classes that arn't abstract              if (type.IsClass && !type.IsAbstract)             {                 // If a class implements the IFactoryProduct interface,                  // which allows retrieval of the product class key...                  Type iFactoryProduct = type.GetInterface("IFactoryProduct");                 if (iFactoryProduct != null)                 {                     // Create a temporary instance of that class...                      object inst = asm.CreateInstance(type.FullName, true,                         BindingFlags.CreateInstance, null, null, null, null);                                              if (inst != null)                     {                         // And generate the product classes key                          IFactoryProduct keyDesc = (IFactoryProduct)inst;                         object key = keyDesc.GetFactoryKey();                         inst = null;                                                  // Determine whether the product class implements                          // one or more of the neccesary product interfaces                          // and add mappings for each one thats implemented                          Type prodInterface = type.GetInterface("IProductA");                         if (prodInterface != null)                         {                             m_aProducts.Add(key, type);                         }                                                  prodInterface = type.GetInterface("IProductB");                         if (prodInterface != null)                         {                             m_bProducts.Add(key, type);                         }                                                  prodInterface = type.GetInterface("IProductC");                         if (prodInterface != null)                         {                             m_cProducts.Add(key, type);                         }                     }                 }             }         }                  m_asm = asm;     }     #endregion }         

Once a map of all the available types has been created, that map can be used with a key object to create an instance of the appropriate class. Once the class is created, an instance of the neccesary interface can be retrieved and returned for use by a client class. Below are the threeCreateProductX methods of the ClassFactory class. All three methods use pretty much the same code, with the exception of theListDictionary collection used, and the interface instance returned. At first glance, many might wonder whether the inst created with Assembly.CreateInstance will stick around when the method returns. As long as there is any reference to a reference type in a .NET application, the garbage collector will keep the object in memory. While you are only returning an interface, essentially a subset of the whole inst object, that interface still points to the same object on the heap. Only when the instance of the interface is destroyed will the objects memory be recovered by the garbage collector.

Collapse
public class ClassFactory {     // ...           #region Methods     public IProductA CreateProductA(object key)     {         if (key == null)             throw new NullReferenceException("Invalid key supplied, must be " +
"non-null."); Type type = (Type)m_aProduct[key]; if (type != null) { object inst = m_asm.CreateInstance(type.FullName, true,
BindingFlags.CreateInstance, null, null, null, null); if (inst == null) throw new NullReferenceException("Null product instance. " +
"Unable to create neccesary product class."); IProductA prod = (IProductA)inst; return prod; } else { return null; } } public IProductB CreateProductB(object key) { if (key == null) throw new NullReferenceException("Invalid key supplied, must be " +
"non-null."); Type type = (Type)m_bProduct[key]; if (type != null) { object inst = m_asm.CreateInstance(type.FullName, true,
BindingFlags.CreateInstance, null, null, null, null); if (inst == null) throw new NullReferenceException("Null product instance. " +
"Unable to create neccesary product class."); IProductB prod = (IProductB)inst; return prod; } else { return null; } } public IProductC CreateProductC(object key) { if (key == null) throw new NullReferenceException("Invalid key supplied, must " +
"be non-null."); Type type = (Type)m_cProduct[key]; if (type != null) { object inst = m_asm.CreateInstance(type.FullName, true,
BindingFlags.CreateInstance, null, null, null, null); if (inst == null) throw new NullReferenceException("Null product instance. " +
"Unable to create neccesary product class."); IProductC prod = (IProductC)inst; return prod; } else { return null; } } #endregion // ... }

Implementing the Pattern: Support Facilities

In addition to the ClassFactory itself, several interfaces and all the product classes must be implemented. We'll create the neccesary interfaces first. In C# (and .NET in general), an interface is like a class, but much simpler. Interfaces can not have constructors, and the methods defined in them can not be implemented. Very similar to a function prototype in C/C++, a definition before implementation. Any class that implements the interface must include it in its inheritance list.

Collapse
// IFactoryProduct Interface, provides a means  // for the class factory to retrieve a classes  // mapping key  public interface IFactoryProduct {     object GetFactoryKey(); }  // IProductA Interface  public interface IProductA {     void MethodA(); }  // IProductB Interface  public interface IProductB {     void MethodB1();     string MethodB2(); }  // IProductC Interface  public interface IProductC {     void MethodC(string msg); }         

As you can see, the interfaces are quite simple. Implementing them is nearly as simple, and the explicit implementation can differ as neccesary between classes. Below are the implementations of all the products specified in the Class Factory diagram above. For the purposes of this article, we will use a floating point key for all of the product classes. Each class will only perform a Debug.WriteLine, but in a practical situation, the methods would perform some sort of useful operations on input data, or would output some kind of result based on a variety of criteria.

Collapse
// Product A1  public class ProductA1: IFactoryProduct, IProductA {     public ProductA1()     {     }          #region IFactoryProduct Implementation     public object GetFactoryKey()     {         return 1.0f;     }     #endregion          #region IProductA Implementation     public virtual void MethodA()     {         Debug.WriteLine("ProductA1.MethodA() was called!");     }     #endregion }  // Product A2,B  public class ProductA2B: ProductA1, IFactoryProduct, IProductA, IProductB {     product ProductA2B()     {     }          #region IFactoryProduct Implementation     public object GetFactoryKey()     {         return 1.1f;     }     #endregion          #region IProductA Implementation     public override void MethodA()     {         Debug.WriteLine("ProductA2B.MethodA() was called.");     }     #endregion          #region IProductB Implementation     public virtual void MethodB1()     {         Debug.WriteLine("ProductA2B.MethodB1() was called.");     }          public virtual string MethodB2()     {         return "ProductA2B.MethodB2() was called.");     }     #endregion }  // Product B  public class ProductB: IFactoryProduct, IProductB {     public ProductB()     {     }          #region IFactoryProduct Implementation     public object GetFactoryKey()     {         return 1.2f;     }     #endregion          #region IProductB Implementation     public virtual void MethodB1()     {         Debug.WriteLine("ProductB.MethodB1() was called.");     }          public virtual string MethodB2()     {         return "ProductB.MethodB2() was called.");     }     #endregion }  // Product C  public class ProductC: IFactoryProduct, IProductC {     public ProductC()     {     }          #region IFactoryProduct Implementation     public object GetFactoryKey()     {         return 1.3f;     }     #endregion          #region IProdctC Implementation     public void MethodC(string msg)     {         Debug.WriteLine("ProductC.MethocC()::Printing: " + msg);     }     #endregion }  // Product A, B, C  public class ProductABC: IFactoryProduct, IProductA, IProductB, IProductC {     public ProductABC()     {     }          #region IFactoryProduct Implementation     public object GetFactoryKey()     {         return 1.4f;     }     #endregion          #region IProductA Implementation     public override void MethodA()     {         Debug.WriteLine("ProductABC.MethodA() was called.");     }     #endregion          #region IProductB Implementation     public virtual void MethodB1()     {         Debug.WriteLine("ProductABC.MethodB1() was called.");     }          public virtual string MethodB2()     {         return "ProductABC.MethodB2() was called.");     }     #endregion          #region IProdctC Implementation     public void MethodC(string msg)     {         Debug.WriteLine("ProductABC.MethodC()::Printing: " + msg);     }     #endregion }         

The important thing to notice here is any class can become a product of the factory. Provided the class implements the neccesary interfaces, it can be a lone class, part of a class higherarchy. The class can reside locally, or in another assembly, or can be spread out accross multiple assemblies. The class factory could even be extended to allow dynamic discovery of remote services, such as web services, remoting objects, etc. There are no required base abstract classes, so any class anywhere can become a product of the class factory, making it very flexible, and 100% dynamic.

Implementing the Pattern: Client Classes

Now that we have the framework of our class factory in place, we need to develop some clients to make use of it. In a real-world situation, you will most probably have an existing system that needs to be extended. That system will have certain rules that gouvern it, certain patterns that repeatedly appear. Every system processes data, each one in a unique way. For the purposes of this article, lets assume our pre-existing system is a simple number processing system. Our clients will process floating point numbers, and depending on the number, different things should happen. We can process each number in a standard way in the client class itself, but in the future, custom actions may be neccesary when certain numbers are encountered. We design our system with a default handler built into the client class, and allow future extensability through a class factory (which we just built).

We will build two clients, for this example. Our class factory is a singleton, which allows a single global instance to be used from anywhere. Our first client, ClientX, uses products A and C, while our second client, ClientY, uses products B and C. The two clients only know about the products, and require no detailed knowledge about the classes they will be using. When certain numbers are processed, the clients will call the class factory with the current number as the key, retrieving a product, or a null if no product exists. Depending on the current number, different classes will be instantiated when a product is retrieved, or possibly none, if there is no class with a matching key.

Collapse
// Client Class X  public class ClientX {     #region Constructor     public ClientX(float start, float end)     {         m_start = start;         m_end = end;             }     #endregion          #region Variables     private float m_start, m_end;     #endregion          #region Methods     public void Process()     {         ClassFactory fact = ClassFactory.Instance;                  for (float cur=m_start; cur <= m_end; cur += 0.1)         {             Debug.WriteLine("ClientX: Processing number " + cur.ToString());                          IProductA prodA = fact.CreateProductA(cur);             if (prodA != null)             {                 prodA.MethodA();             }             else             {                 Debug.WriteLine("Default processing performed on number "
+ cur.ToString()); } IProductC prodC = fact.CreateProductC(cur); if (prodC != null) { prodC.MethodC("Floating-point number " + cur.ToString() +
" has been logged."); } } } #endregion } // Client Class Y public class ClientY { #region Constructor public ClientY() { } #endregion #region Methods public void Process(float Max) { float cur = 1.0; ClassFactory fact = ClassFactory.Instance; while (cur <= Max) { Debug.WriteLine("ClientY: Processing number " + cur.ToString()); IProductB prodB = fact.CreateProductB(cur); if (prodB != null) { prodB.MethodB1(); Debug.WriteLine("Result from ProductB.MethodB2(): " +
prodB.MethodB2()); } else { Debug.WriteLine("Number " + cur.ToString() +
" was not processed."); } IProductC prodC = fact.CreateProductC(cur); if (prodC != null) { prodC.MethodC("Floating-point number " + cur.ToString() +
" has been logged."); } cur += 0.1; } } #endregion }

Now that we have the class factory, we can add product classes for any floating point number. We currently have products for numbers 1.0-1.4, but that range could be expanded to cover 1.0-2.0, 0.0-50.0, whatever is neccesary. The extensability of our floating point processing clients is now endless, and can easily and readily be extended at any time. The power of a class factory is expansive, and can help simplify large projects into smaller, more manageable parts.

Points of Interest

This article introduced a new design pattern, the Class Factory, and explained its usefulness in a practical environment. So far, you have seen what the Class Factory is, and how to implement it in a very simple, basic environment. While the example provided covers all the details, there are many more possabilities with this pattern that have yet to be explored. The example provided works in a single-threaded environment, and workes with a single key per product class. That provides flexability for the example depicted, but it may not be flexible enough for every system.

To extend this pattern so it works in a multi-threaded environment, a small and simple addition to the ClassFactory class will suffice. We already have a synchroniztion root object, the static m_syncRoot variable. Adding a SyncRoot property to the class will allow lock() to be called on the instance of ClassFactory, from any thread before calling a Create method. Since lock is a blocking call, only one thread at a time can retrieve a product. The example below depicts:

Collapse
public class ClassFactory {     private static object m_syncRoot = new object();          // ...           public object SyncRoot     {         get { return m_syncRoot; }     }          // ...  }  // ...   ClassFactory fact = ClassFactory.Instance; IProductA prodA; lock (fact.SyncRoot) {     prodA = fact.CreateProductA(); }  // ...          

Another change that can be made to the pattern is the use of multiple keys for each product. This can either be a simple matter of changing the IFactoryProduct interfaces method, object GetFactoryKey(), to object[] GetFactoryKeys(). If hard-coded key mappings are not what you need for your project, its easy enough to develop an external XML format to describe keys, assembly locations, and more to product classes. The Initialize routeen of the class factory would then load and process the xml file, finding all the neccesary types based on their assembly locations (i.e. the path to a .dll, web service locations, etc.).

The class factory can also be extended to provide not only instantiated objects, but also information about the objects, or even more detailed knowledge about the actual class that implemented the interface. It all depends on your needs, the existing system, what kinds of new functionality the system needs, and how you map keys to products. The usefulness of a class factory extends beyond just providing easy extensability to existing systems. New systems or applications can be designed eith class factories in mind from the start, building in an innate extensability. Class Factories can be used as the core element of a plugin system for an application, too (see http://www.datgen.info/ for a practical example of a program I've written that makes use of class factories for the programs plugin and dynamic type system).

Ultimately, class factories provide a level of application or system extensability that is otherwise not possible. The use of interfaces, rather than explicit abstract classes, makes the class factory an extremely flexible pattern. Implementation of a required interface in a previously existing class immediately makes that class available through the class factory as a product, allowing already existing functionality to be integrated with the system in question. The system itself requires minimal modification, and the goal of true oblivious instantiation is possible. Disconnected and uninformed execution of dynamically discovered code is now within the realm of reality.

History

This article is largely conceptual in topic, and will probably have few updates. For those who like to see a changelog, though, here ya go:

  • January 16, 2005 - Initial Article Version, Class Factory for .NET

License

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

About the Author