Simple Plugin System

We needed a basic scheduler that could be extended with plugins to support multiple functions. I wanted to make it easy to add functionality without being required to rebuild it every time.

First of all, create a new solution using a console application as the base project. Next, add another project using the class library template. Call this one Plugins (or solution name with "Plugins" on the end).

In the Plugins solution, delete Class1.cs. We won't be using it. Create a new interface in the plugins project by right-clicking on the project and pointing to Add>New Item... and select "Interface" from list. Call this IPlugin.cs and click Add. This can be added to the main project instead, if you want to reference the EXE directly. I prefer to reference a DLL.

Mine looked like this:

public interface IPlugin
{
    string Name { get; }
    Period Frequency { get; }
    int NthPeriod { get; }
    void Do();
}
public enum Period
{
    Hourly,
    Daily,
    Weekly,
    Monthly
}

Next, add a reference to the Plugins project in your base project. In Program.cs in the base project add the following code:

string[] dllFileNames = null;
dllFileNames = Directory.GetFiles(Environment.CurrentDirectory, "*.dll");
ICollection<Assembly> assemblies = new List<Assembly>(dllFileNames.Length);
foreach (string dllFile in dllFileNames)
{
    AssemblyName an = AssemblyName.GetAssemblyName(dllFile);
    Assembly a = Assembly.Load(an);
    assemblies.Add(a);
}
Type pluginType = typeof(IPlugin);
ICollection<Type> pluginTypes = new List<Type>();
foreach (Assembly a in assemblies)
{
    if (a != null)
    {
        Type[] types = a.GetTypes();
        foreach(Type type in types)
        {
            if (type.IsInterface || type.IsAbstract)
            {
                continue;
            }
            else
            {
                if (type.GetInterface(pluginType.FullName) != null)
                {
                    pluginTypes.Add(type);
                }
            }
        }
    }
}
foreach (Type type in pluginTypes)
{
    IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
    Log.Trace("Starting " + plugin.Name + "...");
    plugin.Do();
}

Of course, there's more that can be done with this, like combining it with a basic database or JSON objects to keep track of when a plugin was last started so that it can be set on a schedule. To really utilize this functionality, it may be better to create a service rather than a console application that you have to set up through the Task Scheduler.

Now, create a new class library project for your first plugin. Add a reference to the plugins project and add a new class (Class1.cs can be deleted again). Make this new class inherit from IPlugin (and add the appropriate using statement). Go ahead and implement the Interface (one of the Resolve tasks or Quick Actions, depending on your version of Visual Studio).

public class MyPlugin : IPlugin
{
    public string Name
    {
        get
        {
            return "My New Cool Plugin";
        }
    }
    public Period Frequency
    {
        get
        {
            return Period.Hourly;
        }
    }
    public int NthPeriod
    {
        get
        {
            return 1;
        }
    }
    public void Do()
    {
        Log.Trace("My New Cool Plugin is now running!"); // Add entry to log file and output to the screen using class provided in Plugins project
    }
}

The Do() method is where we'll do all of our work. Add additional classes as needed. I also included a Log class in my Plugins project that could used by my plugins to log actions:

public class Log
{
    static public void Trace(string s)
    {
        s = DateTime.Now + ": " + s + "\r\n";
        File.AppendAllText("Scheduler" + DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString().PadLeft(2, '0') + DateTime.Now.Day.ToString().PadLeft(2, '0') + ".log", s);

        Console.Write(s);
    }
}

Build solution and run it! You now have a (very) simple plugin-enabled application.