This morning I was wondering on the best way to approach handling custom sidebar widgets, and it struck me that creating a simple plug-in system would not only be fun, but it would allow other people to develop widgets without having to rebuild the inner workings of CodeBlog.
After a half hour or so of tinkering, I came up with the basic concept for developing a CodeBlog plug-in, though there is a lot more to code out.
The basic concept:
- Each plug-in is stored within its own assembly.
- A common interface (ICodeBlogPlugin) is used to reference the plug-in.
- A static factory method is used in CodeBlog to load and instantiate the plug-in.
Each Plug-In is a class library that references CodeBlog.Plugin.dll. This library provides an interface ICodeBlogPlugin that must be implemented by the plug-in class.
For testing, I used a very basic interface, but I will extend this interface to provide all the method signatures needed for an actual plug-in:
1 public interface ICodeBlogPlugin
2 {
3 string PluginName
4 {
5 get;
6 set;
7 }
8
9 void Render();
10 }
This interface is to be implemented by any plug-in class. For example, to test my idea, I created a new class library and added CodeBlog.Plugin as a reference:
1 public class TestPlugin : ICodeBlogPlugin
2 {
3
4 private string _pluginName;
5
6 /// <summary>
7 /// PluginName Property required by ICodeBlogPlugin
8 /// </summary>
9 public string PluginName
10 {
11 get
12 {
13 return _pluginName;
14 }
15 set
16 {
17 _pluginName = value;
18 }
19 }
20
21 /// <summary>
22 /// Default Constructor
23 /// </summary>
24 public TestPlugin()
25 {
26 PluginName = "TestPlugin!";
27 }
28
29 /// <summary>
30 /// Render Method required by ICodeBlogPlugin
31 /// </summary>
32 public void Render()
33 {
34 HttpContext.Current.Response.Write(PluginName);
35 }
36 }
To load the plugin into a class instance in the CodeBlog Core. I also added a static class called PluginFactory into CodeBlog.Plugin:
1 public static class PluginFactory
2 {
3 public static ICodeBlogPlugin LoadPlugin(string pluginName)
4 {
5 Type theType = Type.GetType(pluginName);
6 return (ICodeBlogPlugin)Activator.CreateInstance(theType);
7 }
8 }
Of course, in actual production code, there needs to be exception handling implemented, but this was just some quick test code. Eventually, I will write a plugin loader framework and configuration file, but for now, quickly mocking up some code to test load the plugin was trivial:
1 ICodeBlogPlugin TestPlugin;
2 TestPlugin = PluginFactory.LoadPlugin("CodeBlog.TestPlugin.TestPluginClass,CodeBlog.TestPlugin");
3 TestPlugin.Render();
The potential here is great. A developer can implement the ICodeBlogPlugin interface and create a plug-in that will work directly in CodeBlog. A end user will only have to drop the DLL into the /bin directory and add the assembly name to a configuration file and the plug-in will be ready to use.
This is definitly a fun feature that I hope will be leveraged to its full potential.
2 comments:
this is pretty much the standard approach i've seen for implementing plugins ... a few extra steps you could add are:
- create an AppNamePluginAttribute to be used by the class implementing the plugin interface..
-use LoadAssembly and iterate through the dlls in your app's dir and have it try and create an instance only of classes that have the above-mentioned attribute... that would make the plugins more "drag'n'droppish", if you wanted to cut out the config file step. a matter of personal preference, really.
thanks for speaking on the topic... i previously had to search for days to find any articles on implementing a plugin framework for .net, it's good to see more posts about it.
Keep in mind .NET 3.5 adds a namespace dedicated to plugins: System.AddIn. They've eased the burden of creating robust, reliable, safe add-ins.
Post a Comment