Saturday, October 25, 2008

Provider Model Design Pattern – Implementation in C#

Download Provider Model C# code

The Provider Model is a design pattern allowing your application to work with different implementation to the same problem.  This makes your application extensible and can easily work with various ways of interacting with a set of data through configuration.

An example would be to allow your application to work with data existing in an MS SQL, MySQL, and XML data.  Your application will interact with each of these set of data through a particular provider.  The great thing about this is that your application is extendible by others now.  For instance another developer could code an Pointbase provider.

The following class diagram shows the classes implemented:

ClassDiagram1

Overview

There are at least 6 files that need to be created/modified to fully implement a provider model in your application.

Configuration file

There is no difference between the configuration between a web-based application or a windows-forms.

Provider Configuration

This class provides access to the provider settings collection of data.  Each provider setting is information about your data provider such as Name, Type and various parameters.  This class is usually used only the Provider manager however in my example, I’m providing direct access to the provider settings collection through a property in the provider manager.

Provider Collection

This is a convenience class providing an indexer to get a provider class by the configured string name.

Provider Manager

This class is a singleton class that has initialized the default provider and the provider collection.

Provider

This is an abstract class that provides a method signatures to be implemented in all sub-types.

Concrete provider class

There is at least one of this kind of class.  In the example provided below, there are two classes MySQLDataProvider and MyXMLDataProvider that inherit from the Provider class and potentially could implement its abstract methods.

More in depth

Configuration data

Perhaps the first to add is configuration data about your providers in either App.Config or Web.Config.  The following snippet shows the proper configuration elements placed within the <configuration> element.

<configuration>
<
configSections
>
<
section name="MyProviders"
type="Blog.Joubin.Ca.Providers.MyProviderConfiguration, ConsoleProviderModel"
/>
</
configSections
>
<
MyProviders default="SQLProvider"
>
<
providers
>
<
add name="SQLProvider"
type="Blog.Joubin.Ca.Providers.Instances.MySQLDataProvider, ConsoleProviderModel"
connectionString="Data Source=.\SQLEXPRESS;database=MyDatabase;Integrated Security=SSPI;"
/>
<
add name="XMLProvider"
type="Blog.Joubin.Ca.Providers.Instances.MyXMLDataProvider, ConsoleProviderModel"
fileLocation="c:\temp\"
/>
</
providers
>
</
MyProviders
>
</
configuration>
Provider Configuration class

This class inherits from the System.Configuration.ConfigurationSection class.  It exposes various configuration data through its properties.  This class is utilized in the Provider Manager class and it will be initialized in the manager class.

The code provided below has a string property that names the default configured provider.  Another property of this class is a collection of System.Configuration.ProviderSettings.  The first default provider name property could have easily been replaced with a property exposing the default ProviderSetting object.

using System.Configuration;

namespace Blog.Joubin.Ca.Providers
{
public class MyProviderConfiguration :
ConfigurationSection
{
// Represents a collection of System.Configuration.ProviderSettings objects.
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers
{
get
{
return (ProviderSettingsCollection)base["providers"];
}
}

[ConfigurationProperty("default", DefaultValue = "SQLProvider")]
public string DefaultProviderName
{
get
{
return base["default"] as string;
}
}
}
}
Provider Collection class

This class inherits from System.Configuration.Provider.ProviderCollection class.  The sample code hides the “this” indexer method and returns type of your provider class.

using System.Configuration.Provider;

namespace Blog.Joubin.Ca.Providers
{
public class MyProviderCollection :
ProviderCollection
{
// Return an instance of DataProvider for a specified provider name
new public MyDataProvider this[string name]
{
get { return (MyDataProvider)base[name]; }
}
}
}
Provider Manager class

This a singleton class that reads the configuration file, initializes the provider configuration and collection classes above.  This class could also expose a property that returns the provider collection.  In my sample code, I’m also providing another convenient property that allows user to have access to the System.Configuration.ProviderSettingsCollection which essentially is a copy of the data in the configuration file.

Your application uses the Provider manager class to get access to the default provider as well as to the provider collection.

using System.Configuration;
using System.Web.Configuration;
namespace Blog.Joubin.Ca.Providers
{
   
/// <summary>

   ///A singleton class that manages the providers collection
   
/// </summary>
    
public class
MyDataProviderManager
    
{
        static MyDataProviderManager()
        {
            Initialize();
        }

        private static MyDataProvider _default;
       
/// <summary>
        ///
Returns the default configured data provider
       
/// </summary>
        
public static MyDataProvider Default
        {
            get { return _default; }
        }

        private static MyProviderCollection _providerCollection;
       
/// <summary>
        ///
Returns the provider collection
       
/// </summary>
        
public static MyProviderCollection Providers
        {
            get { return _providerCollection; }
        }

        private static ProviderSettingsCollection _providerSettings;
        public static ProviderSettingsCollection ProviderSettings
        {
            get { return _providerSettings; }
        }

       
/// <summary>
        ///
Reads the configuration related to the set of configured
        
///
providers and sets the default and collection of providers and settings.
       
/// </summary>
        
private static void Initialize()
        {
            MyProviderConfiguration configSection = (MyProviderConfiguration)ConfigurationManager.GetSection("MyProviders");
            if(configSection == null)
                throw new ConfigurationException("Data provider section is not set.");

            _providerCollection = new MyProviderCollection();
            ProvidersHelper.InstantiateProviders(configSection.Providers, _providerCollection, typeof(MyDataProvider));
            _providerSettings = configSection.Providers;
            if (_providerCollection[configSection.DefaultProviderName] == null)
                throw new ConfigurationException("Default data provider is not set.");

            _default = _providerCollection[configSection.DefaultProviderName];
        }
    }
}

Abstract Provider class

This is an abstract class defining the to-be-implemented methods in the concrete sub-types.  In my example, I’m providing a single abstract method (GetUserTypes) that are implemented in the MySQLDataProvider and MyXMLDataProvider classes.

using System.Configuration.Provider;
using System.Collections.Generic;

namespace Blog.Joubin.Ca.Providers
{
public abstract class MyDataProvider :
ProviderBase
{
// abstract methods that are to be concretely implemented in the Provider classes

public abstract ICollection<string> GetUserTypes();
}
}
Concrete provider classes

This is where you or another developer can extend your application by writing more providers.  In my example, there will be two concrete classes, MySQLDataProvider and MyXMLDataProvider.  However this can be easily extended to cover let’s say Oracle provider, MySQL or Pointbase providers.

The following code snippet is from MySQLDataProvider:

using System.Collections.Generic;

namespace Blog.Joubin.Ca.Providers.Instances
{
public class MySQLDataProvider :
MyDataProvider
{
// implement the abstract methods from MyDataProvider

public override ICollection<string> GetUserTypes()
{
return new List<string>();
}
}
}

The entire code base could be downloaded:

Download Provider Model C# code

1 comments:

Giorgio Bozio said...

Hi,
interesting post!
What about applying this pattern to enable conditional dependency injection?
For example, in your console sample, what if I wanted to have a factory method that instantiates one of the two providers based on an attribute decorating the class of the calling method? Look at my blog post:
http://letsfollowtheyellowbrickroad.blogspot.com/2008/11/in-memory-data-access-methodology-to.html
I have dependency injection, but enabled through an helper method that references the assemblies of the concrete classes.
It would be nice if I could have the provider pattern in place and move to a configuration file all the logic about what concrete class to instantiate.
I'll work on it...