Provider design pattern at a glance

Introduction

In a nutshell, the provider model is a design pattern largely used by Microsoft components for allowing an application to make use and choose from multiple implementations of a given contract based on the settings of a configuration file. So, for instance, management of user membership or roles are usually carried out by means of classes based on this pattern (see MemberShipProvider or RoleProvider classes). This way, the application can choose the default provider for dealing with membership or roles, add or remove providers, etc. in a declarative way. It brings a lot of benefits for developers as they can plug new components easily without refactoring code.

Background

In the Microsoft world, providers must inherit from ProviderBase abstract class (System.Configuration.Provider namespace in System.Configuration.dll, System.Configuration.ConfigurationManager.dll assemblies).

Derived provider classes are configured in a declarative way within a proper app.config or web.config file according to the type of application we are working with. So, we need some rules to write these settings and some classes to read data accordingly. We can implement all of this with a ProviderConfiguration class able to read collection of providers and details for each one. On the other hand, the way for writing data in config files can be carried out by means of configSections (see <configSections /> node in the app.config displayed at the bottom).

As said before, if we are going to deal with multiple providers we need an object to store the list of providers. This can be achieve with a ProviderCollection class holding the list of configured providers.

Finally, we need a LogProviderManager class able to:

  • Read and expose all the configuration data by using the ProviderConfiguration class.
  • Instantiate and expose the list of providers by placing them in a ProviderCollection class.
  • Expose the default provider by some public default property.

Sample

Let's suppose we need to provide options for logging information in plain text or xml depending on application requirements. It would be a very good case to implement it by using the provider pattern. Not only developers would be able to choose between these implementations but they could create new ones as well and plug them very easy. See the class diagram displayed below:

LogProviderManager class instantiates the LogProviderCollection based on the configuration settings exposed by LogProviderConfiguration class. The default provider along with the collection of log providers are exposed by LogProviderManager by means of properties Default and Providers. Additionally, LogProviderManager exposes the ProviderSettingsCollection by means of ProviderSettings collection.

Here is the app.config file for more clarification:

<configuration>
  <configSections>
    <section name="LogProviders"
      type="ProviderPatternLogTest.LogProvider.LogProviderConfiguration, ProviderPatternLogTest"/>
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
  <LogProviders default="XmlProvider">
    <providers>
      <add name="XmlProvider"
        type="ProviderPatternLogTest.LogProvider.Providers.XmlLogProvider, ProviderPatternLogTest"
        fileLocation="c:\temp\log.xml"/>

      <add name="TextProvider"
        type="ProviderPatternLogTest.LogProvider.Providers.TextLogProvider, ProviderPatternLogTest"
        fileLocation="c:\temp\log.txt"/>
    </providers>
  </LogProviders>
</configuration>

Notice that configuration of providers should contain a name and a type attribute containing the provider name and the fully qualified class name implementing the provider. The rest of attributes are optional (fileLocation above) and serve to incorporate values for new customized provider properties. They will be returned in a System.Collections.Specialized.NameValueCollection property for each ProviderSetting object within ProviderSettings collection property in LogProviderConfiguration or LogProviderManager classes.

Having said that, all developers have to do is to use the LogProviderManager.Default property to get an instance of the default provider and then, call the exposed methods on it.

References

Please, take a look at here for accessing the original post from which this one was written. You can also download the source code from there.

Add comment