TechEd 2008 notes: Create Your Own Providers for the Ultimate Flexibility

This was an interesting session. The Provider model seems simple enough. There’s a lot of classes involved, each of which is pretty simple (I think he stuck pretty well to the single-responsibility principle), although I had a bit of a hard time keeping track of which class went where in the chain. Sometime later I’ll look back at this and draw some sort of class-interaction diagram to help me figure it out.

One note, though: apparently there’s a ProviderBase class that does some of the boilerplate code for you. He didn’t mention that until the very end (after someone asked him about it). So this is mostly theory about the bits and pieces, rather than necessarily a list of what you need to implement on your own. I haven’t looked at ProviderBase to see how much of a base it gives you to build on.

Create Your Own Providers for the Ultimate Flexibility
Paul D. Sheriff
President
PDSA, Inc.

Samples at pdsa.com/teched, in both VB.NET and C#.

Agenda

  • What’s a provider and why use one
  • Dynamically loading assemblies
  • Creating a custom data provider
  • Implement an ASP.NET Membership provider
    • Store users/roles in XML file

What is a provider?

  • Components that can be loaded at runtime
  • Allows you to switch components without recompiling
  • Patterns
    • Strategy
    • Abstract factory

Why use a provider?

  • Keep dev API consistent
    • Developer always calls a method named SendAFax
  • Implementation can be different

Provider examples

  • ADO.NET Data Provider
    • MSSQL
    • Oracle
    • OLE DB
    • DB2
  • Each implements an interface
    • IDBCommand
    • IDBConnection
  • ASP.NET Membership System
    • Front end always same
      • Login control, CreateUserWizard control
    • User storage can change
    • Change the provider by deploying a new DLL (not recompiling old) and changing the config file
  • ASP.NET session state

How to…

  • Create interfaces and/or base classes
  • Dynamically load
  • Read config files
  • Create providers

Dynamically create the class

  • System.Type.GetType(className)
  • System.Activator.CreateInstance(type)

Dynamically load assembly

  • Assembly class
    • Use Load if in GAC or current directory
    • Use LoadFile if not
  • Then use the Assembly‘s CreateInstance

Reading the config file

  • ConfigurationManager.AppSettings[“ProviderName”]
  • Better: add your own section. But that’s a little more work.

Demo

<configuration>
  <configSections>
    <section name="ConfigSettings" type="ConfigSimple.ConfigSectionHandler, ConfigSimple">
  </configSection>
  <ConfigSettings type="..." location="...">

class ConfigSectionHandler : ConfigurationSection
{
    [ConfigurationProperty("type")]
    public string Type
    {
        get { return (string) this["type"]; }
    }
    [ConfigurationProperty("location")]
    public string Location
    {
        get { return (string) this["location"]; }
    }
}
abstract class ConfigProviderBase
{
    public abstract string GetSetting(string key);
    public string Location { get; set; }
}
class ConfigSettings
{
    private static ConfigProviderBase _configProvider;
    private static void InitProvider()
    {
        object section = ConfigurationManager.GetSection("ConfigSettings");
        ConfigSectionHandler handler = (ConfigSectionHandler) section;
        _configProvider = (ConfigProviderBase)
            Activator.CreateInstance(Type.GetType(handler.Type));
        _configProvider.Location = handler.Location;
    }
    public static string GetSetting(string key)
    {
        if (_configProvider == null)
            InitProvider();
        return _configProvider.GetSetting(key);
    }
}

So, here’s provider #1:

class ConfigAppSettings : ConfigProviderBase
{
    override string GetSetting(string key)
    {
        return ConfigurationManager.AppSettings[key];
    }
}

And, another one that reads from a separate XML file instead:

class ConfigXML : ConfigProviderBase
{
    public override string GetSetting(string key)
    {
        string result = "";
        var xe = XElement.Load(this.Location);
        var setting = (from elem in xe.Elements["Setting"]
            where elem.Attribute("key").Value == key
            select elem).SingleOrDefault();
        if (setting != null)
            result = setting.Attribute("value").Value;
        return result;
    }
}

Could have used a whiteboard with some boxes and arrows, because it seems like the naming conventions are confusing. But it’s just a matter of following the pattern.

Has an example of how to do this with a collection of providers specified in the XML (e.g., <providers> <add ... /> <add ... /> <add ... /> </provider>)

Once you start the process, get the boilerplate going, writing a new provider becomes pretty easy.

Leave a Reply

Your email address will not be published. Required fields are marked *