Home > Articles > Web Services > XML

Building Plugins with C# Part 3: Adding LDAP, SQL, and Configuration

📄 Contents

  1. Configuration Issues
  2. The LdapAuthenticator
  • Print
  • + Share This
Feeling smarter, yet? In this continuing series, you'll learn how to use inheritance to re-use code, and how your applications can load their own configuration files. You'll also learn more about doing LDAP authentication and connecting to a database to run a stored procedure.
Like this article? We recommend Be sure to check out the rest of this article series. Part 1 introduces the concept of using plug-ins to handle authentication of users. In Part 2, you’ll learn how to use XML to validate users. Finally, Part 4 wraps up the series by showing you how to log your process, as well as some troubleshooting.

This is the third article in a four-part series on building plug-ins with C# .NET. The second part in the series covered some XML-related topics, such as using an XML file to store usernames and passwords, and writing a custom XML configuration section handler to parse the application configuration file.

In this article, I'll show you how to build two new plug-ins that require configuration. The first plug-in requires an LDAP root and the name of a domain in which to find a user. The second requires a database connection string. Aside from the configuration concepts, the other concepts that I'll introduce are using directory services like LDAP to authenticate against Active Directory, and using classes in the System.Data.SqlClient namespace to connect to a database.

Configuration Issues

When the plug-ins are loaded by the testing app, AuthenticationPlugin.UI.UITester, a call to ConfigurationSettings.AppSettings will pull configuration values from the application's configuration file, even if an XML configuration file was added correctly to the plug-in project. This can be seen by the Debug statement added to the MyTest test plug-in, which prints the location of the configuration file using the built-in .NET AppDomain class:

  ( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile );

The Debug statement above prints the full name of the file that is being used as the configuration file, which will be the Application's configuration file.

This presents a slight problem. To add configurable values to one of the plug-ins, I could simply add the configuration keys to the application file, and I could even keep the file separate but include it using:

<appSettings file="plugin.config" />

However, with many different plug-ins, the potential exists for configuration keys to overlap. For instance, if more than one plug-in uses a database connection, I could easily have two configuration strings. One way to get around this is to add the full namespace and classname to the front of the configuration key, like this:

  <add key="AuthenticationPlugin.Plugins.SqlAuthenticator.connectionString"
  value="Database=…" />

Although this can work fine, the main reason why you might not want to configure the plug-ins this way is because it requires you to modify the application's configuration file. A requirement to add values to the configuration file conflicts with the intended concept: add the plug-in, and use it right away.

To solve this configuration dilemma, I wrote a base class that can be extended by any plug-in that requires configuration. Using a base class allows both our two new plug-ins, the LDAP and database authentication plug-ins, to take advantage of the same code to load configuration.

The base class uses an XML reader to iterate through a file and add any elements it finds under the base element to a NameValueCollection—a class that comes with .NET in the Systems.Collections.Specialty namespace. The base class uses the Assembly's current directory and name to compose a full configuration file filename by tacking on an extension. I chose ".config" as the file extension, but you could change it to make more sense for your implementation.

The LoadConfiguration method from the base class is shown in Listing 1-1. The LoadConfiguration method accepts the name of the configuration file's root node as a string and returns a new NameValueCollection object with the element names and their values. A sample file, listed here, results in a NameValueCollection with two key value pairs in it: valueA, with the value of Foo, and valueB with the value of Bar.

<?xml version="1.0"?>

An XMLTextReader reads in the configuration file. The reader iterates through the XML nodes and looks to see if the node is of type Element (other types include Comment, Document, Text, and more). Once an Element is found (otherwise known as a tag), the name of the element is added to the NameValueCollection along with the text inside the element. The root element, identified by the single parameter to the LoadConfiguration method, is skipped because we don't want it in the configuration key-value pair.

The base class is added to the AuthenticationPlugin.Common project so other plug-ins can extend from it easily; they will all need to refer to the project anyway, to implement the IAuthenticationPlugin interface and define the AuthenticationPlugin attribute.

Listing 1-1

protected NameValueCollection LoadConfiguration( string rootNodeName )

  NameValueCollection config = new NameValueCollection();
  /* It's not implemented for this example for the sake of
   * brevity, but this method really should check to see 
   * if the file exists and log the error somewhere if it 
   * doesn't.
  Debug.WriteLine( Assembly.GetCallingAssembly().Location );
  XmlTextReader configReader = new XmlTextReader( 
          Assembly.GetCallingAssembly().Location + ".config" );

    /* While the file is not at the end */
    while ( ! configReader.EOF )
           /* In this specific configuration file, the code is 
            * looking for elements 
           if ( XmlNodeType.Element == configReader.MoveToContent() &&
                   configReader.Name != rootNodeName )
           /* Add the configuration to the internal 
              NameValueCollection object */
           config.Add( configReader.Name, 
           configReader.ReadElementString() );
           /* Advance through the file if we're not interested in
            * the current node
    /* It is very important to close the file */
    if ( null != configReader )
  return config;
  • + Share This
  • 🔖 Save To Your Account