.Net Provider Pattern – Designing decoupled and extensible Component for .Net Application

Provider design pattern of .Net Framework 2.0 facilitates an approach to design components in a decoupled and extensible manner. In this post, we investigate this design pattern, and show how we can utilize it to make components decoupled while providing extension points for configuration. To do so, we present the outline of today’s discussion as follows-–

Outline

  1. What is Provider Design Pattern?
  2. Walkthough: Using Provider Pattern

  3. Advantages
  4. Conclusion

What is Provider Design Pattern?

Provider pattern is a way in .Net Framework 2.0 to design extensible and decoupled Component. Ron Howard mentioned –

“A provider is simply a contract between an API and the Business Logic/Data Abstraction Layer. The provider is the implementation of the API separate from the API itself.”

Provider pattern is a way to get rid of the coupling among the components while making the components extensible. Main reason for our today’s discussion on Provider Pattern is its wonderful ability to publish the API and at the same time make the API pluggable; that is– it gives us the flexibility to choose the API that is best suited for the application rather than the one developed by API developer. And from an API developer perspective, it allows them to create an extension point for the API where clients of the framework can extend the functionality in their own way.

In the next section, we walk-through an example, which builds a component using provider design pattern.

Provider Pattern in Action

The basic idea behind the provider pattern is to have multiple ConcreteProviders and selecting one of them depending on configuration (just a change in ‘*.config file can lead to completely different provider to perform the operation) at the runtime by avoiding writing huge amount of code and coupling among the components. Provider pattern completely abstract the decision of which provider to use out of programming interface. That way we can say that, it has some kind of dependency injection/inversion flavor, but it does not use any kind of container like Windsor or Spring.net.

We first consider a simple and contrived problem (designed only for illustrative purpose), which is used throughout today’s discussion. We have the following simple domain object: User and we need a persistence media to store(/Save) and retrieve(/Get) it.

User class

This class is responsible for communicating with the physical persistence media. PersistenceManager has only two jobs.

  1. public static void Save<T>(T obj)
  2. public static T Get<T>()

Consider that this implementation as of now only supports two persistence media: SQL Server2005 and Xml (via File system). Depending on the clients’ need, we will be using any one of them at the runtime, keeping in mind that in future client might use some other persistence media like Oracle, mySql or whatever.

If we are not familiar with provider pattern, we would solve this problem using any dependency injection container (e.g. Windsor/Spring.Net/Unity), or introducing factory method to instantiate the desired component at the runtime; that is, either we had to introduce new code (write and manage) or new vocabulary to grasp (with dependency injection container) while providing custom solution. Truly that would be an overhead if we would like to solve only this problem. Then, why do we not use something from .Net2.0 when it is providing it (e.g. as in Asp.net Membership)?

A solution with .Net provider design pattern consist of following basic parts–

  1. API class (PersistenceManager) to publish API(save and get). It is also responsible to instantiate a ConcreteProvider depending on the configuration.
  2. Domain specific Abstract Provider (PersistenceProviderBase) a.k.a. Application ProviderBase inherited from ProviderBase class of System.Configuration.Provider namespace.
  3. ConcreteProviders (XmlPersistenceProvider and SqlPersistanceProvider) inherited from domain specific Abstract Provider.
  4. Custom Configuration Section to configure the Providers and a class inherited from ConfigurationSection to represent it in .Net.

The following diagram shows different parts of provider design pattern that we intend to discuss one by one.

Basic parts of Provider Design pattern

We begin with a custom Configuration section.

Custom Configuration Section

In order to make the provider pattern pluggable and flexible, evidently we have to devise a wat to configure the providers at the runtime. Application configuration via .config is probably the best approach to link communication between the available providers and configuration.

To achieve this, we need to add a class inherited from ConfigurationSection to handle the configuration of providers:

Class to store custom Configuration Section

Following is an example of the custom section for the Persistence Provider.

<PersistenceProvider defaultProvider="XmlPersistenceProvider">
<providers>
<add name="XmlPersistenceProvider" type="ProviderPattern.XmlPersistenceProvider, ProviderPattern" PersistenceMediaConnectionString="C:\PersistenceMedia\DocumentInfos.xml"/>
<add name="SqlPersistenceProvider" type="ProviderPattern.SqlPersistenceProvider, ProviderPattern" PersistenceMediaConnectionString="[Your database connection string]"/>
</providers>
</PersistenceProvider>

Important attributes to note here:

defaultProvider:
Indicates the default ConcreteProvider.
PersistenceMediaConnectionString:
Defined to provide extra information needed to the Concrete Provider. For example , XmlPersistenceProvider will save the information about the domain object in the path specified and SqlPersistenceProvider use the value specified as the connection string to the database.

We can also define other attributes as required, which can be used to initialize the ConcreteProvider (e.g. logFilePath). Benefit of such approach is that we can return to this custom configuration, and change ConcreteProvider at the runtime.

Next we move on to explore the PersistenceManager class whose responsibility is to initialize the ConcreteProvider depending on the configuration section and publish the APIs.

PersistenceManager

PersistenceManager is the major gateway to the concrete provider as I mentioned earlier that it communicates directly with the underlying persistence media using one of the concrete provider to perform the operation (e.g. Save/Get) that it exposes.

Save method of PersistenceManager is outlined as follows.

public static void Save<T>(T obj){
if (DefaultProvider == null){
Instantiate(
PersistenceProviderConfigSection.GetPersistenceConfigSection());
}
DefaultProvider.Save<T>(obj);
}
view raw save.cs hosted with ❤ by GitHub

Get method of PersistenceManager is described next.

public static T Get<T>(){
if (DefaultProvider == null){
Instantiate(PersistenceProviderConfigSection.GetPersistenceConfigSection());
}
return DefaultProvider.Get<T>();
}
view raw get.cs hosted with ❤ by GitHub

If we look at the PersistenceManager closely, the static Instantiate method, that instantiate the provider based on the Configuration from PersistenceProviderConfigSection. In order to do that, we use a built-in support feature of the .Net Framework2.0, which is core to this desing pattern: we will use ProvidersHelper class of System.Web.Configuration namespace. The ProvidersHelper.InstantiateProviders method initializes the ConcreteProviders by calling the Intialize() method of the ConcreteProviders (we come back to this point in the next section again).

private static void Instantiate(PersistenceProviderConfigSection configSection){
if (Providers == null)
SetupProvider(configSection);
}
private static void SetupProvider(PersistenceProviderConfigSection config){
if (config == null)
throw new Exception("PersistenceProvider are not configured to be used with this application");
Providers = new PersistenceProviderCollection();
ProvidersHelper.InstantiateProviders(config.Providers, Providers, typeof(PersistenceProviderBase));
DefaultProvider = Providers[config.DefaultProvider] as PersistenceProviderBase;
}
view raw Instantiate.cs hosted with ❤ by GitHub

Therefore, the DefaultProvider property in PersistenceManager always refers to the default ConcreteProvider specified in the configuration. Another alternative is to use reflection to instantiate ConcreteProvider.

Now, we describes the details of the ConcreteProvider, and how it gets initialized when we call ProvidersHelper.InstantiateProviders(config.Providers, Providers, typeof(PersistenceProviderBase)).

Application ProviderBase and Concrete Providers

In short, Application ProviderBase class or Domain-specific ProviderBase provides the abstract version of the functionality exposed by the API class, and the responsibilities of the ConcreteProviders is to implement those API in their own way. As we can see next figure, our Application ProviderBase- PersistenceProviderBase implements IPersistenceProvider, which describes the API exposed by PersistenceManager class.

PersistenceProviderBase

ProviderBase class belongs to System.Configuration.Provider namespace, which contains all the member to be implemented by the ConcreteProviders. It contains properties to describe ConcreteProviders, such as, Name and Description. Initialize() is used to initilize providers. PersistenceProviderBase is the mirror of API or services that ConcreteProvider facilitates.

As shown below, two ConcreteProviders extends PersistenceProviderBase and provides implementation of Save and Get specific to the context of a particular provider.

ConcreteProviders and their members

In addition to that, in Initalize() method, concrete providers also initialize associated properties configured through web.config. For instance,

  • _PersistenceMediaPath of the concrete providers will be initialized with the value ofPersistenceMediaConnectionString from web.config.
  • Name and Description will be initialized.

Following code outlines the initialization process of SqlPersistenceProvider.

public override void Initialize(string name, NameValueCollection config)
{
name = string.IsNullOrEmpty(name) ? "SqlPersistanceProvider" : name.Trim();
base.Setup("SqlPersistanceProvider", "SqlPersistanceProvider saves the T to SQL DB", config);
_PersistenceMediaPath = config[PersistenceMediaPathKeyName];
//Call the base class to initialize
base.Initialize(name, config);
}
view raw init.cs hosted with ❤ by GitHub

To illustrate initilization of a ConcreteProvider, we show following snapshot taken from the debug-mode.

init of a concrete provider

After initialization, we are only left with the Provider-specific implementation of the abstract functionality of the PersistenceProviderBase, i.e., Save/Get. Every provider will implement in their own way. For instance, if we consider XmlPersistenceProvider, it will implement the Save/Get method as follows, whereas, SqlPersistenceProvider typically stores and retrieves from Sql Server.

public override void Save<T>(T obj)
{
string serailzedObj = SerializeHelper.Serialize(obj);
File.WriteAllText(_PersistenceMediaPath, serailzedObj);
}
public override T Get<T>()
{
string stringContent = File.ReadAllText(_PersistenceMediaPath);
if (!String.IsNullOrEmpty(stringContent))
return ((T)SerializeHelper.Deserialize(typeof(T), stringContent));
return default(T);
}

Advantages

Why would we adopt provider design pattern?– To create loosely coupled components that are extensible from an application perspective.

Revisiting custom ConfigurationSection we have implemented, we set XmlPersistenceProvider as the default PersistenceProvider. If we want to use SqlPersistenceProvider we can simply change in the value of the defaultProvider in the web.config file and our client can start using the SqlPersistenceProvider at runtime.

<PersistenceProvider defaultProvider="SqlPersistenceProvider">
<providers>
<add name="XmlPersistenceProvider" type="ProviderPattern.XmlPersistenceProvider, ProviderPattern" PersistenceMediaConnectionString="C:\PersistenceMedia\DocumentInfos.xml"/>
<add name="SqlPersistenceProvider" type="ProviderPattern.SqlPersistenceProvider, ProviderPattern" PersistenceMediaConnectionString="[Your database connection string]"/>
</providers>
</PersistenceProvider>

If requires, any additional provider can simply be added by extending any ConcreteProvider, or by implementing IPersistenceProvider, as shown below.

MySqlPersistenceProvider

As in other providers, this new provider can also be configured during run-time as follows.

<PersistenceProvider defaultProvider="MySqlPersistenceProvider">
<providers>
<add name="XmlPersistenceProvider" type="ProviderPattern.XmlPersistenceProvider, ProviderPattern" PersistenceMediaConnectionString="C:\PersistenceMedia\DocumentInfos.xml"/>
<add name="SqlPersistenceProvider" type="ProviderPattern.SqlPersistenceProvider, ProviderPattern" PersistenceMediaConnectionString="[Your database connection string]"/>
<add name="MySqlPersistenceProvider" type="ProviderPatternExplored.MySqlPersistenceProvider, ProviderPatternExplored" PersistenceMediaConnectionString="[Your my sql database connection string]"/>
</providers>
</PersistenceProvider>

Conclusion

In this post, we have shown how we can utilize .net provider design pattern to make a component loosely couple and extensible. Note that in the example implementation, we have used ProvidersHelper class of System.Web,Configuration while building the component. However, we can easily get rid of adding reference to System.Web namespace, by implementing ProvidersHelper class; alternatively reflection can be used during instantiation of concrete providers.

We highly appreciate any question or query regarding this post. Thanks!


Revision

[R-1: 04-04-2013] Porting this blog-post from its weblogs.asp.net page.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: