Tuesday, February 10, 2009

Dependency Injection by configuration

In an effort to get better at applying the Dependency Injection pattern in my "framework" for data access separation I looked at a way to move out of the code the reference to the assembly and classes that implement the data session interfaces.

You can read my article at CodeProject to get the details about the interfaces I use to define data access services. In short, I have a ISession interface that is both an Abstract Factory and a Facade to methods that persist and retrieve objects.

The pattern is similar to the Service locator pattern as defined by Martin Fowler.

The data access assembly contains classes that implement the ISession interface and the interfaces for data access for the single entities. Instead of referencing this dll directly in my application model assemblies the file location is specified in the app.config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DALDllFilePath"
value="C:\PathToTheDalDll\Dal.dll"/>
</appSettings>
</configuration>

Then reflection can be used to load the assembly and instantiate the ISession concrete implementation without adding a reference to the assembly containing it. This approach, though, can be expensive in terms of performance, since instantiating object and calling methods through reflection can be substantially slower then doing it directly in code.

We can get around performance issues by performing reflection just once by using a singleton object. Doing reflection just in the static constructor ensures that it is done only once at the first reference to the singleton.

We also need a static method that returns an object implementing the ISession interface.

So we need to initialize and store in the singleton an instance of a factory object implementing the interface shown below.

public interface ISessionFactory
{
ISession GetSession();
}

Having an object implementing this interface in the singleton instance enables us to define a static method that executes GetSession() and returns the ISession concrete implementation to the caller.

The static constructor will load the assembly located at the path retrieved from the config file, search for a class implementing ISessionFactory, instantiating it and storing it in a private field (sessionFactory). The code will be something like:
  
internal class sessionDI
{
private static readonly sessionDI instance = new sessionDI();
ISessionFactory sessionFactory;

static sessionDI()
{
}

private sessionDI()
{
Assembly dalSessionAssembly = Assembly.LoadFile(
System.Configuration.ConfigurationSettings.AppSettings
["DALDllFilePath"]);

Type[] allTypes = dalSessionAssembly.GetTypes();

foreach (Type type in allTypes)
{
if (type.IsClass && !type.IsAbstract)
{
Type iSessionImplementer
= type.GetInterface("ISessionFactory");
if (iSessionImplementer != null)
{
this.sessionFactory =
dalSessionAssembly.CreateInstance(type.FullName)
as ISessionFactory;
}
}
}
if (this.sessionFactory == null)
throw new ApplicationException("Configuration error");
}

internal static ISession GetSession()
{
return instance.sessionFactory.GetSession();
}
}


The GetSession() singleton static method will simply call the GetSession() method of the sessionFactory object singleton instance loaded at singleton construction.