Enterprise Library Configuration (Part 2/2): Customizable configuration with framework extensions.

In my first article on Enterprise Library configuration, I talked about how to build your own "root node" in a configuration file.  We also discussed how to use the ILinkedNodeService to reference another configuration node from within your custom configuration section, and went over some details as to how the code worked in relation to the configuration manager tool.  I provided a downloadable code example that I will use again in this post.

Before I get started, I wanted to point you to the tool that myself (and many others) use to get our VS.NET code into such nice HTML format - it's called CopySourceAsHtml by Colin Coller.  Thanks for such a time-saving tool.

In this post, I'm going to discuss how you can create customized "providers" (the Enterprise Library term for pluggable modules that fit within the code EntLib frameworks), and how those providers can use the configuration tool to gather customizable information from the user beyond default key/value pairs you get without any additional work.  We're going to build an Authorization Provider that will authorize a given request based solely on the system's pseudo-random number generator and a threshold value provided through the configuration framework.

If you open up the solution, we'll be looking at the EntLibFrameworkConfigDemo project this time.  I want to start with the MyAuthenticationProvider class, which is the actual random authenticator.

MyAuthorizationProvider.cs

 

    1 using System;

    2 using Microsoft.Practices.EnterpriseLibrary.Configuration;

    3 using Microsoft.Practices.EnterpriseLibrary.Security;

    4 

    5 

    6 namespace EntLibConfigDemo.ExtendingFrameworks

    7 {

    8     /// <summary>

    9     /// Summary description for MyAuthenticationProvider.

   10     /// </summary>

   11     public class MyAuthorizationProvider: ConfigurationProvider, IAuthorizationProvider

   12     {

   13 

   14         private static System.Random _rnd = new System.Random();

   15 

   16         private double threshold;

   17         private string applicationName;

   18 

   19         public MyAuthorizationProvider()

   20         {

   21             // No constructor logic needed

   22         }

   23         #region IAuthorizationProvider Members

   24 

   25         public bool Authorize(System.Security.Principal.IPrincipal principal, string context)

   26         {

   27             if (_rnd.NextDouble()>threshold)

   28             {

   29                 return true;

   30             }

   31             return false;

   32         }

   33 

   34         #endregion

   35 

   36         #region IConfigurationProvider Members

   37 

   38         private SecurityConfigurationView securityConfigurationView;

   39 

   40         /// <summary>

   41         /// Initializes the state of the current object from

   42         /// the specified configuration data.

   43         /// </summary>

   44         /// <param name="configurationView">A <see cref="SecurityConfigurationView"></see> object</param>

   45         public override void Initialize(ConfigurationView configurationView)

   46         {

   47             // Check to make sure we have a valid configuration node before continuing

   48             if (null==configurationView)

   49             {

   50                 throw new ArgumentNullException("configurationView cannot be null");

   51             }

   52             securityConfigurationView = configurationView as SecurityConfigurationView;

   53             if (null==securityConfigurationView)

   54             {

   55                 throw new ArgumentException("configurationView is not of the correct type.");

   56             }

   57 

   58             // Load our authorization data and store the relevant information for later use

   59             MyAuthorizationProviderData data = securityConfigurationView.GetAuthorizationProviderData(ConfigurationName) as MyAuthorizationProviderData;

   60             if (null==data) {

   61                 throw new ArgumentException("AuthorizationProviderData is not of type MyAuthorizationProviderData");

   62             }

   63             threshold = data.AuthorizationRate;

   64             applicationName = data.Application;

   65         }

   66         #endregion

   67     }

   68 }

The IConfigurationManager interface:

What we're interested in here is the IConfigurationManager implementation, which is nothing more than the Initialize method.  This method is called when the provider is first loaded, and provides the framework a way to pass configuration data to the provider.  Here we check to make sure we've received the right type of configuration data and then initialize the private variables from the configuration data.  Pretty simple all in all.  The SecurityConfigurationView class is part of the core EntLib class library and provides several utility methods including the GetAuthorizationProviderData we use to retrieve the authorization data, which is defined in the MyAuthroizationProviderData class.  Both the MyAuthorizationData and the MyAuthroizationProviderNode don't add anything new from my previous post, so I'm not going to go into detail on them here.  The major difference between the two examples is in the DesignManager class, in this case MyAuthorizationProviderDesignManager class:

MyAuthorizationProviderDesignManager.cs

 

    1 //===============================================================================

    2 // Microsoft patterns & practices Enterprise Library

    3 // Security Application Block

    4 //===============================================================================

    5 // Copyright © Microsoft Corporation.  All rights reserved.

    6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY

    7 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT

    8 // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND

    9 // FITNESS FOR A PARTICULAR PURPOSE.

   10 //===============================================================================

   11 

   12 using System;

   13 using System.Diagnostics;

   14 using Microsoft.Practices.EnterpriseLibrary.Configuration;

   15 using Microsoft.Practices.EnterpriseLibrary.Configuration.Design;

   16 using Microsoft.Practices.EnterpriseLibrary.Security.Configuration;

   17 

   18 namespace EntLibConfigDemo.ExtendingFrameworks

   19 {

   20     /// <summary>

   21     /// Configuration Design Manager for MyAuthorizationProvider. <seealso cref="IConfigurationDesignManager"/>.

   22     /// </summary>

   23     public class MyConfigurationDesignManager : IConfigurationDesignManager

   24     {

   25         /// <summary>

   26         /// Initializes a new instance of the <see cref="MyConfigurationDesignManager"/> class.

   27         /// </summary>

   28         public MyConfigurationDesignManager()

   29         {

   30         }

   31 

   32         /// <summary>

   33         /// <para>Registers the <see cref="MyAuthorizationProviderNode"/> in the application.</para>

   34         /// </summary>

   35         /// <param name="serviceProvider">

   36         /// <para>The a mechanism for retrieving a service object; that is, an object that provides custom support to other objects.</para>

   37         /// </param>

   38         public void Register(IServiceProvider serviceProvider)

   39         {

   40             RegisterNodeTypes(serviceProvider);

   41             RegisterXmlIncludeTypes(serviceProvider);

   42         }

   43 

   44         /// <summary>

   45         /// <para>Opens the configuration settings and registers them with the application.</para>

   46         /// </summary>

   47         /// <param name="serviceProvider">

   48         /// <para>The a mechanism for retrieving a service object; that is, an object that provides custom support to other objects.</para>

   49         /// </param>

   50         public void Open(IServiceProvider serviceProvider)

   51         {

   52         }

   53 

   54         /// <summary>

   55         /// <para>Saves the configuration settings created for the application.</para>

   56         /// </summary>

   57         /// <param name="serviceProvider">

   58         /// <para>The a mechanism for retrieving a service object; that is, an object that provides custom support to other objects.</para>

   59         /// </param>

   60         public void Save(IServiceProvider serviceProvider)

   61         {

   62         }

   63 

   64         /// <summary>

   65         /// <para>Adds to the dictionary configuration data for

   66         /// the enterpriselibrary.configurationSettings configuration section.</para>

   67         /// </summary>

   68         /// <param name="serviceProvider">

   69         /// <para>The a mechanism for retrieving a service object; that is, an object that provides custom support to other objects.</para>

   70         /// </param>

   71         /// <param name="configurationDictionary">

   72         /// <para>A <see cref="ConfigurationDictionary"/> to add

   73         /// configuration data to.</para></param>

   74         public void BuildContext(IServiceProvider serviceProvider, ConfigurationDictionary configurationDictionary)

   75         {

   76         }

   77 

   78         private static void RegisterXmlIncludeTypes(IServiceProvider serviceProvider)

   79         {

   80             // Find the xmlIncludeTypeService, which registers the XML-serializable class representing the configuration data.

   81             IXmlIncludeTypeService xmlIncludeTypeService = serviceProvider.GetService(typeof(IXmlIncludeTypeService)) as IXmlIncludeTypeService;

   82             Debug.Assert(xmlIncludeTypeService != null, "Could not find the IXmlIncludeTypeService");

   83             // Register the MyAuthorizationProviderData type with the xmlIncludeTypeService

   84             xmlIncludeTypeService.AddXmlIncludeType(SecuritySettings.SectionName, typeof(MyAuthorizationProviderData));

   85         }

   86 

   87         private static void RegisterNodeTypes(IServiceProvider serviceProvider)

   88         {

   89             // Get the Node Creation Service to we can register our configuration node (the designer class) with the configuration tool.

   90             INodeCreationService nodeCreationService = ServiceHelper.GetNodeCreationService(serviceProvider);

   91 

   92             Type nodeType = typeof(MyAuthorizationProviderNode);

   93             // Register a new command with the Node Creation Service, allowing multiple instances within a single configuration file.

   94             // The DisplayName parameter is what is displayed in the configuration manager menu.

   95             NodeCreationEntry entry = NodeCreationEntry.CreateNodeCreationEntryWithMultiples(new AddChildNodeCommand(serviceProvider, nodeType), nodeType, typeof(MyAuthorizationProviderData), "My Authorization Provider");

   96             nodeCreationService.AddNodeCreationEntry(entry);

   97         }

   98     }

   99 }

Because we are simply adding a new provider of a type the configuration manager already knows something about, we just have to figure out how to add our type to the correct menu item.  In this case, the key is to know that in the RegisterXmlIncludeTypes method to call the AddXmlIncludeType takes the section name as its first parameter.  Otherwise, the major difference between this class and the AppConfig example is that this one is much simpler.  Most of the implementation of the IConfigurationDesignManager interface is not necessary, and there is no CreateCommands method, as the command to create an authentication provider node is already part of the configuration manager.

With that, I'll leave you to explore the Enterprise Library configuration management classes.

3 Comments

Comments have been disabled for this content.