In a recent post I was wondering how one can do a lookup for the current implementation of an object service. Armand pointed me to the Spring.NET framework (a port of the Java Spring framework). Following here is a quick example of how I used it. (The framework can do a lot more than what I show here - it has a complete dependancy injection/container framework for example)
First thing is to download and extract the zip file, compile the source and reference the Core and Context namespaces in your project.
Continuing with my Logger example you can declare an interface for your service :
namespace Tester
{
public interface ILogger
{
string logStuff(string stuff);
}
}
Then we update our projects .config file to point to the current implementation:
<configSections>
<section name="objects" type="Spring.Context.Support.ApplicationContextHandler,Spring.Context"/>
</configSections>
<objects>
<object name="Tester.ILogger" class="Tester.MyLogger,Tester">
<constructor-arg index="0">
<value>c:\Bla.txt</value>
</constructor-arg>
</object>
</objects>
This basically says that the class MyLogger is the current implementation for ILogger. Note that the name of the object could have been any unique string, but I prefer the class name, it's more useful. Here is the MyLogger class:
namespace Tester
{
public class MyLogger : ILogger
{
private string _file;
public MyLogger(string file) { _file = file; }
public string logStuff(string stuff)
{
//log the stuff to the file here
}
}
}
The idea is that if we don't want to log to the file anymore, we can just create our new class(for example to log to the application log), make it implement ILogger and then change the config file to the new implementation. [We would also need to remove the constructor-arg tag from the config file].
It goes without saying that the rest of your code should only use the interface.
Here is how your code would get a reference to the current implementation.
IApplicationContext ctx = (IApplicationContext) ConfigurationSettings.GetConfig("objects");
ILogger log = (ILogger)ctx.GetObject("Tester.ILogger");
log.logStuff("hello logger");
As you can see, we've achieved complete seperation between the interface and the current implementation.
you can also wrap the service lookup generically with a method like this:
public class ServiceLookup
{
protected ServiceLookup() { }
public static object getService(Type serviceType)
{
IApplicationContext ctx = (IApplicationContext) ConfigurationSettings.GetConfig("objects");
return ctx.GetObject(serviceType.ToString());
}
}
Then if you have a bunch of services define, you can access them like this:
ILogger log = ServiceLookup.getService(typeof(ILogger));
If you want to share an implemenation object across a process (note: not a thread or web request) you can make it a singleton, which will force Spring to create one instance an the return that same instance every time it is requested. You do this in the config file:
<object name="Tester.ILogger" class="Tester.MyLogger,Tester" singleton="true" />