Los Techies : Blogs about software and anything tech!

Decoupling Workflow And Forms With An Application Controller


One of the big problems I’ve been trying to solve recently, is in my current WinForms application that using a Model-View-Presenter setup. I have my workflow between forms coupled to the forms directly. That is, in order to get from MainForm to SubForm, I have code inside of MainForm instantiate SubForm and it’s Presenter. The nightmares of changing any part of the workflow because of this, are astounding. I won’t go into great detail on the problems. It should be sufficient to know that my form codebehind would often contain several hundred lines of code to create all the needed views and presenters for a workflow, per workflow.

Building A Solution

There are two parts of the solution that I’m trying to use now, that are relatively new to me.

1) Use a good IoC container. I’m using StructureMap at the moment. I’ve used Windsor in the past and don’t like some of the default conventions it has. StructureMap’s conventions fit very well with my personal style of development (at least in part because I’ve considered Jeremy Miller to be a mentor – via his blog, etc – for several years now). Although I have done IoC / DI / DIP before, I’ve not used a good IoC container in quite some time. I’ve primarily been using a ServiceLocator and manual Dependency Inversion.

2) Set up an Application Controller to hide most of the coordination and infrastructure needs, including the IoC container, from the rest of the application.

Application Controller

Martin Fowler’s PoEAA book says this about Application Controllers:

“Some applications contain a significant amount of logic about the screens to use at different points, which may involve invoking certain screens at certain times in an application. This is the wizard style of interaction, where the user is led through a series of screens in a certain order. In other cases we may see screens that are only brought in under certain conditions, or choices between different screens that depend on earlier input.

To some degree the various Model View Controller input controllers can make some of these decisions, but as an application gets more complex this can lead to duplicated code as several controllers for different screens need to know what to do in a certain situation.

You can remove this duplication by placing all the flow logic in an Application Controller. Input controllers then ask the Application Controller for the appropriate commands for execution against a model and the correct view to use depending on the application context.”

For the last month or two, I’ve been trying to find as much information as possible, on Application Controller, with little to no luck in finding any information on WinForms development. Then Dino Esposito posted an article on “The Presenter in MVP Implementations” over at DotNetSlackers where he discusses the idea of introducing an Application Controller into an MVP application, to control the workflow. This was exactly what I was looking for… or so I thought. After playing around with the structure that he introduces, I found myself wanting more – specifically wanting a better decoupling of the workflow from the AppController.

My Application Controller Implementation

After working with various ideas for the last month, I finally have an example implementation that I’m happy with. The core of the sample is the Application Controller, of course. Surprisingly, it is a very simple implementation. The primary functionality that I ended up needing in my Application Controller, is the ability to execute an ICommand<T> interface, and publish an event via an EventAggregator. Both the ICommand<T> and EventAggregator that I use, are heavily influenced by Jeremy Miller’s Build Your Own CAB series.

using EventAggregator;
using StructureMap;
 
namespace ApplicationControllerExample.AppController
{
 
 public class ApplicationController : IApplicationController
 {
 
   private IContainer Container { get; set; }
   private IEventPublisher EventPublisher { get; set; }
 
   public ApplicationController(IContainer container, IEventPublisher eventPublisher)
   {
     Container = container;
     EventPublisher = eventPublisher;
     
     Container.Inject<IApplicationController>(this);
   }
 
   public void Execute<T>(T commandData)
   {
     ICommand<T> command = Container.TryGetInstance<ICommand<T>>();
     if (command != null)
       command.Execute(commandData);
   }
 
   public void Raise<T>(T eventData)
   {
     EventPublisher.Publish(eventData);
   }
 
 }
 
}

I also included an IApplicationController interface definition, for easy Dependency Injection, etc. This interface is a core part of my complete solution, and is referenced by all of my Presenters.

namespace ApplicationControllerExample.AppController
{
 public interface IApplicationController
 {
   void Execute<T>(T commandData);
   void Raise<T>(T eventData);
 }
}

Reference IApplicationController From The Presenters

With this in place, I can now set up my Presenters to use the IApplicationController instead of having direct references to ICommand<T> objects, or the IEventPublisher object. This allows me to simplify the dependency list in many of the presenters that I have – especially the “Menu” presenter that has 20 or 30 menu commands… one command for each menu item.

When a Presenter needs to kick off a workflow or raise an event, all it needs to do is call out to the IApplicationController. This allowed the individual presenters and WinForms to be decoupled from the workflow.

using ApplicationControllerExample.AppController;
using ApplicationControllerExample.Model;
using EventAggregator;
 
namespace ApplicationControllerExample.App
{
 
 public class MainPresenter: IEventHandler<SomeEventData>
 {
 
   private IMainView View { get; set; }
   private IApplicationController AppController { get; set; }
 
   public MainPresenter(IMainView mainView, IApplicationController appController)
   {
     View = mainView;
     AppController = appController;
     View.Presenter = this;
   }
 
   public void Run()
   {
     View.Run();
   }
 
   public void DoSomething()
   {
     AppController.Execute(new SomeCommandData());
   }
 
   public void SomethingElseIsHappening()
   {
     AppController.Raise(new SomeEventData("Something done here"));
   }
 
   public void Handle(SomeEventData eventData)
   {
     View.SaySomething(eventData.Message);
   }
 }
 
}

The call to AppController.Raise() will use the EventAggregator to publish an event of type SomeEventData. In this case, I have the very same presenter registered to handle the event, which isn’t terribly exciting – but it does illustrate the point of it working.

Building An ICommand<T> And Workflow Service

The call to AppController.Execute(), in the above Presenter example, will load up the ICommand<SomeCommandData> object from StructureMap and execute it. The ICommand<SomeCommandData> interface is implemented by an explicit object. This is where I would include any workflow definition that I need to start up and run.

namespace ApplicationControllerExample.Model
{
 public class SomeCommand: ICommand<SomeCommandData>
 {
   private ISomeWorkflowService WorkflowService { get; set; }
 
   public SomeCommand(ISomeWorkflowService workflowService)
   {
     WorkflowService = workflowService;
   }
 
   public void Execute(SomeCommandData commandData)
   {
     WorkflowService.Run();
   }
 }
}

Since I am using StructureMap to instantiate this object, it will inject the ISomeWorkflowService registered instance for me, which depends on a role specific interface called IPartOfTheProcess.

namespace ApplicationControllerExample.App
{
 public class SomeWorkflowService: ISomeWorkflowService
 {
   private IPartOfTheProcess PartOfTheProcess { get; set; }
 
   public SomeWorkflowService(IPartOfTheProcess partOfTheProcess)
   {
     PartOfTheProcess = partOfTheProcess;
   }
 
   public void Run()
   {
     PartOfTheProcess.DoThatThing();
   }
 }
}

Looping Back To The App Controller

The IPartOfTheProcess interface is implemented by another Presenter. This Presenter depends on the IApplicationController interface. By having that dependency, I can start the chain all over again. The "SecondaryPresenter” can call out the AppController and execute another command or raise another event to be published.

using ApplicationControllerExample.AppController;
using ApplicationControllerExample.Model;
 
namespace ApplicationControllerExample.App
{
 public class SecondaryPresenter: IPartOfTheProcess
 {
   private ISecondaryView View { get; set; }
   private IApplicationController AppController { get; set; }
 
   public SecondaryPresenter(ISecondaryView view, IApplicationController appController)
   {
     View = view;
     AppController = appController;
     View.Presenter = this;
   }
 
   public void DoThatThing()
   {
     View.Run();
   }
 
   public void Whatever()
   {
     AppController.Raise(new SomeEventData("you did what?"));
   }
 
   public void ThatThingHappened(string s)
   {
     AppController.Raise(new SomeEventData("click-o-that menu"));
   }
 }
}

Conclusions

I think you get the idea by now… by including the IApplicationController dependency in my presenters, I no longer have to worry about coupling my specific presenters to any part of the workflow, or my workflow to any specific presenters. And notice that I haven’t even mentioned the WinForms that I’ve implemented for the I(whatever)View interfaces. I don’t care anymore. I implement a view interface however I want to, and register that Implementation with StructureMap.

The combination of a good IoC container (pick the one you like; it doesn’t have to be StructureMap), an Application Controller, and some good old Dependency Inversion and Interface Separation (with a healthy dose other SOLID principles), can really help to decouple a system, very quickly.

I’m quite happy with this little example, at this point. It is helping me to solve some of the most painful coupling problems that I’ve had in the last 9+ months of my current project. I’m sure I will run into situation in the future, where this simple ApplicationController needs to be extended, though.

Download The Example App

As a side note – I used this example app as an opportunity to not only learn the ApplicationController pattern, but also to learn Git source control, using msysgit. With that in mind, I decided to push the sample app out to GitHub.

If you would like to download the entire codebase for this sample, and see how it all comes together to create a working program, you can get it here:

http://github.com/derickbailey/appcontroller/tree/master

Kick It on DotNetKicks.com
Posted Apr 18 2009, 02:04 PM by derick.bailey

Comments

DotNetShoutout wrote Decoupling Workflow And Forms With An Application Controller - Los Techies - Derick Bailey
on 04-18-2009 2:54 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Marcos wrote re: Decoupling Workflow And Forms With An Application Controller
on 04-19-2009 2:22 PM

Thanks a lot, looks really interesting.

Rei wrote re: Decoupling Workflow And Forms With An Application Controller
on 04-19-2009 4:33 PM

Isn't this more typically called MVC?

Jeremy Wiebe wrote re: Decoupling Workflow And Forms With An Application Controller
on 04-23-2009 3:30 PM

@Rei: I think in this case, the ApplicationController is not an MVC controller, but truly is an Application Controller as per Fowler's definition which Derick mentioned near the beginning.  The presenter's that are mentioned in this post are often synonymous with controllers from MVC (please correct me if that's not true..)

@Derick: fantastic post!  Really enjoying your blog since I've found it.  Since we're doing WinForms development it's nice to see some great blog posts about WinForms in the age of WPF and Silverlight.  :-)

Enrique Ramirez wrote re: Decoupling Workflow And Forms With An Application Controller
on 05-13-2009 5:11 PM

Interesting post. I've been looking for something along these lines for a while since coupling problems in WinForms development is my major pain point right now. I didn't get this 100% since the example is really abstract, but I'll jyst try to read through it and the code over and over until I get it.

Again, (like Jeremy said) thanks for writing about Winforms in this age of Web/Silverlight/WPF.

derick.bailey wrote re: Decoupling Workflow And Forms With An Application Controller
on 05-13-2009 5:59 PM

@Enrique,

Glad the post helped at least a little! I'm currently writing a much more elaborate, closer-to-real-world example app and presentation based on this blog post, and am hopefully going to be giving a presentation on it at the upcoming Austin Code Camp, on May 30th.

I know you're not in the Austin area (saw your Twitter location), but I'll be posting the complete presentation and solution on my blog some time soon after the code camp. Hopefully it will be a little more enlightening. :)

Enrique Ramirez wrote re: Decoupling Workflow And Forms With An Application Controller
on 05-14-2009 10:50 AM

Oh man, I really wish I could make it to the code camp. I made it a priority to make budget for next year to try to make it to at least one code camp (hopefully somewhere I can get a cheap flight to).

In any case, I really hope to get an "Ah-ha!" moment out of your presentation. Right now I'm using the MVP pattern as described by Craig Shoemaker in his site. The separation of logic is nice, but I still run into a lot of coupling problems when one form has to instantiate and call another and depends on what the user did or entered in that other form.

Something that I missed the first time around (I think I was speedreading through it just before leaving work), was the idea of using an IoC container to achieve this level of decoupling. I'm yet to use an IoC container, but putting it in context, your code makes a bit more sense now. Time to go read up on IoC containers...

new ThoughtStream("Derick Bailey"); wrote Balsamiq And A Sneak Preview Of My ‘Decoupling Workflow’ Presentation
on 05-14-2009 9:25 PM

I know I’m late jumping on this bandwagon, but it’s better late than never, right? :) I decided to try

derick.bailey wrote re: Decoupling Workflow And Forms With An Application Controller
on 05-15-2009 4:54 PM

@Enrique,

I've basically completed the "real world" example application for my upcoming presentation. I decided to use a very simple Org Chart as the sample app. There are a few key pieces of the sample app that I'll try to outline further, in another blog post: on the main form, I'm using the EventAggregator to get notification of employees being added, and employees being selected from the org chart to display their info. I'm also using an ICommand to kick off the add new employee wizard, and using a workflow service object to run the add new employee wizard.

I hope that this app, being a little more "real world", will help to shed some more light on the AppController and the other patterns that are in play, for you.

You can get a copy of this app from my Github repository, at:

github.com/.../tree

under the "Decoupling Workflow With App Controller" folder.

new ThoughtStream("Derick Bailey"); wrote I’m Presenting At Austin Code Camp 2009
on 05-18-2009 9:29 PM

As Chad so eloquently stated, this year’s AustinCodeCamp really is going to be better than bacon ! And

new ThoughtStream("Derick Bailey"); wrote Understanding The Application Controller Through Object Messaging Patterns
on 12-22-2009 10:06 PM

Earlier in the year, I posted a few times on the Application Controller pattern that I was implementing

Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems