Homam's Mind

Friday, May 29, 2009

Service Provider Pattern Part II

Read the first part

At first I found it is generally a good advice to store the configuration in a static, read-only property somewhere. And there's no better place other than the configuraiton class itself:
static MyServicesConfigurationSection _Value;
public static MyServicesConfigurationSection GetValue()
{
if (_Value == null)
{
_Value = (MyServicesConfigurationSection)
System.Configuration.ConfigurationManager.GetSection("myServices");
}
return _Value;
}

Here we assume that we always define the matching element to be "myServices" in the configuration file. It makes sense because it makes it easier for us to find the element in different configuration files. We can always access the value using:
var config = Configuration.MyServicesConfigurationSection.GetValue();

Modularizing is the obvious upgrade we are goging to make to the Service Provider Pattern Part I. I can find three distinct components:

Service-Provider-Pattern-Ar 

  • Service Provider Pattern contains all the logic required by the pattern to work. You alway reference it everywhere you want to use the pattern.

  • Service Definitions is where we define our services.

  • Implementation of the Services contains  concrete classes and implementations of (some of) the services that have been defined in Service Definitions module. In a real application you may end up with many Implementation components each containing the implementation of a one or few number of services.


As before the configuration file of the Host Application maps the definitions (abstract services) to implementations (concrete services).

It's clear that using this architecture we can have host applications that are hosting different implementations of the services.

Configuring the Services


Till now the only purpose of the configuration file was to store the mapping between the definitions and the implementations. But we can use it in order to actually configure the services. For an example it's very likely that the FTPFileStorageService that we defined in the previous part, needs a FTP account credential to work. In this case the <add> element (that maps FileStorageService to FTPFileStorageService) may look like:
<add def="MyServiceDefinitions.FileStorageService"
impl="MyServiceImplementations.FTPFileStorageService,
MyServiceImplementations
"
host="ftp://ftp.wingooli.com" username="wingooloi"
password="password" />

Both the abstract service definition and the concrete implementation can implement IServiceBase interface:
public interface IServiceBase
{
void Initialize(Configuration.ServiceProviderSettings settings);
}

This interface just has one method, Initialize, that takes a ServiceProviderSettings (the <add> element). We can read the additional attributes of the <add> element using a code like this:
settings.Properties["host"]

The logics in the Service Provider Pattern component automatically call the Initialize method if this interface has been implemented in the definition the  implementation of the service.

Here is the design:

Service-Provider-Pattern

Now our Service Provider Pattern has nothing less than ASP.NET Provider Pattern but it is easier to implement.

Using all these modules we can reduce the code needed to instantiate a service (this code snippet should be placed in the abstract service definition class):
static FileStorageService _Instance;
static object _InstanceLocker = new object();
public static FileStorageService Instance
{
get {
if (_Instance == null) {
lock (_InstanceLocker) {
_Instance = ServiceModel.ServicesHelper
.GetServiceInterface<FileStorageService>();
}
}
return _Instance;
}
}

Because it is a repeatable pattern and to make it all more developer friendly, I created a C# code snippet that generates a similar code automatically.

You can download the whole things here.

2 comments:

Service Provider Pattern, Part I « Abstract form said...

[...] Comment! Read the Second and final part [...]

Shameem Chowdhury said...

I never knew how much information there was on the internet about this!

Thank you for making this all simple to grasp