Rich Newman

December 12, 2007

SCSF Business Modules: Start Up and the ControlledWorkItem (Introduction to CAB/SCSF Part 20)

Introduction

Part 19 of this series of articles discussed business modules in a Smart Client solution generated using the Smart Client Software Factory. This article continues that discussion.

The Load Method of a Business Module

As discussed in the previous article, a business module has a class called ‘Module’ which inherits from class ModuleInit. We saw in part 1 of this series of articles that this means the Load method in that class will get called at start up, provided the module has been added to the ProfileCatalog file.

The Load method of Module generated by the Smart Client Software Factory is as below:

        public override void Load()
        {
            base.Load();
 
            ControlledWorkItem<ModuleController> workItem = _rootWorkItem.WorkItems.AddNew<ControlledWorkItem<ModuleController>>();
            workItem.Controller.Run();
        }

As we can see, it’s creating a ControlledWorkItem class instance and adding it to the WorkItems collection of the root WorkItem. It’s then calling the Run method on the Controller property of this WorkItem.

ControlledWorkItem

ControlledWorkItem is a class that inherits directly from WorkItem. So a ControlledWorkItem is a WorkItem. The ControlledWorkItem also adds additional functionality to the WorkItem, and, crucially, it is a sealed class (which means we can’t inherit from it).

The idea here is that each business module should have a ControlledWorkItem as a root for its functionality. This is what we are creating in the Load method. In the overall WorkItem hierarchy each business module ControlledWorkItem is immediately below the root WorkItem for the entire solution.

Inheriting WorkItem to add Functionality

The ControlledWorkItem has been created to clarify the situation with regard to adding code to WorkItems. When we start using the CAB we quickly find that we need our WorkItems to be extended in various ways. They are intended to control business use cases, after all. For example we may want specific services instantiated at start up and added to the Services collection. Doing this in the WorkItem itself may seem like a sensible thing to do. Clearly the main WorkItem class is a CAB framework class, but we can inherit from it to give it this additional behaviour.

The reference implementations of both the CAB and the SCSF do this: each WorkItem inherits from the base WorkItem class and extend it to give the use case functionality. If you look at the CustomerWorkItem in the Bank Teller Reference Implementation you’ll see this.

Why Inheriting from WorkItem has been Deprecated

The difficulty with this is that our WorkItem class is acting as both a container for all the various WorkItem collections, as we have discussed before, AND as a place where all the code for a business use case goes.

This breaks the Single Responsibility principle, which is that every class should have just one responsibility in a system to avoid confusion.

As a result the Patterns and Practices team have decided it’s not ideal to have developers inherit from WorkItem and add functionality to the derived class. Instead a second class is created to contain the new code, and that class is associated with the WorkItem class by composition.

How ControlledWorkItem Addresses the Problem

This is what the ControlledWorkItem is doing. The ControlledWorkItem class itself inherits from WorkItem, but also has a member variable that references another class. The type of this class is generic (so the developer provides it), and the class is instantiated when the ControlledWorkItem is created.

So in the line of code below we are creating the ControlledWorkItem and adding it to the root WorkItem’s WorkItems collection. However we are also telling the ControlledWorkItem that its member class should be of type ModuleController, and that class will get instantiated and set up as the member variable.

ControlledWorkItem<ModuleController> workItem = _rootWorkItem.WorkItems.AddNew<ControlledWorkItem<ModuleController>>();

We are not expected to inherit from ControlledWorkItem itself. In fact we can’t because it is sealed: the Patterns and Practices team have done this deliberately to indicate that the pattern has changed. Instead we add our additional functionality for the WorkItem to the ModuleController class.

ModuleController

We can access the ModuleController instance from the ControlledWorkItem using the Controller property. We can then call a Run method on that class. This is the standard pattern that is generated by the Guidance Automation Package: note that the final line in the Load method above is:

workItem.Controller.Run();

So we can add start up code for the WorkItem into the ModuleController class in the Run routine.

The SCSF gives us a default ModuleController whenever we set up a Module, as we have seen. This has a default Run method. There isn’t any code that actually does anything in this method, but four empty methods are set up in ModuleController to indicate to us the sort of things we should be doing:

    public class ModuleController : WorkItemController
    {
        public override void Run()
        {
            AddServices();
            ExtendMenu();
            ExtendToolStrip();
            AddViews();
        }
...

There are also comments in these routines to describe what we should be doing inthem. To see this in more detail look in any of the ModuleController classes in the sample code.

WorkItemController Class

Note also above that our default ModuleController inherits from a class called WorkItemController, which is an abstract base class intended to be used just of these controllers. Inheriting from this ensures that we have a Run method in our derived class as there is an abstract function of this name in the base class.

The base WorkItemController also gets a reference to the associated WorkItem using our usual dependency injection pattern. This can be accessed via the WorkItem property on the WorkItemController class.

Finally the WorkItemController class has two overloaded ShowViewInWorkspace methods, which can create and show a SmartPart in a named Workspace in the WorkItem.

Obviously we don’t have to make our ModuleController inherit from WorkItemController. However, if we don’t this base class functionality will not be available.

Conclusion

This article has discussed the standard patterns generated by the Smart Client Software Factory for starting up business (and other) modules.

Part 21 of this series of articles will look briefly at foundational modules, and will also discuss the way names are handling in Smart Client Software Factory projects.

Advertisements

6 Comments »

  1. This article has been a great help in figuring out some of the changes that were made in SCSF from straight CAB and why. However I’m still a little confused about the workitem situation. In our previous CAB project we had one Module that contained a “controlling workitem”, e.g. System Administration that only contained services and child workitems, and several child workitems (use cases) each with their own associated Views and Presenters e.g. Maintain Users, Maintain Codes. Can you please offer some insight as to whether this is still possible, or even makes sense, in SCSF. It seems to me that I now can have only one workitem per module?

    Comment by Glenn Plott — January 10, 2008 @ 4:37 pm

  2. Glenn

    I think the idea is still that we should use multiple WorkItems to support different business use cases within a module. This hasn’t changed with the SCSF patterns. What has changed is that we now use two classes for a WorkItem rather than one. One class contains all the WorkItem collections, and the other (the ‘Controller’) contains any developer code for the WorkItem. It’s certainly still possible to arrange everything in a hierarchy as you describe. The ControlledWorkItems themselves can be in the WorkItems collections, and the controller functionality can be accessed through their Controller properties.

    However I do think that trying to structure modules with different WorkItems for different business use cases is difficult and can get confusing. However, the alternative of having one WorkItem per module isn’t that good either. I started writing a post about this a while ago which I will complete at some stage.

    Rich

    Comment by richnewman — January 10, 2008 @ 7:20 pm

  3. Hi Rich, thanks for that wonderful serie of articles.

    Have you continued work on the post you write about in comment #2 about how multiple workitems within the same module is confusing. I tried writing one such module thinking in terms of passive views MVP in a way that would be unit-testable but bogged down because the presenter of a view needed to:
    1- add a sub-workitem to current item
    2- run that workitem
    so my presenters now had a dependency on the Workitem itself and is more difficult to test.

    One way I thought of resolving this issue was through the event broker in the following way:
    1- User does an operation on View1 that would trigger a new use case
    2- View1 forwards the call to Presenter1
    3- Presenter1 publishes an event (should that be within the view?)
    4- That module’s top WorkItem is subscribed to that event topic and when it is called it will, create a new sub WorkItem, add it to its collection and run it.
    5- The new workitem would create a View2 and display it to user.

    Should that be the way to go or I am complicating things a little?

    Marcel

    Comment by Marcel — February 29, 2008 @ 4:23 pm

  4. Great and clear overview of changes. Thank you!

    Gyuri

    Comment by Gyuri — April 7, 2008 @ 2:35 pm

  5. Hi Richard,

    How can you reference the extended methods that have been added to the workitemcontroller within the presenter? There is a workitem property within the presenter, however, the workitemcontroller is not included.

    Comment by Bernie — September 19, 2009 @ 1:36 am

  6. Hello Marcel, Did you get ansfer on your question?

    Comment by Serge — October 5, 2009 @ 4:56 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: