Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Security

Implementing a Plug-In Architecture in C#


Loading Plug-Ins

Listing 4 contains the method LoadPlugs. LoadPlugs is located in HostForm.cs and is a private instance method of the HostForm class. The LoadPlugs method uses .NET reflection to load the available plug-in files, validates them as plug-ins that can be used by the host application, and then adds them to the host application’s tree view. The method goes through several steps:

  1. By using the System.IO.Directory class, the code is able to do a wildcard search for all of the files with a matching .plug file extension. The Directory class’ static method GetFiles returns an array of System.String that contains the absolute path of each file in the hard-coded path that matches the pattern.
  2. After retrieving the array, the method next iterates through each file path attempting to load the file into a System.Reflection.Assembly instance. The code that attempts to create an Assembly instance is wrapped in a try block. If the file is not a valid .NET assembly, then an exception is caught and feedback in the form of a message box is provided to the user about the unsuccessful attempt. If more file paths are left to process, the loop is able to continue.
  3. With an assembly loaded, the code next iterates through each accessible type in the assembly to see if it supports the HostCommon.IPlug interface.
  4. If the type supports HostCommon.IPlug, the code next validates that the type also supports the attributes that have been defined for plug-ins. If any of the attributes are not supported, a HostCommon.PlugNotValidException is thrown. After the exception is thrown, it is caught and feedback in the form of a message box is provided to the user explaining why the plug-in failed. If more file paths are left to process, the loop is able to continue.
  5. Finally, if the type supports HostCommon.IPlug and defines all of the required attributes, it is wrapped in an instance of PlugTreeNode. The PlugTreeNode instance is then added to the host application’s tree view.

Listing 4: The method LoadPlugs


private void LoadPlugs()
{
  string[] files = Directory.GetFiles("Plugs", "*.plug");

  foreach(string f in files)
  {

    try
    {
      Assembly a = Assembly.LoadFrom(f);
      System.Type[] types = a.GetTypes();
      foreach(System.Type type in types)
      {
        if(type.GetInterface("IPlug")!=null)
        {
          if(type.GetCustomAttributes(typeof(PlugDisplayNameAttribute),
  false).Length!=1)
            throw new PlugNotValidException(type,
              "PlugDisplayNameAttribute is not supported");
          if(type.GetCustomAttributes(typeof(PlugDescriptionAttribute),
  false).Length!=1)
            throw new PlugNotValidException(type, 
              "PlugDescriptionAttribute is not supported");

          _tree.Nodes.Add(new PlugTreeNode(type));
        }
      }
    }
    catch(Exception e)

    {
      MessageBox.Show(e.Message);
    }
  }

  return;
}

Deployment

The primary framework for the example application is deployed as two assemblies. The first assembly is Host.exe, and it houses the window forms host application. The second assembly is HostCommon.dll, and it houses all of the types that are used for communication between the host application and plug-ins. For example, the IPlug interface is deployed in HostCommon.dll so that it is equally accessible to both the host application and plug-ins. With the two assemblies in place, additional assemblies can be deployed that store the individual plug-ins. These assemblies are deployed to the plugs directory directly below the application path. The EmployeePlug class is deployed in the Employee.plug assembly, and the CustomerPlug class is deployed in the Customer.plug assembly. The example has taken the liberty of creating its own .plug file extension for plug-ins. The plug-in assemblies that are deployed are ordinary .NET library assemblies. Usually library assemblies are deployed with a .dll extension. The special extension has no influence on the runtime, but helps the plug-ins to stand out to users.

Alternative Designs

The design chosen for the example application is not exclusively correct. For example, using attributes is not required to develop a plug-in solution with C#. The services provided by the two defined attributes could also be provided by two property signatures added to the IPlug interface definition. Attributes were chosen because the name of a plug-in and its description are declarative in nature and fit quite nicely into the attribute model. Of course, using attributes requires more reflection code in the host application. This is a case-by-case design decision that developers will have to make on their own.

Conclusion

The example application is intended to be as thin as possible to help accentuate the communication between a host application and plug-ins. For a production environment, many improvements can be made to make a more useful solution. Some possible additions include:

  1. Increasing the communication points between the host and the plug-in by adding more method, property, and event signatures to the IPlug interface. Additional interaction between the host and plug-ins will allow for plug-ins that can do more things.
  2. Enabling users to explicitly select the plug-ins that are loaded.

Source Code

The complete source code for the sample application is available for download in walchesk.zip.

Notes

[1] Erich Gamma et al. Design Patterns (Addison-Wesley, 1995).


Shawn Patrick Walcheske is a software developer in Phoenix, Arizona. He is a Microsoft Certified Solution Developer and a Sun Certified Programmer for the Java 2 Platform.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.