Click here to Skip to main content
Click here to Skip to main content

Task Plug-in: A Flexible .NET Plug-in Architecture

, 12 Jun 2007
Rate this:
Please Sign up or sign in to vote.
The Task Plug-in library is a set of classes, interfaces, enumerations and attributes that collectively support the ITaskPlugin interface. The ITaskPlugin interface is a .NET interface created to demonstrate how to create a “Plug-in” architecture utilizing the Microsoft .NET Framework.

Screenshot - PluginTestHost.png

Introduction

I guess I need to start off with the customary, "This is my first CodeProject article, so please be nice." Now that it's been said, let's move on the the meat of this article. The sample project/application was designed to demonstrate the creation of an infrastructure within an application in order to provide some extensibility through plug-ins. This project is hosted on SourceForge. If you wish to contribute to it, provide feedback or alternative approaches, please feel free to contact me. The solution provided, Plug-in, includes five C# projects:

  • TaskPluginInterface: The main library.
  • TaskPluginTest: An application provided to test the plug-ins.
  • FileCopyPlugin: A plug-in created to demonstrate the implementation of ITaskPluginInterface. This plug-in copies one or more files from one directory to another.
  • RunCommandPlugin: A plug-in created to demonstrate the implementation of ITaskPluginInterface. This plug-in will run commands using the System.Diagnostics.Process class.
  • PluginShellPlugin: This plug-in provides a basic shell for implementing the ITaskPluginInterface.

Technologies used

  • Microsoft .NET Framework v2.0, although v1.1 could be used with some modifications.
    • System.configuration
    • System.Reflection
    • System.Collections.Generic
    • System.File.IO
    • System.Diagnostics
    • Delegates, events, and event arguments
    • Log4Net
  • Guadagno.Utilties.dll, a series of classes that provides common functionality amongst most of my projects. The key class is ConfigurationBase, which is used for the application configuration.
  • SchedulerTime.dll, a class library used for the scheduling. See the reference article below.

Quick and dirty: how-to

Create the plug-in host

Step 1: Include a reference to the TaskPluginInterface.dll in your solution.

Step 2: Get the folder location for the plug-ins. I use \Plugins. Call the Utilities.GetPluginFolder() method.

Step 3: Get a list of plug-ins. Call Utilities.GetPlugins(folderName).

Step 4: Call the plug-ins Execute method.

Create the plug-in

Option 1: code from scratch

Step 1: Include a reference to the TaskPluginInterface.dll in your solution.

Step 2: Create a class that inherits from ITaskPlugin.

public class RunCommand : ITaskPlugin
{
}

Step 3: If you are using Visual Studio 2005, you can use the Intellisense or SmartTag to create the stub implementation of ITaskPlugin.

Step 4: Place your code in the Execute method.

Option 2: use the PluginShellPlugin class

Step 1: Rename the class to what ever name you want.

Step 2: Change the resource file strings to accurately describe your plug-in.

Step 3: Change the code in the DoWork() method.

TaskPluginInterface namespace

ITaskPlugin interface

The ITaskPlugin interface defines the methods, events and properties that the plug-ins must implement.

Methods

Enumeration Name Description
Execute Executes the task

Properties

Enumeration Name Description
Author The author of the plug-in.
Description The description of the plug-in.
Extension The file extension(s) that this plug-in handles. This is currently not used.
Extension Description A description of the extension(s) that this plug-in handles. This is currently not used.
Name The name of the plug-in.
Schedule The schedule for the plug-in. This was created for a future project, the pluggable task scheduler.
Version The version of the plug-in.

Events

Enumeration Name Description
EventEnd This is used to notify the host about the ending of the Execute method.
EventException This is used to notify the host about any Exceptions that have occurred.
EventProcessing This is used to notify the host about the processing of the Execute method.
EventStart This is used to notify the host about the starting of the Execute method.

PluginAttribute class

The PluginAttribute class defines the class attributes which can be applied to a class that is implementing the ITaskPlugin interface. This class defines an Attribute, which is PluginType. The PluginType corresponds to the PluginType class. Syntax:

TaskPluginInterface.Plugin(PluginType.Executable)]

public class RunCommand : ITaskPlugin
{

}

Enumerations

ExecuteResult

This enumeration is used as the return value of the Execute method for the ITaskPlugin interface.

Enumeration Name Description
Cancelled Indicates that the Execute method of the plug-in was cancelled.
Exception Indicates that an exception was raised by the plug-in.
Failed Indicates that the plug-in has failed.
Ok Indicates that everything went OK with execute of the plug-in.

PluginType

This enumeration is used to indicate the type of plug-in that is being created. Applying the PluginType attribute to a class does not have an effect the functionality of the class. Its only purpose is to provide a classification of the plug-ins available for list boxes or separate functionality.

Enumeration Name Description
Executable Indicates that the plug-in is used for launching executables.
Import Indicates that the plug-in is used for importing data.
SQL Indicates that the plug-in is used for processing SQL statements.
Unknown Denotes that the type of plug-in is not known.

PluginEventArgs class

The PluginEventArgs class provides information back to the plug-in host. This information is provided back to the plug-in host via one of the four events. PluginEventArgs properties:

Name Description
Cancel Indicates if the operation should be canceled.
Message A message returned from the plug-in.
Progress Indicates the current progress of the plug-in. The Progress is returned as a struct, which is defined in the Utilities class.
RaisedException An exception raised from the plug-in.

ScheduleConfig class

The ScheduleConfig class provides functions that will load the schedule configuration. Note that this was created for a future version of the application.

Utilities class

The Utilities class provides helper functions to interact with and discover plug-ins. All of the provided methods are static, so there is no need to create an instance of the Utilities class. Utilities class methods:

Method Name Description
FileContainsPlugins Determines if the file contains at least one plug-in. There is one overload that allows you specify a PluginType.
GetPlugin Returns a plug-in of the specified class from the specified file.
GetPluginFileList Gets a list files that contain plug-ins within the specified directory. There is one overload that allows you specify a PluginType.
GetPluginFolder Returns the plug-in directory.
GetPlugins Gets a List of plug-ins from the specified file. There is one overload that allows you specify a PluginType.

Included plug-ins

FileCopy

The FileCopy plug-in provides the ability to copy files that fit a mask from one directory to another. This plug-in reads the configuration file, FileCopyPlugin.Settings.xml, for all of the Directory nodes listed in the Directories element. For example:

<Directories>
    <Directory FromDir="C:\Temp\" ToDir="d:\Temp\" FileMask="*.*" />
    <Directory FromDir="C:\Temp\junk" ToDir="d:\Temp\junk" FileMask="*.txt" />
    <Directory FromDir="C:\Temp\junk" ToDir="d:\Temp\junk" FileMask="*.xyz" />
</Directories> 

The following configuration contains three copy commands.

    1. Will copy all of the files located in the c:\temp directory to d:\temp
    2. Will copy all of the TXT files located in the c:\temp\junk directory to the d:\temp\junk directory
    3. Will copy all of the XYZ files located in the c:\temp\junk directory to the d:\temp\junk directory

PluginShell

The PluginShell plug-in provides a class that contains everything needed to implement the ITaskPluginInterface.

RunCommand

The RunCommand plug-in provides the ability to execute processes using the System.Diagnostics.Process namespace. This plug-in reads the configuration file. RunCommandPlugin.Settings.xml, for Command elements listed in the Commands node. Each command element has XmlChildNodes that correspond to parameters of the ProcessStartInfo struct of the Process object.

TaskPluginTest

The TaskPluginTest is a sample application that demonstrates the use of the TaskPluginInterface library. This application utilizes the TaskPluginInterface utilities to load the list of application plug-ins. In addition, this application displays the plug-in metadata, executes the plug-in and handles events from the plug-in.

Future enhancements

  • Create NUnit test cases for entire library.
  • Create VB.NET sample plug-ins.
  • Improve on the Schedule library to allow for the displaying of all future schedules.
  • Integrate the ITaskPlugin interface into a Windows Service application to provide a flexible version of the Windows Task Scheduler.

References

History

Version Date What was done
1.0 4/21/07 Initial release.
1.0.0.1 4/21/07 Fixed an issue with spaces in the path.
1.0.0.2 5/5/07

Added better logging information to the plug-ins and the plug-in host.

Updated the Utilities class to replace the logic for GetPluginFolder.

1.0.0.2 6/12/07 Article edited and posted to the main CodeProject.com article base.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Joseph Guadagno
Web Developer
United States United States
I have been in software development for about 15 years or so. I started out with a small book on QuickBASIC, then moved the Visual Basic for DOS, then Visual Basic for Windows, then Visual Basic .NET and eventually Visual C#. When I am not working at my full time job I donate my time to several community efforts like:
 
Former President of INETA North America, currently Vice President.
President of the Southeast Valley .NET User Group (SEVDNUG) in Chandler, AZ.
Serving on my City's Parks and Recreation board.
 
I have or have had the following "MVP" awards:
  • Visual Basic MVP in 1996
  • C# MVP since 2009
  • Telerik MVP since 2010
I maintain a Open Source project on CodePlex which wraps the Bing API called BingSharp.
 
I also help / organize or participate in several community events:
  • Desert Code Camp
  • AZGiveCamp
  • Organizer for the 1st Time MVP event at the MVP Summit
  • MVP 2 MVP Sessions at MVP Summit.
  • Awesome bean pusher at GeekGive at the MVP Summit.
Follow on   Twitter

Comments and Discussions

 
QuestionNice work Joseph PinmemberMike Hankey28-May-12 5:33 
Question'Sticky' Plugins? PinmemberTheNeoCortex2-Jul-09 12:08 
Nice Article, better than some I have read that's for sure!
 
I am curious: How large would the effort be, in your estimate, to build in the ability for plugins to be hosts and allow other plugins to 'stick'?
 
I am looking at MEF (Managed Extensibility Framework) and I need to be able to provide 'stickiness' with my addins but I am not keen on using IOC to accomplish it
 
Thoughts?
AnswerRe: 'Sticky' Plugins? PinmemberJoseph Guadagno2-Jul-09 13:56 
GeneralRe: 'Sticky' Plugins? PinmemberTheNeoCortex6-Jul-09 5:41 
GeneralRe: 'Sticky' Plugins? PinmemberJoseph Guadagno6-Jul-09 5:44 
GeneralRe: 'Sticky' Plugins? PinmemberTheNeoCortex6-Jul-09 5:49 
QuestionAppropriate use of plugins? Pinmembercraibuch16-May-07 4:05 
AnswerRe: Appropriate use of plugins? PinmemberJoseph Guadagno16-May-07 5:02 
GeneralRe: Appropriate use of plugins? Pinmembercraibuch16-May-07 5:24 
GeneralRe: Appropriate use of plugins? PinmemberJoseph Guadagno16-May-07 8:33 
GeneralMonitor plugin directory Pinmembercraibuch11-May-07 5:52 
GeneralRe: Monitor plugin directory PinmemberJoseph Guadagno11-May-07 11:32 
GeneralCorrected a problem with spaces in the path name. PinmemberJoseph Guadagno20-Apr-07 7:43 
GeneralGreat project but I'm having problems getting it to run Pinmemberlberman20-Apr-07 3:26 
GeneralRe: Great project but I'm having problems getting it to run PinmemberJoseph Guadagno20-Apr-07 3:33 
GeneralRe: Great project but I'm having problems getting it to run PinmemberGary E Paul20-Apr-07 5:33 
GeneralRe: Great project but I'm having problems getting it to run PinmemberGary E Paul20-Apr-07 5:35 
AnswerRe: Great project but I'm having problems getting it to run PinmemberJoseph Guadagno20-Apr-07 5:37 
GeneralRe: Great project but I'm having problems getting it to run PinmemberJoseph Guadagno20-Apr-07 5:39 
GeneralRe: Great project but I'm having problems getting it to run PinmemberGary E Paul20-Apr-07 5:43 
AnswerRe: Great project but I'm having problems getting it to run PinmemberJoseph Guadagno20-Apr-07 7:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141216.1 | Last Updated 12 Jun 2007
Article Copyright 2007 by Joseph Guadagno
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid