Sunday, June 03, 2007

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

Back by popular demand… (and WAY too late, I might add…)

In this article, part 9 of the series, we’re going to wrap up our initial feature list and focus on building a user-interface for our video store, named Videocracy.

Here is our feature list:

  • Add new Customer / Account
  • Add other members to an account
  • Restrict Certain members from renting certain content
  • Query for a customer by customer # (swipe card, etc), phone number, or last name
  • Add new rental item (move game, console, vcr, etc)
  • Rent an item to a customer
  • Check Items Back in
  • Get movies checked out for a customer
  • Query for an item, see who has it

Let’s implement Check Items Back In.

What is the use case here?  Typically a customer drops off a movie, either in the slot from the outside of the store, or directly to an employee.  Either case starts with the movie, or the Item.

So the employee is going to scan the item.  At this time, they are going to need to see the details of who and when the item was checked out (the Rental object), and then have a confirmation button to finalize the check-in (which will update the Rental object).

In order to facilitate scanning the item, we need to be able to query the database for a particular UPC.

In implementing this next test I noticed a large problem with my domain.  Our Item class defines a name property with a mapped column in the database.  The problem with this is that not all items have names of their own.  They might have display names that are a combination of other properties.  For example, a video copy of the movie The Matrix shouldn’t have a name of ‘The Matrix’ (it really belongs to the Movie class).  Typically the text on the outside of a video rental is the movie name followed by maybe the year, and the format that the movie is in.  These are deferred properties, so there is no more need for a database column in the item class.  I still provide a read-only Name property, and inherited classes have to provide this information.  Would you have made a large change like this so eagerly in your project?  If you did, how would you know if you broke some existing functionality?  As I always say, it’s a good thing I have the tests to back me up…

Here’s our next test:

      [Test]

        public void Can_Check_In_Item()

        {

            Item i = TestHelper.CreateTestItem("Test_ITEM123", "1234_UPC");

            Customer c = TestHelper.GetTestCustomer();

            Employee empl = TestHelper.CreateTestEmployee();

 

            using (ISession session = SessionSource.Current.GetSession())

            {

                using (ITransaction tx = session.BeginTransaction())

                {

                    //store the customer and employees

                    session.Save(c);

                    session.Save(empl);

 

                    //check the item out to the customer

                    Rental r = new Rental(i, 2.30f);

                    RentalTransaction trans = c.CreateTransaction();

                    trans.Employee = empl;

                    trans.AddRental(r);

 

                    session.Save(c);

                    session.Save(trans);

 

                    tx.Commit();

                }

            }         

 

            //item is checked out, can we check it back in?

            Item i2 = Repository<Item>.FindSingleByProperty("UPC", "1234_UPC");

            Assert.IsNotNull(i2); //just a sanity check.  Item exists in the table.

 

            //we need to get the rental by the item upc

            Rental r2 = new RentalFinder().FindByItemUPC(i2.Upc);

 

            Assert.IsNotNull(r2, "Rental was null!");

        }

There is a lot going on in this test, so let’s break it up and take a look at each part.

            Item i = TestHelper.CreateTestItem("Test_ITEM123", "1234_UPC");

            Customer c = TestHelper.GetTestCustomer();

            Employee empl = TestHelper.CreateTestEmployee();

 

            using (ISession session = SessionSource.Current.GetSession())

            {

                using (ITransaction tx = session.BeginTransaction())

                {

                    //store the customer and employees

                    session.Save(c);

                    session.Save(empl);
                    . . .

Here we setup our environment.  We have to have a lot of entities that already exist in order to test our new funtionality.  We need an item, a customer, and employee, and an account.  We create all of those and save them.  (Remember all of this happens within a transaction that is rolled back, so this doesn’t stay in the database).

 

                    //check the item out to the customer

                    Rental r = new Rental(i, 2.30f);

                    RentalTransaction trans = c.CreateTransaction();

                    trans.Employee = empl;

                    trans.AddRental(r);

 

                    session.Save(c);

                    session.Save(trans);

 

                    tx.Commit();

 

Here we setup the rental and perform the rental transaction.  This is how the UI will structure the business process.  Once everything is saved, it’s time to verify that we can retrieve the data solely based on the item’s upc code.

            //item is checked out, can we check it back in?

            Item i2 = Repository<Item>.FindSingleByProperty("UPC", "1234_UPC");

            Assert.IsNotNull(i2); //just a sanity check.  Item exists in the table.

 

            //we need to get the rental by the item upc

            Rental r2 = new RentalFinder().FindByItemUPC(i2.Upc);

 

            Assert.IsNotNull(r2, "Rental was null!");

The Rental Finder class will encapsultate common queries so that we can reuse them across the application.  Here’s the code for that method:

public Rental FindByItemUPC(string upc)

{

    Rental r = Repository<Rental>.FindSingleByQuery("from Rental r where r.Item.Upc = :upc and r.DateReturned is null", new Parameter("upc", upc));

    return r;

}

There is a lot going on here in this test, but what you need to get from this is that we are setting up the stage for our scenario.  As our tests get more involved we are verifying that business cases are being met.  If we make drastic changes later on, we will know if we have broken existing business functionality.

The next thing to check is to make sure that we can check the item back in.  I add a .Return() method on the rental, which doesn’t exist yet, so I need some additional tests.

I also need to be able to calculate late fees in a central place to make that easy to change later.  I add a few tests for this as well.

It turns out that the Return() method is easy to implement.  All we need to do is set the return date and calculate the late fee and save it.

[Test]

public void CanReturnItem()

{

    Rental r1 = GetTestRental(DateTime.Now.AddDays(-6));

 

    r1.Return();

 

    Assert.IsTrue(r1.DateReturned.HasValue);

 

    //it's 1 day late, so expect the right late fee

    float lateFee = Utility.LATE_FEE_PER_DAY;

    Assert.AreEqual(lateFee, r1.LateFee);

 

}

which leads to the following code in the Rental class…

public void Return()

{

    this.DateReturned = DateTime.Now;

    this.LateFee = Utility.CalculateLateFee(_dateDue, _dateReturned.Value);

}

Now we need to finish the original test and verify that we can save the rental.

 r2.Return();

 

 //save the rental

 using (ISession session = SessionSource.Current.GetSession())

 {

    using (ITransaction tx = session.BeginTransaction())

    {

        session.SaveOrUpdate(r2);

        tx.Commit();

    }

 }

This test passes and we’ve implemented our feature!

I think I’m at a point where I have demonstrated how we can work on core business features for an application test-first, using NHibernate along the way for persistence.  A lot more work has to be done to complete our domain model, but that will be left as an excercise for the reader.

Instead, I would like to focus my efforts on getting a basic UI in place using ASP.NET.  I said in part 1 that I wanted to demonstrate how to work with the NHibernate Session in a web environment, so that’s where I will pick up next time.

Until then, you can download and view the current project here:

File Attachment: Videocracy_09.zip (3442 KB)

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…

Monday, November 13, 2006

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

After a very long spell of inactivity, we’re back for Part 7 of the series!

Last time we left off with a decent domain model, a database, and the beginnings of NHibernate.

Since the last article, the NHibernate team has produced the ever-so-fantastic v1.2.0 beta 1.  This release supports numerous new exciting features.  Topping the list of cool new features is:  native support for .NET GenericsNative SQL 2005 is also supported.  Another feature was just enabled that will really help bridge the gap for those folks who will clutch to stored procedures forever:  Stored Procedure / Custom Query Support.

I’ll start today by slapping in this version of NHibernate and do a little bit of housekeeping.  With this new version of NHibernate, I no longer have a need for NHibernate.Generics (and thus I will remove it).  Some people might still use it, as it has the nice side-effect of automatically managing bi-directional relationships (which we’ll visit later), however I’m going to show this manually in this series.

I’ve changed my EntityList<T> / EntityRef<T> / EntitySet<T> to normal generic collections, and NHibernate will use them automatically.  These classes do provide you with an extra nifty feature (explained later), but it’s important to understand what it does under the hood, so I will implement the functionality the manual way, and later I’ll reference these classes to show how you might still want to use them.

So I’ve remove the old dll of NHibernate and I referenced in the new one.  I also updated my nhibernate schema file in Visual Studio so that I get the updated intellisense.  I compile, nothing is broken, and we’re ready to test!  The beauty of having our unit tests is that we have much more confidence that we know exactly what to fix, and we also know the instant that we are done fixing any breaking changes.  Our application returns to a known state of behavior very quickly.

Since I’ve made persistence level changes (the new NHibernate dll) as well as domain model changes (replacing NHibernate.Generics.Entity*<T> with standard .NET generic lists) I need to run both test assemblies.

 Here are the immediate results of the tests:

TestCase 'Flux88.Videocracy.Persistence.Tests.PersonTester.TestCanListPeople' failed: NHibernate.InvalidProxyTypeException : Type 'Flux88.Videocracy.DomainModel.Person' cannot be specified as proxy: method get_Id should be virtual
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(28,0): at NHibernate.Proxy.ProxyTypeValidator.Error(Type type, String reason)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(76,0): at NHibernate.Proxy.ProxyTypeValidator.CheckMethodIsVirtual(Type type, MethodInfo method)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(63,0): at NHibernate.Proxy.ProxyTypeValidator.CheckEveryPublicMemberIsVirtual(Type type)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(22,0): at NHibernate.Proxy.ProxyTypeValidator.ValidateType(Type type)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Cfg\Configuration.cs(915,0): at NHibernate.Cfg.Configuration.ValidateProxyInterface(PersistentClass persistentClass)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Cfg\Configuration.cs(891,0): at NHibernate.Cfg.Configuration.Validate()
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Cfg\Configuration.cs(1035,0): at NHibernate.Cfg.Configuration.BuildSessionFactory()
	c:\sandbox\Videocracy\Flux88.Videocracy.Persistence\SessionSource.cs(55,0): at Flux88.Videocracy.Persistence.SessionSource.Initialize()
	c:\sandbox\Videocracy\Flux88.Videocracy.Persistence\SessionSource.cs(81,0): at Flux88.Videocracy.Persistence.SessionSource.GetSession()
	c:\sandbox\Videocracy\Flux88.Videocracy.Persistence.Tests\PersonTester.cs(27,0): at Flux88.Videocracy.Persistence.Tests.PersonTester.TestCanListPeople()

We have a few failing tests, however they all relate to the same problem.  NHibernate 1.2.0 beta 1 now sets everything to lazy-load by default.  This means that our objects must be able to be inherited so that NHibernate can inject proxy subclasses of our objects (the consumer doesn’t know or care that this happens).  To do this all of the methods and properties need to be virtual.   This is a large change, and it’s not something I entirely agree with, but it’s very easy to turn off.   (It pays to read the release notes of these 3rd party products!)  We’ll discuss how to effectively lazy-load a bit further on.

In our mapping file, we can specify default-lazy=”false” to override this behavior.  At a later time we may investigate and find that the class will benefit from lazy loading and we’ll revert it, but until then I’ll just make all the classes default-lazy=”false”.

Here’s the change:

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

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"

                  namespace="Flux88.Videocracy.DomainModel"

                  assembly="Flux88.Videocracy.DomainModel"

                  default-lazy="false"

                  >

 

  <class name="Person" table="People">

     …

  </class>

 

</hibernate-mapping>

Once that change is in place, all 5 of my persistence tests are passing.   I have 6 failing tests in my domain model, mostly due to my careless replacement of the EntityRef stuff with standard .NET collections.  The tests expose my oversights and once I fix them I’m back on track.

Ok, now where were we?  (It’s been a while, so I open NUnit and see that we have Save/List/Load for a Person object, but nothing else). We introduced some simple mapping concepts, and this time we’ll dig in a bit deeper.

How does NHibernate deal with associations?  Lets start with Account.  Account has a collection of Customer objects that represent its members.  In standard database terms, Account is a one-to-many with Customer.  How do we map this kind of relationship with NHibernate?

There are a few choices when looking at the documentation for NHibernate.  To understand them you must understand the semantics of each kind of list.  Ask yourself these questions:

  • is it one-to-one?  many-to-one?  many-to-many?
  • does order matter?
  • is it bidirectional?

From the NHibernate FAQ, we find this informative nugget, that explains the collections available to us (and their .NET counterparts):

  • The <list> maps directly to an IList.
  • The <map> maps directly to an IDictionary.
  • The <bag> maps to an IList. A <bag> does not completely comply with the IList interface because the Add() method is not guaranteed to return the correct index. An object can be added to a <bag> without initializing the IList. Make sure to either hide the IList from the consumers of your API or make it well documented.
  • The <set> maps to an Iesi.Collections.ISet. That interface is part of the Iesi.Collections assembly distributed with NHibernate.

Our Account -> Customer relationship is one-to-many.  I could choose to allow one customer to have many accounts, but I don’t see any real use for that yet.  Order does not matter either.  I could have 4 members on an account, and it doesn’t really matter what order they are given to my in a list. 

We also have to consider what each end of the association looks like.  Right now I’m looking at it from the perspective of Account, where Account has many Customers (members).  On the customer object, the customer only has one Account, so this isn’t a bidirectional association.  (We’ll see an example of this later).  Techically our collection maps to an ISet, but I’d rather not depend on the Iesi.Collections.dll, so I’m going to map it to a list (the only drawback is that the list will allow the same member twice, so I’ll just get around this in our model manually).

Here’s how we’ll deal with that:

/// <summary>

/// Adds a member to this account

/// </summary>

/// <param name="customer"></param>

public void AddMember(Customer customer)

{

    //ignore multiple adds for the same customer.

    if(_members.Contains(customer)) return;

 

    _members.Add(customer);

 

    //make sure that our association is handled on both sides

    customer.Account = this;

}

 

/// <summary>

/// Removes a member from this account.

/// </summary>

/// <param name="customer"></param>

public void RemoveMember(Customer customer)

{

    //ignore the call if the customer isn't a member of this account

    if (!_members.Contains(customer)) return;

 

    _members.Remove(customer);

 

    //make sure that our association is handled on both sides

    customer.Account = null;

}

 The rest of the class is self-explanatory, so I won’t include it here.  You’ll  be able to download the project at the end of today’s article, however.

Next up is the mapping.  Let’s take another look at the table structure for reference:

CropperCapture[4]

This is slightly different than what was in the last archive.  Instead of an account having a single primary customer, any customer can be the ‘Owner’ of his/her account.  I chose to keep the association simple for this demo.  I also wanted to allow multiple ‘Owners’ for a single account.  I’ve updated the tests to reflect this change.

Here you see that many customers belong to exactly one account.    This is a one-to-many relationship from Account to Customer.

If we stop and think about the domain for a minute, we can determine that the Customer will be identified first (by his/her ID or Account #) and that needs to be able to pull up the account.  I’d also like to keep this relationship bidirectional.  That means that I need to map the relationship on both classes so that we can do this:

customer.Account ….  

or this:

for each Customer c in _account.Members { … }

Here is the relevant mapping for Customer:

 <!-- CUSTOMER  -->

 <joined-subclass name="Customer" table="Customers">

  <key column="PersonId" />

 

  <!-- todo:  map this to an enumeration -->

  <property name="RentalRestriction" type="Int32" column="rentalRestrictionId" />

 

  <many-to-one name="Account" class="Account" column="accountId" cascade="save-update" />

 

 </joined-subclass>

This tells NHibernate that this is the *many* end of a one-to-many association.  We tell it the property name, type, foreign key column name, and our cascade strategy.  This basically means, whenever we save or update our Customer, cascade the save/update to the Account as well.  You can also specify to cascade deletes as well if you need to.

The Account mapping looks like this:

 <class name="Account" table="Accounts" where="Active=1">

 

    <!-- ... -->

 

    <bag name="Members" access="nosetter.camelcase-underscore" lazy="true" 
         
cascade="save-update" inverse="true">

         <!-- this key refers to the Account key in the Customer table -->

         <key column="accountId" />

         <one-to-many class="Customer" />     

    </bag>

 

 </class>

This section tells NHibernate to map this association as a bag.  Lazy=true means that the collection will only actually be retrieved from the database once it is accessed.  NHibernate does this by silently replacing our IList with a proxy that knows about the session and how to hydrate the collection.  This is 100% transparent to our consumers, so make sure you are using this in appropriate places.  Lazy=false will force NHibernate to pre-load the entire association (and it’s associations(and it’s associations(…. you get the point…))). 

To test that this association worked, I wrote a simple test:

 [Test]

 public void CanSaveCustomerAndAccount()

 {

    Customer c = TestHelper.GetTestCustomer();

 

    Account a = new Account();

    a.AddMember(c);

 

    using (ISession session = SessionSource.Current.GetSession())

    {

        using (ITransaction tx = session.BeginTransaction())

        {

            session.SaveOrUpdate(c);

            session.Flush();

 

            session.Evict(c); //make sure we don't get an object from the cache

 

            Assert.AreNotEqual(0, c.Id, "Customer didn't get an Id after save");

            Assert.AreNotEqual(0, a.Id, "Account didn't get an Id after save");

 

            Customer customerFromDb = session.Get<Customer>(c.Id);

 

            Assert.AreNotSame(c, customerFromDb, "Got same instance of customer!");

            Assert.AreEqual(a, customerFromDb.Account, "Account didn't get saved");

 

            tx.Rollback();

        }

    }

 }

This test is passing and we have our first association mapped!

I think this is a good stopping point.   We have migrated our version of NHibernate and our tests forced us to fix any outstanding issues before continuing.  We also identified our first association, mapped it, and tested it.

From here on out I will step up the pace and start glossing over the details a bit and focus on getting working product done using this domain model.  As I begin writing some UI components I will come across some features I have not developed, which may require more mapping changes and tests.  In order to finish this series sometime this year I’ll be speeding up a bit.  I will still continue to post the source so that you may follow along.  If you have comments or questions, feel free to comment.

Here is the latest source:

File Attachment: Videocracy_07.zip (44 KB)

Friday, September 01, 2006

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

Welcome back!  In Part 5 we finished off with a table structure and the beginnings of NHibernate.  We’ll dive in deeper with NHibernate and mapping in this article.

(part 1 was Dugg, which was quite exciting to me!  It has also increased the traffic around here a little bit!  If you’re enjoying the series, why not Digg it some more?)

Currently we can initialize our SessionFactory which reads the configuration file and loads our domain model assembly.  This step is where NHibernate will parse our mapping files (once we add them).

So let’s take a step back and ask the question that’s probably on your minds already: how do we get our classes mapped to the database using NHibernate?  We have to provide a mapping file.  An NHibernate mapping file is an xml file that specifies how your object fields and properties map to database columns.  There are a few ways you can load mapping files into NHibernate, but the easiest I have found is to add them as part of your domain model class library as embedded resources (details below).   I emphasize embedded resources because if you just add the XML files without specifying they will not be recognized automatically by our SessionFactory initialization.

A number of people have asked me to display more source code, and in this article you’ll see the domain model in more detail.  At the end of this article I will post the code that we’ve created so far.

If you are a little scared about writing these mapping files and would rather use a tool to generate it for you that is certainly possible.  Ayende Rahien’s NHibernate Query Analyzer can help with this.  I have found, however, that in order to fully understand how to effectively map your objects, you should write the mapping by hand.  Don’t fret, there is hope with the manual method.  The hope?  Intellisense.  To get nhibernate mapping intellisense in Visual Studio 2005 you can copy the schema file (nhibernate-mapping-2.0.xsd) to C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas.

Now that we have intellisense for our mapping files, we can start creating our mappings.  I choose to have a single mapping file per class, so that they don’t get too cluttered.  There is nothing to stop you from defining your entire object model in a single mapping file, but I avoid this approach.

CropperCapture[26]Starting off with the Person class, we create add a new XML file to our domain model project called Person.hbm.xml.  NHibernate will search our assembly for embedded resources named *.hbm.xml.  If this is mispelled or the file is not marked as an embedded resource the mapping will not be found and NHibernate wonâ