brady gaster

yadnb

More Provider Model Goodieness - Selective Provision

So this time i've taken the old example one step further. Let's say that you've got a plugin architecture that works with the Provider model, so that plugins can be snapped right in via the configuration file. Now think about this for a moment - what if you wanted to be able to snap in as many plugins as you want, but want to be able to reference the one you need at run-time with a key?

Without going into too long-winded a discussion like the last post on this topic (which ended up being something shy of an article), here's an example of how to do something like this.

First off, the configuration file itself.

<configuration>
 <configSections
>
  <sectionGroup name
="SelectiveProvider">
   <section name="Settings"

      type
="SelectingProviderViaXPath.SelectiveProviderReader,
      SelectingProviderViaXPath"
    />
  </sectionGroup
>
 </configSections>

 <SelectiveProvider>
  <Settings
>
   <provider key
="helloWorld">
    <typeName>SelectingProviderViaXPath.HelloWorld</typeName
>
   </provider
>
   <provider key="goodbyeWorld">
   
<typeName>SelectingProviderViaXPath.GoodbyeWorld</typeName>
   </provider
>
  </Settings
>
 </SelectiveProvider
>

</
configuration>

Now, a quick look at the configuration reader and settings classes.

using System;
using
System.Configuration;
using
System.Xml;
using
cs = System.Configuration.ConfigurationSettings;
namespace
SelectingProviderViaXPath
{
 public class
SelectiveProviderReader : IConfigurationSectionHandler
 {
 ///
<summary>
 ///
Creates an instance of the GenericDal settings object
 ///
from the custom configuration settings.
 ///
</summary>
 ///
<returns></returns>
 public object Create(object
parent,
  object
context,
  XmlNode section)
  {
   XmlNodeList lst = section.SelectNodes("provider");
   return new
SelectiveProviderSettings(lst);
  }
 }
 /// <summary>
 ///
The settings class, which contains the type name to be loaded.
 ///
</summary>
 public class
SelectiveProviderSettings
 {
  const string
section = "SelectiveProvider/Settings";
  string
typeName = String.Empty;
  XmlNodeList providerList;

  internal SelectiveProviderSettings(XmlNodeList installedProviders)
  {
   providerList = installedProviders;
  }

  public string TypeName
  {
   get { return
typeName; }
  }

  /// <summary>
  ///
Set the provider according to what was asked for in the
  ///
GetSettings() parameter.
  ///
</summary>
  ///
<param name="key"></param>
  void SetProvider(string
key)
  {
   for(int
i=0; i<providerList.Count; i++)
   {
    string
j = providerList[i].Name;
    string
keyValue = providerList[i].Attributes["key"].Value;
    XmlNode nodTypeName = providerList[i].SelectSingleNode("typeName");
    if
(keyValue == key)
    {
     typeName = nodTypeName.InnerText;
     return
;
    }
   }
  }

  /// <summary>
  ///
Return an instance of the Settings object.
  ///
</summary>
  /// <param name="providerKey">The provider's key we want to instantiate.
</param>
  ///
<returns></returns>
  public static SelectiveProviderSettings GetSettings(string
providerKey)
  {
   SelectiveProviderSettings b =
   (SelectiveProviderSettings)cs.GetConfig(section);
   b.SetProvider(providerKey);
   return
b;
  }
 }
}

Next, the IProvider interface and a few basic implementations of it.

using System;
namespace SelectingProviderViaXPath
{
 public interface IProvider
 {
  void WriteMessage();
 }

 public class HelloWorld : IProvider
 {
  public void WriteMessage()
  {

   Console.WriteLine("Hello World!");
  }
 }
 public class GoodbyeWorld : IProvider
 {
  public void WriteMessage()
  {
   Console.WriteLine("Goodbye World!");
  }
 }
}

Finally, a little console client to exemplify the whole deal.

using System;
namespace
SelectingProviderViaXPath

class Client
{
 static void Main(string[] args)
 {
  Client c =
new Client("goodbyeWorld");
  c.WriteMessage();
  Console.ReadLine();
 }

 protected IProvider provider;

 /// <summary>
 /// Constructor which sets up the required provider.
 /// </summary>
 /// <param name="providerKey">Key of the provider in the config setting.</param>
 public Client(string providerKey)
 {
  SelectiveProviderSettings settings =
  SelectiveProviderSettings.GetSettings(providerKey);
  Type t = Type.GetType(settings.TypeName);
  object o = Activator.CreateInstance(t);
  provider = o
as IProvider;
 }

 void WriteMessage()
 {
  if(provider != null)
  provider.WriteMessage();
  else
  Console.WriteLine("Provider does not implement IProvider");
 }
 }
}

There you have it - the Provider model, extended somewhat so that multiple plugins can coexist in harmony, only to be used when needed by an individual application at run-time. Deviation, variation, and extension, all through one little model.

Comments

No Comments

Leave a Comment

(required) 

(required) 

(optional)

(required)