NAVmoble - the pocket-sized ERP
Optimized for Microsoft Dynamics NAV and Windows Mobile powered devices

Wednesday, April 06, 2005

Service Locator pattern and .NET

Introduction
One way to break the dependency between 2 classes is to use Service Locator pattern. Recently I had a post about Dependency Injection and .NET. I pointed out, that one of the ways to break the depndency between 2 classes is to use the built-in capabilities of the .NET framework to create lightweight containers. Let us try to implement a simple container using the classes and interfaces from the System.ComponentModel namespace

Implementation
Sample source code may be downloaded from here
First, we have to define our problem. Lets say, we need to imlpement a class to process some data. This class is named ServiceConsumer. We want our ServiceConsumer to have the ability to consume data from diffeent sources like emails and files. In order to decouple our ServiceConsumer class from the actual source data fetching, we will declare an interface called
ICommonService
. We will imlpement two versions of ICommonService called EmailService and
FileService
.


The ServiceConsumer class imlpementation looks like this:

1  public class ServiceConsumer:Component
2 {
3 public ServiceConsumer():base()
4 {
5 }
6 public void Process()
7 {
8 ICommonService service=
9 (ICommonService)GetService(typeof(ICommonService));
10 service.Execute();
11 }
12 }
  • ServiceConsumer inherits System.ComponentModel.Component. This way our Consumer may be embeded into containers.
  • Line 8 invoke Component.GetService method in order to obtain implementation of ICommonService - note that our consumer class does not depend on the actual service implementation

Now, we want to write the code to instantiate our actual service implementation. We'll do it smarter by using the configuration namesapce of the .NET framework. First, we will create our application xml configuration file:

<configuration>
<appSettings>
<add key ="ServiceLocatorSample.ICommonService"
value="ServiceLocatorSample.EmailService" />
</appSettings>
</configuration>

Following the implementation of our container. In the sake of simplicity our container contains the code to deal with the actual service implementation. It reads our configuration file and create the proper service instance.

1 public class ConfigurableContainer:Container

2 {
3 public ConfigurableContainer():base()
4 {
5 }
6 protected override object GetService(Type service)
7 {
8 string implementationTypeName =
9 ConfigurationSettings.AppSettings[service.FullName];
10 Type actualType = Type.GetType(implementationTypeName);
11 if(actualType!=null)
11 {
12 return Activator.CreateInstance(actualType);
13 }
14 return base.GetService(service);
15 }
16 }
  • Our ConfigurableContainer inherits System.ComponentModel.Container
  • Lines 8 and 9 fetch the service implementation type name from the configuration file
  • Line 12 creates the service instance
  • In real world scenario, we should have additional exception handling code
And finally, we will wrap up everything:
1  string consumerName = "consumer1";
2 containter = new ConfigurableContainer();
3 ServiceConsumer consumer = new ServiceConsumer();
4 containter.Add(consumer,consumerName);
5 ServiceConsumer myConsumer =
6 ((ServiceConsumer)containter.Components[consumerName])
7 myConsumer.Process();

  • line 2 creates an instance of the container
  • line 3 creates an instance of the Service Consumer and adds it to the
    containers' components list. This way our component is automatically binded to
    the containers service instantiation code
  • lines 5 and 6 demonstrate the usage of the Service Consumer instance.
  • Note, that this code snipset is not depenedent on the actual service implementation

Conclusion
What are the benefits of using lightweight containers in .NET :

  • Maximize class decoupling, e.g. better design
  • Easier code maintainance -if we want to add additional service implementation,
    we need to implement a new class and modify our configuration file.
  • Maximize reusability - our component(ServiceConsumer) may be used by other
    developers and they don't need to know detaisl about the service creation
    process.
  • Creating complex agile plug-in archtiectures based on proved standards is
    eaiser.
This sample is to demonstrate a basic way to implement lightweight container in .NET. In a real world scenario, we may have more complex container architecture. We may use layered containers(implementing a chain of responsibility) , service containers,more complex configuration, etc.

Unit testing
To be continued...

No comments: