Monday, December 10, 2007

Blame NHibernate, Why Not?

I’m currently assisting with another project that is experiencing some performance issues.  A lot of finger-pointing and blaming has been going on, and most of the parties involved just want to jump in and blame NHibernate.

I figured that we could optimize the way NHibernate is being used to help gain some perf. back in the application and hopefully restore its reputation at the client (and frankly, my company). 

Some info about the application:

It’s a WinForms application that communicates via Web Services to a service layer.  The service layer utilizes NHibernate over a domain model for persistence.  The domain types are serialized and used directly on the client.  (more on this later)

There are roughly 100 tables and almost as many mapped entities.  It is using NHibernate 1.0.2.

We did some basic benchmarking of the application so that we could quantify how effective various fixes were.

Startup time: 14 seconds.  Ouch!  I turned on the hibernate.show_sql setting in the config file and watched the SQL queries fly.  They were covering the screen!  I wrote a simple log4net IAppender that would count the number of log statements that contained a query and found out that 304 queries were being executed at startup.  Obviously something is wrong here, so I copied the queries to notepad and began to group them.

The domain of the application is shipping (like, in ships across the ocean).  So there is a concept of Terminals, Ports, Port Locations, and Geographic Locations.  If we load all of the terminals, we need to load the port for each one, the port location for each one of those, and the geographic location for each one of those.  It turns out that this many-to-one is not that bad.  You can get most of the data you need in one query using left joins.  The problem we faced was that GeographicLocations held an IList of all of its PortLocations.  And furthermore the PortLocation held an IList of all of its Ports. 

Picture trying to build up just a single terminal…

  • select terminal details and build up a Terminal
    • need a port, so build it up
      • need a port location, so build that up
        • need a geographic location, so build that up
          • not done?  Now we need all of the port locations for the geographic location
            • you guess it, now we need all of the ports for all of the portlocations you just loaded
              • now we need to get all of the terminals for all of the ports for all of the port locations, ….

This is starting to sound like that children’s story The House That Jack Built.

This is EXACTLY the reason that ORM’s have lazy-loading.  If you haven’t used it before, here’s how it works:  You load up the terminal, but it doesn’t fire a query for the port.  It gives you a stand-in object instead.  The second you access the terminal.Port property, *boom* – a database query is executed, the port is loaded, and you are returned a port.  This allows us to select a minimal amount of data, and is generally favorable unless you know ahead of time that you’ll need the port, in which case it’s faster to just query for it all at once.  Needless to say, you need to at least think about this issue while developing.

Lesson #1:  Understand Lazy Loading Or Be Doomed

But remember that our domain entities are being returned from a web service.  There is no way for NHibernate to open a database connection on the client.  Thus, we cannot utilize lazy loading at all.

I decided to remove the IList of port locations from the GeographicLocation class.  As it turns out, there was no code using this method, so it was a simple change.  I removed the list, removed the relevant mapping xml, and rebuilt.

The queries were reduced to 94.  That 5–minute change improved the application load time to about 6 seconds.  This is not the end of the story on improving startup time, but this was a big win at a very low cost.

There are likely other areas like this where we can break collections, but I probably will be breaking client code, and I will have to resort to adding a service method and utilizing NHibernate queries to provide the objects in a collection, rather than object graph traversal.

Lesson #2:  Don’t go crazy with your colleciton associations.  Possibly favor querying over object traversal for problem areas.

As a side-note to lesson 2, read Eric Evans’ Domain Driven Design for a much better understanding of aggregates, aggregate roots, and how to partition your domain model.

Then I started looking at the logs.  These were turned off in development, so nodody ever saw this.  I noticed that there were a ton of messages like “CodeDOM failed for class …..   unknown character `” — this was the reflection optimizer trying to compile some code on the fly to assist with getting/setting property values.  The code was listed along with the error and you could clearly see that this happened only on types that had a generic parameter.  I searched around and found that this was a bug in 1.0.2 that didn’t understand how to read the string representation of generic types.  It was fixed in 1.2.0, so I decided to upgrade. 

The upgraded version reduced the startup time to 3 seconds, and I’m pretty confident that we won’t get much better than that.  Sure we can reduce the number of queries a bit more, but we’re getting into the realm of acceptable values here.

How did we go from 6 seconds to 3 seconds?  Well the reflection optimizer had previously been turned on and was failing… once for every entitiy.  This caused an exception and easily slowed down the startup time.  Additionally, the reflection optimizer wasn’t helping out getting and settting property values so they fell back on reflection, whcih can contribute to overal runtime performance degredation.  The reflection optimizer is FAST, so let it do it’s job!  (see how fast in this article by Jay Chapman)

Lesson #3: Turn on logging (even in Dev!)

Lesson #4:  Take advantage of the reflection optimizer!

Next we took a look at one of the trouble screens and discussed how to make it faster.  The screen needed a lot of different types of data.  It had details at the top of the page, most of which were dropdown selections loaded by another entity, and the grid needed data from 3 different entities, flattened out.

The issue here is that the UI needs SO many different entities, that a signification portion of the entities are being loaded when only a subset of the data is actually being displayed.  This is an excellent opportunity for applying Screen Bound DTO’s.

A screen-bound DTO is a custom type that contains a flattened view of only the data I need to fulfill the needs of the screen.  I can utilize Projections to create slim entities that only contain name/value pairs for example.  I can accomplish this all with HQL.

This means less queries being sent to SQL server, and less data going over the wire.

Lesson #5:  Consider Screen-bound DTO’s instead of consuming your entities on the UI

On the database side, we can probably deal with a more friendly transaction isolation strategy, such as ReadCommitted.  This will allow more concurrent reads than other isolation levels.  This is accomplished through configuration.

Lesson #6:  Consider using ReadCommitted as your isolation level

We should also configure the default_schema setting to be databasename.dbo because that will be used to fully qualify the objects in all database queries.  Without this, SQL Server will not cache the query plan for these queries.

Lesson #7:  Always make sure you’ve set hibernate.default_schema

There are still more optimizations that we might make, by analyzing opportunities for cachine on both server side and the client, tweaking the mappings, and loading large data sets on a background thread to keep the UI responsive.

I believe that we will be able to achieve very acceptable performance with a lot of analysis and a tweak here and there.  Maybe then we can restore some faith in NHibernate, as it is a truly powerful persistence framework and it would be a shame to yank it because it was implemented poorly.

An excellent resource is Billy McCafferty’s article on NHibernate Best Practices with ASP.NET.  Be sure and read it if you haven’t already (it’s full of useful advanced tips on NHibernate.

Are there any perf. considerations I’ve missed?

Thursday, March 15, 2007

Writing a Simple Image Editor in CAB - Part 4

In today’s installment we’ll continue where we left off and add the functionality to apply image filters.

In order to do this, let’s take a step back and think about how we want to accomplish this.  I’m imagining two use cases:

  • Load filters from dynamic assemblies
  • Apply a filter to the image

To load the filters, I’ll have a separate assembly implement a specific interface, then they will be loaded from a directory and placed in the menu.

First, our core interface:

using System;

using System.Drawing;

 

namespace ImageFiltering

{

    public interface IImageFilter

    {

        string Name { get; }

        Bitmap Filter(Bitmap source);

    }

}

The name property determines what will be displayed on the menu.  The Filter method is, as they say on MTV Cribs, “where the magic happens.”

I’ll implement some basic image filters in a bit.  Since both of these use cases are related, I can package them up in the same module.  I create a module called ImageFiltering.

The first workitem is going to be the LoadFiltersWorkItem.  It will run at startup and read up the assemblies and obtain a list of IImageFilter implementations:

private UIExtensionSite GetMainMenu()

{

    //return the well known ui extension site for the main menu

    return RootWorkItem.UIExtensionSites["MainMenuStrip"];

}

 

protected override void OnRunStarted()

{

    base.OnRunStarted();

 

    //get the menu strip

    UIExtensionSite site = GetMainMenu();

 

    //create the new menu item

    ToolStripMenuItem filterMenu = new ToolStripMenuItem();

    filterMenu.Text = "Filters";

 

    //load the filters

    LoadFiltersFromDirectory(filterMenu);

 

    //add the filters menu to the site

    site.Add<ToolStripMenuItem>(filterMenu);

}

The LoadFiltesrFromDirectory(filterMenu) method basically uses reflection to pull out all of the assemblies in the /filters directory of our application.  The details of this aren’t important here, but if you want to see it you can download the project at the end of today’s article.

Since this needs to run when the application starts up, we code that up in the Module Init class:

public class ImageFilteringModuleInit : ModuleInit

{

    private WorkItem _rootWorkItem;

    [ServiceDependency]

    public WorkItem RootWorkItem

    {

        get { return _rootWorkItem; }

        set { _rootWorkItem = value; }

    }

 

    private LoadFiltersWorkItem _loadFiltersWorkItem;

 

    public override void Load()

    {

        base.Load();

 

        //load up our work items

        _loadFiltersWorkItem = this.RootWorkItem.WorkItems.AddNew<LoadFiltersWorkItem>("LoadFiltersWorkItem");

        _loadFiltersWorkItem.Run();

    } 

}

This is pretty basic Module Init stuff.  Create the work item and run it.  Assuming we’ve already created some filters and placed the dll inside of the filters directory, we should be able to run the application and see the filters loaded in the menu.

Our filters have been loaded

Notice how I initially set the menu items to be disabled.  This is because no image has been loaded yet!  We already have an event being raise when the image is loaded, so I handle that in the LoadFiltersWorkItem and enable the menu items:

[EventSubscription("topic://ImageEditor/ImageDisplayModule/ImageLoaded", ThreadOption.UserInterface)]

public void OnImageSelected(object sender, DataEventArgs<Bitmap> e)

{

    _image = e.Data;

    foreach (ToolStripMenuItem filterItem in _filterItems)

    {

        filterItem.Enabled = true;               

    }

}

Attached to the Tag property of each of these menu items is the concrete filter that we dynamically loaded.  The next step is to raise an event when the filter is clicked, so that the other work item (that we’re about to create) can apply the filter.

As I create each of the menu items, I wire up the click event to call this handler:

void filterItem_Click(object sender, EventArgs e)

{

    ToolStripMenuItem menuItem = sender as ToolStripMenuItem;

    IImageFilter filter = menuItem.Tag as IImageFilter;

 

    if (FilterSelected != null)

    {

        DataEventArgs<IImageFilter> args = new DataEventArgs<IImageFilter>(filter);

        FilterSelected(this, args);

    }

}

The event is raised with the concrete filter passed along as data event args.

The next work item doesn’t get created at start up.  It begins when the user clicks the menu item.  So when/where do we kick off the work item?  We handle the FilterSelected event (that is being published as a CAB event) in our module, and create the workitem there:

 [EventSubscription(ModuleConstants.Events.FilterSelected, ThreadOption.UserInterface)]

 public void OnFilterSelected(object sender, DataEventArgs<IImageFilter> e)

 {

    //get the current image

    Bitmap image = _loadFiltersWorkItem.Image;

 

    //create a new workitem to apply the filter           

    WorkItem wi = new FilterImageWorkItem(e.Data, image);

    this.RootWorkItem.WorkItems.Add(wi);

 

    wi.Run();

 }

We have to get a handle on the current image as well as the filter, and this proved to be a bit difficult.  I’d like to have some sort of global state (and maybe I’m missing something) but the State property is WorkItem specific.  I was already handling the ImageLoaded event in the LoadFiltersWorkItem, so I snag the image from that event and hang on to it.  The module reads this and passes it to the FilterImageWorkItem.  Until I can figure out a cleaner way to do this, it will have to stay for now.

Here’s the FilterImageWorkItem:

public class FilterImageWorkItem : WorkItem

{

    private IImageFilter _filter;

    private Bitmap _image;

 

    [EventPublication(ModuleConstants.Events.ImageLoaded, PublicationScope.Global)]

    public event EventHandler<DataEventArgs<Bitmap>> ImageLoaded;

 

    public FilterImageWorkItem(IImageFilter filter, Bitmap image)

    {

        _filter = filter;

        _image = image;

    }   

 

    protected override void OnRunStarted()

    {

        base.OnRunStarted();

 

        Bitmap newImage = _filter.Filter(_image);

        if (ImageLoaded != null)

        {

            ImageLoaded(this, new DataEventArgs<Bitmap>(newImage));

        }

    }

}

Pretty plain and simple.  It calls the filter on the image when it runs.  We need to notify the canvas to redraw the new image, so we raise the already implemented event ImageLoaded.  Once this fires, the DisplayImageWorkItem picks it up and displays the filtered image.

Let’s check out the app in action.

The original image
The original image

The Black & White filter applied
The Black & White filter applied

The inversion filter applied
The inversion filter applied

The image filters I originally wrote were painfully slow, so I borrowed some excellent filters from the code project article here by Christian Graus.  I’m glad I could leverage somebody else’s hard work, because it’s been a few years since I did complex image processing .

I hope you enjoyed this short series of articles on building an application using CAB.  I only touched on some of the topics.  For example, ObjectBuilder was barely used in this application.  I also didn’t use WorkItem State or the StatePersistenceService.  This would be a quick and easy way to save the users work, or you could provide a standard FileSaveDialog box.

You can download the source here:
File Attachment: CAB-ImageEditor.zip (86 KB)
(you’ll need to have CAB already installed and you need to point the reference to the CAB dlls)

I’d appreciate any comments or criticisms you may have for me.

Tuesday, March 13, 2007

Writing a Simple Image Editor in CAB - Part 3

Last time I left off with a working shell, and we loaded a single module into the shell.  In this article we’ll cover:

  • Raising and handling events
  • Invoking and handling commands
  • Adding dynamic items to a UIExtensionSite (our menu)

We have the ability to display the image, but we need to be able to load the image from somewhere. 

I created another WorkItem called ImageSelectionWorkItem.  This workitem will be responsible for loading an image and raising an event that it occurred.

using System;

using Microsoft.Practices.CompositeUI;

 

namespace ImageDisplayModule.WorkItems.Selection

{

    public class ImageSelectionWorkItem : WorkItem

    {

 

        private ImageSelectionView _view;

        private ImageSelectionPresenter _presenter;

 

        protected override void OnRunStarted()

        {

            base.OnRunStarted();

 

            //create & wire up presenter

            _presenter = this.Items.AddNew<ImageSelectionPresenter>();

 

            //create the view

            _view = new ImageSelectionView(_presenter);

 

            //run the view

            _view.Show();         

        }           

 

 

    }

}

This code here is just wiring up the view and presenter so that they can communicate.  Take note on the line where we call this.Items.AddNew<>.  This will instantiate the type provided and add it to the items collection of the WorkItem.  It is important to belong to this collection if you are going to participate in any handle or raise any CAB events or commands.  Our presenter is going to raise an event, so it needs to be added to the Items collection of the WorkItem.

Here is the presenter:

public class ImageSelectionPresenter

{

    [EventPublication(ModuleConstants.Events.ImageLoaded, PublicationScope.Global)]

    public event EventHandler<DataEventArgs<Bitmap>> ImageLoaded;

 

    public void OnFileSelected(string filename)

    {

        if (ImageLoaded != null)

        {

            Image img = Image.FromFile(filename);

            Bitmap bmp = new Bitmap(img);

 

            ImageLoaded(this, new DataEventArgs<Bitmap>(bmp));

        }

    }

}


The view is going to call this function when the user selects a file, and the presenter will raise a global CAB event.  I defined the event name as a constant so that it can be safely referred to throughout the module.

The view isn’t actually a User Control.  It’s just a class that opens a windows forms dialog for opening the file:

public class ImageSelectionView

{

 

    private ImageSelectionPresenter _presenter;

 

    public ImageSelectionView(ImageSelectionPresenter presenter)

    {

        _presenter = presenter;

    }

 

    public void Show()

    {

        using (OpenFileDialog fileDlg = new OpenFileDialog())

        {

            fileDlg.Filter = "Picture files (*.gif; *.jpg; *.bmp; *.png)|*.gif;*.png;*.bmp;*.jpg";

            DialogResult result = fileDlg.ShowDialog();

 

            if (result == DialogResult.OK)

            {

                OnFileSelected(fileDlg.FileName);

            }

        }

    }

 

    public void OnFileSelected(string filename)

    {

        _presenter.OnFileSelected(filename);

 

    }

 

}

This class focuses on the UI only, the decision on what to do is provided through the presenter.

So now that we have this WorkItem completed, we need a way to call it!  To facilitate this, we’ll load up an “Open image” menu option and load our work item when this is clicked.

Our application (the shell) has to expose the menu as a UI Extension site.  In order to do this, we need to register it.  So, in our ImageEditorApplication class:

protected override void AfterShellCreated()

{

    base.AfterShellCreated();

 

    this.RootWorkItem.UIExtensionSites.RegisterSite("MainMenuStrip", this.Shell.MainMenuStrip.Items);

    this.RootWorkItem.UIExtensionSites.RegisterSite("FileMenu", this.Shell.FileMenu.DropDownItems);

}

I registered the top-level menu as well as the File menu so we can append to it.  (Notice how I added the DropDownItems collection, rather than the item itself.  If I don’t do this then Items will be added as top level items, not children.  This took me a while to figure out…)

The next step is to find the well-known UI Extension Site for the menu (I called it “FileMenu”) and add our menu item to it (from the Module).  The reason this looks indirect is because CAB applications are, by nature, loosely-coupled.  This is a good thing.

Our module init class now looks like this:

public class ImageDisplayModuleInit : ModuleInit

{

    private WorkItem _rootWorkItem;

    [ServiceDependency]

    public WorkItem RootWorkItem

    {

        get { return _rootWorkItem; }

        set { _rootWorkItem = value; }

    }

 

    public override void Load()

    {

        base.Load();                       

 

        //create workitem(s)

        DisplayImageWorkItem wi = RootWorkItem.WorkItems.AddNew<DisplayImageWorkItem>();

 

        //modify the ui extension sites

        CreateMenuItems();

 

        //run the workitem

        wi.Run();

    }

 

    private void CreateMenuItems()

    {           

        //creat file->open menu item & register click command invoker

        ToolStripMenuItem fileOpen = new ToolStripMenuItem("Open Image");

        RootWorkItem.Commands[ModuleConstants.Commands.LoadImage].AddInvoker(fileOpen, "Click");

 

        //add it to the file menu

        UIExtensionSite site = RootWorkItem.UIExtensionSites["FileMenu"];                       

        site.Add<ToolStripMenuItem>(fileOpen);

    }

 

    [CommandHandler(ModuleConstants.Commands.LoadImage)]

    public void LoadImage(object sender, EventArgs e)

    {

        string id = "LoadImageWorkItem";

        ImageSelectionWorkItem wi;

        if (RootWorkItem.WorkItems.Contains(id))

        {

            wi = RootWorkItem.WorkItems[id] as ImageSelectionWorkItem;

        }

        else

        {

            wi = RootWorkItem.WorkItems.AddNew<ImageSelectionWorkItem>(id);

        }

 

        wi.Run();

    }

}

There is a lot going on here, so I’ll take it in pieces.  First off, we added a call to CreateMenuItems().  This method will be responsible for loading any menu items required by its work items.   We create our menu item for “Open Image” and add it’s click event as a Command Invoker.  This is very similar to wiring up events.

We also have a method decorated with the CommandHandler attribute.  This is the handler for when the menu item is clicked.  It’s purpose is to create and launch the new image selection work item.

So if we can recap for a moment, our module loads, it stuffs in a new menu item into the File menu.  The user clicks this, which invokes a command called “LoadImage”.  A Command Handler picks this up and launches the ImageSelectionWorkItem.  It will display an open file dialog where the user can select an image.  Once the image is selected, an event is published.  We currently have a subscriber to this event, and it’s job is to load the selected image into the display work item.

If we run the application, we can now browse for an image, select it, and it loads onto our canvas:

Our new menu item, loaded into the UI Extension site

CropperCapture[49]

So at this point we’ve touched on most of the CAB concepts.  Next we’ll introduce another module for Filtering the image, kind of like a mini-photoshop (maybe that’s going too far, but you get the idea…).

Until next time!

Friday, March 09, 2007

Writing a Simple Image Editor in CAB - Part 2

So after part 1, we have a shell ready to go.  We haven’t done anything CABish yet, but we will in this post.

The first thing we need to do is create our layout that modules will be loaded into.  If you remember, CAB Shells basically contain 2 possible things:  Workspaces and UI Extension sites.  It just so happens that we’ll need both!

First, we’ll need a menu for loading the image and applying filters.  That will be our UI Extension Site.

Second we need a workspace in which to load the image display module.

Our first UI Extension Site

Here I added a MenuStrip and created our default File menu.  Give it a name like mainMenuToolStrip so that you can refer to it later.

Next we want to add a workspace so that we can load the image.  To gain access to these CAB UI controls, you need to add them to the toolbox on the left.  Right click on the Toolbox Pane, select Add Tab and name it CAB Controls.  Then right click on the name and select Choose Items.  You’ll have to Browse for the Microsoft.Practices.CompositeUI.WinForms.dll.  Select all of the controls and click OK.

Now you should see a toolbox group like this:

CropperCapture[43]

We will use the DeckWorkspace control.  Drag that onto the form and name it mainWorkspace.  Make sure that you dock it to fill the form.

It should look like this:

CropperCapture[44]

We have our basic form, now it’s time to load the first module into it!

Create a new class library project called ImageDisplayModule.  Rename Class1.cs to ImageDisplayModuleInit.cs.  You’ll need a reference to the dlls mentioned above as well.

If you recall, a module contains work items.  Our first work item is DisplayImageWorkItem.  It’s responsibility is to load an image and display it on the form.

Let’s start out by creating the View.  The view is a user control with a [SmartPart] attribute applied.  The view is going to consist of an ImagePlaceHolder.   Also keep in mind that we are doing this with Model-View-Presenter, so we’ll start by identifying the interface for our view.

Create an interface called IDisplayImageView.  The only real member that this interface ensures is that you can set and retrieve an image.

public interface IDisplayImageView

{

    public Bitmap Image

    {

        get;

        set;

    }

 

}

Next, create a new UserControl called DisplayImageView.  This user control needs to implement the IDisplayImageView interface.  Also notice that I have placed the [SmartPart] attribute on the class as well.

using System;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.Practices.CompositeUI.SmartParts;

 

namespace ImageDisplayModule.cs.WorkItems

{

    [SmartPart]

    public partial class DisplayImageView : UserControl, IDisplayImageView

    {

        private Bitmap _image;

 

        public DisplayImageView()

        {

            InitializeComponent();

        }

 

        #region IDisplayImageView Members

 

        public Bitmap Image

        {

            get { return _image; }

            set { _image = value; }

        }

 

        #endregion

    }

}

 Next, we’ll switch over to design view and drag a PictureBox on the control.  I’ve also added a dummy label so that we can identify this control on the form in a minute.

Here’s what it looks like:

CropperCapture[45]

I’ve also created a presenter that will control all of the UI logic for this view:

public class DisplayImagePresenter

{

    private IDisplayImageView _view;

 

    public DisplayImagePresenter(IDisplayImageView view)

    {

        _view = view;

    }

 

    [EventSubscription("topic://ImageEditor/ImageDisplayModule/ImageLoaded", Thread=ThreadOption.UserInterface)]

    public void OnImageLoaded(object sender, DataEventArgs<Bitmap> e)

    {

        _view.Image = e.Data;

    }

}

Here you can see that the view is accepted in the construtor, and we are responding to an event.  The topic:// is just a hierarchical way of naming events that we might care about.  Basically the presenter is going to listen for an event when a picture is loaded, and set the image to the view once it fires.

In order to load this module into our shell, we need a few more pieces.  The first is a ProfileCatalog.xml file.  This tells the shell what modules to load.

Place an xml file in the shell project and make sure that the properties are set to Copy Always so that it will end up in your output directory.  The file should look like this:

<?xml version="1.0" encoding="utf-8" ?>

<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile">

  <Modules>

    <ModuleInfo AssemblyFile="ImageDisplayModule.dll" />

  </Modules>

</SolutionProfile>

The important concept to grasp here is that there is no project level reference to the module project.  The dll is placed directly in the shell’s bin folder, and CAB is going to read this file to know to load it.

When CAB goes to load a module, it will scan the assembly for a class that inherits from ModuleInit.  So, I created an ImageDisplayModuleInit class :

public class ImageDisplayModuleInit : ModuleInit

{

    private WorkItem _rootWorkItem;

    [ServiceDependency]

    public WorkItem RootWorkItem

    {

        get { return _rootWorkItem; }

        set { _rootWorkItem = value; }

    }

 

    public override void Load()

    {

        base.Load();

 

        //create workitem

        DisplayImageWorkItem wi = RootWorkItem.WorkItems.AddNew<DisplayImageWorkItem>();

 

        //run the workitem

        wi.Run();

    }

Here we take a reference to the Root WorkItem, which is provided to us through the [ServiceDependency] attribute from ObjectBuilder.  The Load() method is called which instantiates our work item and runs it.

The work item then needs to load up any smartparts and place them in the required workspaces.

public class DisplayImageWorkItem : WorkItem

{

    private IDisplayImageView _view;

    private DisplayImagePresenter _presenter;

 

    protected override void OnRunStarted()

    {

        base.OnRunStarted();

 

        ShowView();

    }

 

    private void ShowView()

    {

        //create the view

        _view = this.SmartParts.AddNew<DisplayImageView>();

        _presenter = new DisplayImagePresenter(_view);

 

        this.Workspaces["mainWorkspace"].Show(_view);

    }

}

This part is pretty self explanatory.  We take the workspace name from the shell and tell it to show our smart part.

Everything is wired up now, so if you run the application you should see that the module has been loaded into the shell.

the app running with a module loaded

If you have troubles getting everything to work, make sure that your Module project is setup to output the dll inside the Shell’s bin folder, and also verify that the profile catalog xml file is placed there as well.

Next time we’ll figure out how to load the image using a different workitem.

Writing a Simple Image Editor in CAB - Part 1

I promised posts with more “meat,” so here it goes.  I’m going to demonstrate how to start writing a CAB application by building a simple image manipulation program.

Overview:
The application will load an image from some flexible source (file system, flickr, whatever).  The image will be displayed on the canvas.  The user will have various filters to apply to the image.  These filters should be easily added later on, and they should all manipulate the image in some way.  When everything is done, the user will have the option of saving the changes to disk.

So now that we have our high-level description of the app, let’s build it!

Start up Visual Studio 2005, create a blank solution called CAB-ImageEditor.  Add a new C# Windows application called ImageEditorShell.  This will be the basic structure of the application, and we will add things to it.

Add the following references to your project:

  • Microsoft.Practices.CompositeUI
  • Microsoft.Practices.ObjectBuilder
  • Microsoft.Practices.CompositeUI.WinForms

First you need to delete the files that Visual Studio gives you out of the box.  We will start from scratch.

Create a new Form called ImageEditorShell.cs.  Give it a window title if you like.

Our blank shell

Create a new class called ImageEditorApplication.cs.  This will be the entry point for our application.  We need to inherit the class from FormShellApplication<T,K> and give it the type of the root work item and our shell.

using System;

using Microsoft.Practices.CompositeUI;

using Microsoft.Practices.CompositeUI.WinForms;

 

namespace ImageEditorShell

{

    public class ImageEditorApplication : FormShellApplication<WorkItem, ImageEditorShell>

    {

    }

}

We need an entry point to start the application, so add that…

public class ImageEditorApplication : FormShellApplication<WorkItem, ImageEditorShell>

{

    [STAThread]

    public static void Main()

    {

        new ImageEditorApplication().Run();

    }       

}

That’s all we need to get our application running.  Go ahead and push F5 and see what happens.

Man, are you impressed yet?  Hehe, chill out.  There’s more to come…

CAB - Hands on Labs

The very best resource I have found so far about working with CAB are the Hands On Labs.

For some reason they were very difficult to find for me.

If you’re looking to understand CAB from a very beginner’s perspective, then I highly recommend you go through them.  There are 9 in total.

Wednesday, March 07, 2007

What's in a CAB Module?

One of the root components of a CAB Application is the module.  So what is a module, exactly?

A Module is basically a collection of WorkItems.  Since WorkItems are generally 1:1 with use cases, then modules are a package for related use cases.

Modules

Modules get loaded by the application Shell, via the ProfileCatalog.xml file.  When you are structuring your solution, you do not include a project reference to the module project in your shell project.

One benefit of doing this is that you can create new modules and load them into a shell without recompiling the main shell solutions.  You could easily package up a patch which included a new ProfileCatalog.xml and a dll as a zip file.

Modules also help you organize your WorkItems into logical units so that they become more managable.

 

Digging into CAB - The Terminology

The Composite UI Application Block (or CAB for short) has a lot of terminology to understand.  In order to follow the downloadable samples you should first brush up on what the various components of CAB are.

Shell
The Shell is basically your application.  The Shell’s responsibility is to load and initialize UI services, modules, and other CAB components.  The Shell itself won’t contain many direct UI elements (these will be added later).  The Shell will typically house UIExtensionSites and Workspaces.

Module
Modules are basically packages of WorkItems, which we will see next.  Modules are defined in the ProfileCatalog.xml file so CAB can load them and they have constructs for initializing.  Each module resides it its own assembly.

WorkItem
Your use cases will generally become WorkItems.  A WorkItem is a container for UI elements, model classes, state, and services that are required to satisfy the use-case.  If you were using NHibernate, this would be an ideal place to demarcate your ISession boundary.

Workspace
Workspaces are the containers on your UI that SmartParts (User Controls) can be loaded.  Examples include DeckWorkspace, TabWorkspace, etc.  Workspaces can be moved around and replaced at runtime easily.

UI Extension Sites
UI Extension Sites are static UI elements, such as Menus and Toolstrips, and as such are added directly to the shell.  Different work items can access these to modify their contents.  A good example is setting status text in a status bar at the bottom of the application shell or adding menu items depending on what tab has focus.

SmartParts
SmartParts are your basic user controls, only denoted with a [SmartPart] attribute.  Think of these as the “View” in Model-View-Controller.  As such, these will contain controls, however all logic will be deferred to a controller or presenter class.

Service
As you might expect, Services are very vague.  They can be any type of service that provides your UI with logic or data.  In a CAB architecture, you will abstract most of the data and calculations to services that are consumed by the UI.  Out of the box CAB comes with a Catalog service for loading modules, a State service for persisting WorkItem state to a file or isolated storage, and an authorization service.

 

I think that gives us a good overview of the main terms and responsibilities.  Until next time…

Wednesday, August 23, 2006

A Journey with Domain Driven Design (and NHibernate) - Part 5

In Part 5 of our Journey with Domain Driven Design & NHibernate, we introduce the database structure to support our objects. We also configure NHibernate and build a helper class to assist in the usage of NHibernate.
Sunday, July 23, 2006

A Journey with Domain Driven Design (and NHibernate) - Part 4

In Part 4 of the series, I dig deeper into the tests to fill out the requirements. We talk briefly about some Domain Driven Design concepts and finish up with enough functionality to move on to the database.
Wednesday, July 19, 2006

A Journey With NHibernate (and DDD) - Part 3

In Part 3 of the series, I jump head first into unit testing our domain model with NHibernate.
Monday, July 10, 2006

A Journey With NHibernate - Part 2

In Part 2 of the series we create our project structure and introduce a first-draft implementation of our model.
Wednesday, July 05, 2006

A Journey with NHibernate - Part 1

In this series of articles we will dive into the world of Domain Driven Design. Along the way we'll focus on concepts of Object Oriented Design, Test Driven Development, Refactoring, and Object-Relational Mapping with NHibernate.
Tuesday, June 20, 2006

Adding connection strings at runtime

Today I noticed how non-intuitive it is to write to the configuration file programatically for an application.  What I needed to do was dynamically create a connection string, then write it to the app.config file.

Here’s how you do it:

first, you need to add a project reference to the System.Configuration assembly.  Add a corresponding using clause to the top of your class.

   using System.Configuration;

Next you need to find and open the configuration file.  In win forms, you do this by specifying the full path to your application’s executable.  If you project is at c:\code\project1 then you would pass in something like this: “c:\code\project1\bin\debug\project1.exe”.

 Configuration config = ConfigurationManager.OpenExeConfiguration(FULL_EXE_PATH);

 

 ConnectionStringSettings connStringSettings = new ConnectionStringSettings("database",

     "connection_string_here");

 

 config.ConnectionStrings.ConnectionStrings.Add(connStringSettings);

 

 config.Save();

For ASP.NET, you can follow the same principle, but use the System.Web.Configuration namespace in conjunction with WebConfigurationManager.OpenWebConfiguration(path) where path is the url of your root, for example http://localhost/webapp1 (notice there is no trailing slash).