Adding an Extension Based System to Your Website


Before I begin, I admit 100% that this idea was taken from the people at BlogEngine.Net. It's really a fantastic idea. Anyway, let's say you have a website and you've decided to use someone else's software (no source, just a DLL) to do most of the work, and let's say that you decide that you want to have the software automatically put a watermark on all images that you upload. Well you would normally find the location where you save the images and add a function, class, etc. to do so at that location. However you don't have access to the code, so you curse the developer and complain on their website until they add that option.

Wouldn't it be better if they had added hooks so you could add your own code? Actually it's extremely easy to do by implementing an extension based system (and I recommend it to anyone developing a website as it will cut down on development time in the long run). The great thing about it is that there are already a ton of libraries out there that can help you with this, including MEF. Or if you want, you can spend a couple of hours and create your own. I went this approach and now have an extension manager library that I use on most of my projects. In this example I'll use the library that I created, but all we'll need to do is the following:

  1. Add two lines of code to our Global.asax file.
  2. Create an extension.
  3. Create a config class for the extension.
  4. Create events on any object that you want to make extendable (plus the calls in the appropriate locations).

That's all there is to it. So let's look at what we add to Global.asax.

   1: protected void Application_Start(object sender, EventArgs e)
   2: {
   3:     Gestalt.Manager.Instance.RegisterConfigFile(AssemblyOfExtensions);
   4:     DotExtension.Manager.Instance.Setup(AssemblyOfExtensions);
   5: }

All the code above is doing is starting Gestalt.Net (which is my library that handles config files in an OO approach) and tells it to look for configuration classes in the specified assembly. The next line the tells DotExtension to look in the same assembly for any extensions and automatically loads them. Anyway, let's look at our extension and config class:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using DotExtension.BaseClasses;
   7: namespace Extensions
   8: {
   9:     public class MyExtension:Extension
  10:     {
  11:         public MyExtension()
  12:             : base()
  13:         {
  14:             BusinessObject.Saving+=new EventHandler<EventArgs>(SavingObject);
  15:         }
  17:         public void SavingObject(object Object, EventArgs Args)
  18:         {
  19:             //Here is where we would actually do our work
  20:         }
  21:     }
  23:     [Gestalt.Attributes.Config(Name = "MyExtension")]
  24:     public class MyExtensionConfig:DotExtension.Config.ExtensionConfig
  25:     {
  26:         public virtual string SomeVariable { get; set; }
  27:     }
  28: }
The config object is mapped to the extension through the use of the Config attribute. In it we set the Name to the name of the extension. By doing this, the config class is automatically loaded when the extension is loaded. The extension, when loaded, is really only just attaching itself to the Saving event on the BusinessObject class (which would be whatever object/class you wanted to extend). But that's all the code that you would need to get started with my library. The only part left is to add the Saving event to the BusinessObject class:
   1: public static event EventHandler Saving; 
   3: public void OnSaving()
   4: {
   5:     if (Saving != null)
   6:     {
   7:         Saving(this,null);
   8:     }
   9: }

So whenever the BusinessObject is being saved, it simply calls the OnSaving function and we're done. Each time the event is called, it will in turn fire the function in the extension (along with any other functions that are using it). And that's all there is to it. So download and try out the code, leave feedback, and as always, happy coding.