During the ramp up for my current enterprise GIS development project I created a few simple VB.NET sample projects which illustrate some architectural practices I want the team to use.
The first one I'm going to share covers the creation of a plugin framework, and the use of the Supervising Controller pattern to expose user interface logic to unit tests. In order to keep the focus on the pattern, and not on the complexities of what the code is doing, this sample does not use any ArcObjects. It's just a very simple example of how you could create "property page" type functionality that can be extended via plugins.
What is a Plugin-Framework and why would I want one?
Using a plugin framework is a way to design an application so that other functionality can be added at a later time without needing to modify the original source code. Putting this in ArcGIS terms, this is similar to adding commands into ArcMap via it's plugin framework.
If you are building large complex applications, supporting a plugin model essentially enables the system to be extended in a very managed way. Thinking back to ArcGIS - by simply implementing ICommand, you can add alot of functionality into their application, and ESRI does not have to give you the source code, nor do you need to manage a very complex C++ build process.
Supervising Controller Pattern
Just a quick warning - we're diving into formal object oriented design patterns here. Previously known as Model View Presenter, this is a common object oriented design pattern. Martin Fowler (who invented/named it) has officially retired the "Model View Presenter" pattern, and created two new ones - Supervising Controller and Passive View. You can read up on the details of these patterns by following those links, but the quick and dirty explanation is that they focus on extracting logic from an User Interface (windows or web form) into "controller" classes. (A little pattern nugget to impress your friends with: Autonomous View is the official name for the "put all the code in the form" pattern) These controllers handle most of the User Interface logic - and since they are regular old classes - they are much easier to write unit tests for.
One of the prime reasons to use Supervising Controller is for testability. Assuming the view is hard to test, by moving any complex logic into the controller, we put the logic in a place that's easier to test. - Martin Fowler
At first blush this seems like more work - and it actually is more coding. BUT - if you write tests for the controllers (not covered in the sample), it will make your code more robust and manageable over the long term.
The Plugin Framework
The plugin part is pretty straight forward. We define an interface for the plugin, and implement it in the classes which we are going to plug-into the application.
This is exactly the same as implemeting ICommand. The difference is that instead of registering a COM class with the windows registry, we add the plugin by editing the host application's config file...
<propertypageplugins>
<propertypageplugin name="Editor" type="Research.EditorPluginView, Research.ExamplePlugin" />
<propertypageplugin name="Some Different Plugin" type="Research.EditorPluginView, Research.ExamplePlugin" />
</propertypageplugins>
In order to load the plugins into the application we create a configuration section handler - which I've posted about in the past. For more details, I'd suggest checking out this MSDN article by Roy Osherove. I'd also suggest looking at the code, since there are some other interesting bits in there that I'm skipping over to keep this somewhat short.
The Host Application
The plugins must plug-into something - thus the host application. This is simply a windows form that will list the registered plugins, and then show the selected plugin interface on the right side of the form. The image below shows it running.
The Plugins & Supervising Controller
The plugins are located in the "ExamplePlugin" assembly. In fact there is only one plugin - "EditorPlugin " - I just register it twice. The pluing itself is a super simple text editor. As I metioned earlier, the plugins themselves implement the Supervising Controller pattern. Typically this is used with "forms", but in order to be pluggable, we are working with user controls. And to be fun, I'm using using inherited user controls.
Inheriting the user control forces a common look and feel - granted in this case, it's very simple (just the group box), but in our real app, it's got a lot more going on.
To keep things clear, I have setup a standard naming convention - the UI (user control in this case) is <somename>View, and the Controller is <somename>Controller. The interface that forms the contract between the two is I<somename>View. Looking at the class model above, we can also see that the View implements IPropertyPluginView - which means that it's the thing that actually plugs into the application.
So in this case we have:
Since the Controller must manage the UI, one way to setup a contract between the two is using an Interface. The interface is implemented by the View, and consumed by the Controller. The interface simply specifies the methods that the Controller can call on the View (UpdateText and GetText in this case) and the events that the View raises and that the Controller can handle (ContentChanged and Store).
Conclusion
While this was a whirlwind of terms and concepts, I encourage you to download the code, and play with it. It's actually quite easy to implement once you get the hang of it, and it can help make your applications much more testable. I find it much easier to look at real code than to just read the generic explanations of patterns, so I hope this helps if you are thinking about implemeting a plugin framework or Supervising Controller in .NET
Download the code
Other Reading:
The Polymorphic Podcast has a series of great screen casts and audio clips that go over the details of the Model View patterns. I highly recommend these specifically, and the podcast in general.
MSDN Article: Creating a Plugin Framework. This is from 2003, and deals with ASP.NET but the concepts have not changed.
I'm Dave and this is my blog. I'm usually writing about .NET Software Development, ArcGIS, or Agile Practices, but other stuff does creep in from time to time. I hope you find something of use, and feel free to contact me if you have any questions. You can also check out my profile on LinkedIn
dojo.DTSAgile.com is our technology preview / demo site. As I and my team cook up cool things we post them here.
ArcDeveloper.net is a site that hosts a set of open source projects related to ArcGIS. This includes Tile Cache for .NET (TC4N) and Feature Server for .NET (FS4N). Come over and check it out!
Assembla is a free service that provides Subversion source control, wikis and work Tracking. The ArcDeveloper project is run from here. It rocks. Check them out today.
Agilistas is a LinkedIn group focused on discussing and promoting Agile practices. Everyone is welcome to join in the conversation as we evolve the process of creating software to make it more enjoyable for all involved.