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-–
- What is Provider Design Pattern?
- Walkthough: Using Provider Pattern
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.
This class is responsible for communicating with the physical persistence media.
PersistenceManager has only two jobs.
public static void Save<T>(T obj)
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 (
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–
- API class (
PersistenceManager) to publish API(
get). It is also responsible to instantiate a ConcreteProvider depending on the configuration.
- Domain specific Abstract Provider (
PersistenceProviderBase) a.k.a. Application ProviderBase inherited from ProviderBase class of
- ConcreteProviders (
SqlPersistanceProvider) inherited from domain specific Abstract Provider.
- Custom Configuration Section to configure the Providers and a class inherited from
ConfigurationSectionto represent it in .Net.
The following diagram shows different parts of provider design pattern that we intend to discuss one by one.
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:
Following is an example of the custom section for the Persistence Provider.
Important attributes to note here:
- Indicates the default ConcreteProvider.
- 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 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.
Get method of
PersistenceManager is described next.
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).
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-
IPersistenceProvider, which describes the API exposed by
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,
Initialize() is used to initilize providers.
PersistenceProviderBase is the mirror of API or services that ConcreteProvider facilitates.
As shown below, two
PersistenceProviderBase and provides implementation of
Get specific to the context of a particular provider.
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
To illustrate initilization of a ConcreteProvider, we show following snapshot taken from the debug-mode.
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.
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.
If requires, any additional provider can simply be added by extending any ConcreteProvider, or by implementing
IPersistenceProvider, as shown below.
As in other providers, this new provider can also be configured during run-time as follows.
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!
[R-1: 04-04-2013] Porting this blog-post from its weblogs.asp.net page.