Create a snappable application in C#


The purpose of this tutorial is to demonstrate how to create a very simple snappable application in C#.

Preview
 
1.gif 
 
The above screenshot shows a snappable application with one plugin loaded.  The text in the list box originated from the plugin itself.
 
Introduction
 
A snappable application is simply a program that can be extended using assemblies (DLL's) that the application has no knowledge of at runtime.
 
A snappable application can load external assemblies and then call their methods dynamically at runtime.  This functionality has lots of uses, but is mainly to allow developers to create third party add-ins.
 
This tutorial is trivial, but demonstrates all of what is needed to implement snap-ins.
 
Reflection
 
Before we can get started, we need to understand a little bit about what Reflection (System.Reflection) is, as this is fundamental to our project.
 
Reflection allows us to learn about an assembly at runtime with no prior knowledge.  Reflection, in its simplest form, can be used to determine the properties of an assembly (such as its interfaces, methods, properties, events etc) and bind to the (late bind) and use them at runtime.  At runtime, we can dynamically load an external assembly, and make calls to its methods.
 
Creating a snappable application
 
To make our application snappable, we will need the following;
  • Our main application (called MyApplication in this tutorial)
  • An interface library (called MyApplicationInterface)
  • A snap-in (called MySnapIn)
The main application will host the snap-in, the interface library will expose interfaces that can be used by third party developers and the snap-in will implement the interface library.
 
Interface Library (MyApplicationInterface)
 
The purpose of this library is to expose interfaces that can be implemented by third party developers.  Our main application will also have a reference to this interface.  When we dynamically load our snap-in at runtime, we will look for this interface in the assembly and then invoke its method.
 
Start by creating a project called "MyApplicationInterface" and add a class called "IMyApplication.cs".  Add the following code;
 
namespace MyApplicationInterface
{
    public interface IMyApplication
    {
        string Name { get; }
    }
}
 
n this scenario, the interface has one property which is used to retrieve the name of the snap-in.
 
Snap-in (MySnapIn)
 
Next, create a class library called MySnapIn, create an empty class, and implement the interface we just created.  (Make sure you add a reference to MyApplicationInterface.dll)
 
using MyApplicationInterface;
 
namespace MySnapIn
{
    public class MySnapIn : IMyApplication
    {
        #region Implementation of IMyApplication
        public string Name
        {
            get { return "My Snap In"; }
        }
        #endregion
    }
}
 
Main Application (MyApplication)
 
All that is left to do is load our snap-in  and display its name to the user.
 
Create a new Windows Forms application called MyApplication, add a reference to MyApplicationInterface.dll and add the following code;
 
private void LoadSnapIn(string snapInPath)
{
    if (string.IsNullOrEmpty(snapInPath)) return;
    if (!File.Exists(snapInPath)) return;
    try
    {
        //Load the assembly
        Assembly thirdPartySnapIn = Assembly.LoadFrom(snapInPath);
 
        //Search for class which implemented IMyApplication
        Type[] snapInTypes = thirdPartySnapIn.GetTypes();
        foreach(Type type in snapInTypes)
        {
            if (type.GetInterface("IMyApplication") != null)
            {
                //We have found a class that implements our interface
                //Late bind to it.
                IMyApplication snapInInterface = thirdPartySnapIn.CreateInstance(type.FullName) as IMyApplication;
                if (snapInInterface != null)
                {
                    //Retrive the 'Name' of the snap-in, display it to the user
                    LoadedSnapinsListBox.Items.Add(snapInInterface.Name);
                }
            }
        }
    }
    catch(Exception ex)
    {
        HandleException(ex);
    }
}
 
The above code loads the assembly, searches for a class which implements our interface IMyApplication, and if it finds one, returns the value of the Name property (which is then displayed to the user.
 
Conclusion
 
We can use reflection to dynamically load assemblies at runtime and use late binding to dynamically invoke methods and properties of which we had no prior knowledge.  This example, although trivial, shows how simple it is to create a flexible application which can be extended by third party developers.

Up Next
    Ebook Download
    View all
    Learn
    View all