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?

Tuesday, November 20, 2007

Book Review - ASP.NET 2.0 Anthology

A few weeks ago, Jeff Atwood sent me a free review copy of his new book, The ASP.NET 2.0 Anthology.  He co-authored the book with K. Scott Allen (from OdeToCode), Wyatt Barnett, Jon Galloway, and Phil Haack.

Normally I wouldn't get excited about a book like this, but looking at that list of authors I was more than intrigued to give it a try.  Granted, the book is targeted for the beginner to intermediate ASP.NET developer, so a lot of it was not very helpful to me, but I did find quite a few good nuggets that I will take away and utilize in the future.

The first few chapters give a general overview of the newer features of .NET 2.0 and some other basic concepts.  I think that this would be helpful to someone just coming to ASP.NET (maybe from another language) and want to get started. 

The book was published by SitePoint, under their "Anthology" style.  This means the book is organized into 101 different "tips" phrased as questions that someone might ask on a forum or similar.  Some examples from Chapter 1 are "How do I use source control?" and "How do I go about using open source code?" -- I was pleased to see these sections in the book.  You normally wouldn't expect this and I think it helped make the book more well-rounded.

The middle chapters were a bit more targeted to the intermediate ASP.NET level, which made it more interesting for me.  They covered things like custom configuration sections, custom validation, how to maintain control state when viewstate is turned off.  All throughout I think the authors gave solid advice on all these features.  There was a good section on Membership and Access Control, which is sure to be helpful to intermediate ASP.NET developers.

The last few chapters were the most interesting to me, which is funny because most of them weren't specific to ASP.NET.  A section on troubleshooting bothersome SQL queries is sure to help people out.  There were a good number of general web developer tips, such as considering SEO and clean HTML for good search engine rankings.  I appreciated the tip on how to utilize URL rewriting at the IIS level, and how to serve-up custom images to evil hotlinkers on myspace (thanks Jeff Jon!).  These types of things are great to know when pursuing a career as a web developer.  The last chapter introduced SubSonic, which I think was awesome.  Not many developers that I meet have heard of SubSonic and I find it to be a pretty useful tool with a low barrier of entry.  It definitely warranted some attention in this book.

While a lot of the content was your typical ASP.NET 2.0 fodder that I avoid (like SqlDataSource), I thought that the authors did a good job of noting when things were applicable, for example when to use the Web Site model vs. Web Application Projects.  The book didn't have enough beginner content and explanation of ASP.NET to be a beginner book (which is a good thing), but it did have quite a lot of excellent tips that makes this book a great companion to any intermediate developer.

Friday, November 09, 2007

On Fluent Interfaces and Friction

So I decided to start that NHibernate Mapping DSL project and open-source it.  Right now it doesn't do anything, but you're free to take a look at http://www.assembla.com/space/nhibernate-mapping

I wrote all of this code test-first, and it allowed me to tackle the interface and flow the way I thought might be useful.  I ended up with something that was mildly usable like this:

IMapping mapping = Mapping.For<Product>()
.Identity("Id")
.Property("Name")
.Property("Price")
.Map();

So this allows me to quickly accept the defaults of the mappings, so NHibernate will assume that I have ...
  • the column names are the same as the property names
  • the type of the column matches the type of the property and it can be picked up via reflection
  • the identity generator of the primary key is Identity
  • the identity/properties have setters
  • the "Name" and "Price" columns are nullable
This isn't always true of course, so we need to be able to specify where we deviate from the defaults.  So how can we accomplish this using a fluent interface?  We could resort to adding more overloads to the Identity() method, so you might have....

IMapping mapping = Mapping.For<Product>()
.Identity("Id", "product_id", Access.NoSetterCamelcaseUnderscore, Generator.Native)
.Property("Name", "product_name", false)
.Property("Price", false)
.Map();
But we don't know how many settings the user might want to specify.  If we have 4 simple, independent settings, then we'd have to support 4! method overload options!  Yuck!

public IPropertySpecificationPredicate Property(string name);
public IPropertySpecificationPredicate Property(string name, string columnName);
public IPropertySpecificationPredicate Property(string name, string columnName, DbType type);
public IPropertySpecificationPredicate Property(string name, string columnName, DbType type, int length);
public IPropertySpecificationPredicate Property(string name, string columnName, bool nullable);
...
This is just the beginning.  What if you wanted to only specify the property name and the nullability?  We quickly end up in an anti-pattern I like to call overload explosion

We can do a bit better, right?  I started to gather my thoughts and came up with this syntax:

IMapping mapping = Mapping.For<Product>()
.Identity("Id")
.Column("product_id")
.Generator(Generator.Native)
.Map();
So now the Identity() method takes a single parameter, the name of the property.  Anything else is optional.  The return type is now something like an IIdentityBuilder interface, which accepts methods on altering the identity object that its building.  Here you can see that we only specified the settings that we wanted, nothing else.  We still had to have a way to "pop" the current object (and thus the entire mapping) so that we can indicate to the builder that we are done building the property and you can return the IMapping object next.  This feels awkward for now, but for now it's ok.

Let's extend this pattern.  Once I'm working with the IMappingBuilder interface, I can now see methods called Generator(), Access(), Column(), etc.  There's nothing there to prevent me from calling .Column("...").Column("...").Column("...").Column("...") which I guess isn't such a big deal.  All it's doing is setting the column property of this object we're building.

Now I'm noticing that there has to be a spot where the user gets finished with the mapping identity and now has some choices.  The obvious next operation would be to create a property, but how do I pop the current context and start working on a new one?

Maybe something like this?

IMapping mapping = Mapping.For<Product>()
      .Identity("Id")
      .Column("product_id")
      .Generator(Generator.Native)
      .AndProperty("Name")
      .Nullable(false)
      .Map();

I'm already started to notice that my identity and property elements are getting lost in the noise.  If I keep up this pattern not only do I have TONS of ISomethingPredicateBuilder objects, I also remember that it's not only properties that I can add at any time.  I could add a Bag, a Set, a List, or any number of other mapping elements.

Another route I might take is using anonymous to provide me with the flexibility of code within the interface.  Take a look:

IMapping mapping = Mapping.For<Product>()
      .Identity("Id", delegate(Identity i) {
                         i.column = "product_id";
                         i.generator = Generator.Native;
                      })      
      .AndProperty("Name", delegate(Property p) {
                         p.column = "product_name";
                         p.nullable = false;
                      })
      .Map();
Here I have a lot more flexibility over the different ways that I define various mapping elements.  The only part of this that is really cumbersome is the delegate syntax itself.

This is probably where Boo or Ruby would come in and save the day because of it's super-dynamicness-flexibility-extraordinaire, but I'd like to see how far I can push C# for now.  At least until C# 3.0 comes out, where I'll get object initializers, lamba expressions, and a few other neat tricks that really make this stuff more fun to sculpt.

What about you?  What types of syntax do you find most readable, usable?
Friday, October 05, 2007

SubSonic Gives Us Migrations

SubSonic, a dead-simple code-generator / ActiveRecord ORM tool, is about to release a kick-ass new feature.  Migrations are an awesome tool that exists in Rails, but we haven't had a solid .NET equivalent yet.  I hope that SubSonic Migrations will live up to the hype.

I've blogged about the need for this before.  I've been wanting to use VSTS DB Pro in this way, but the tool just isn't meant to provide evolutionary db support.

My current project relies on SubSonic for the code-generation, but our database development is done through DB Pro.  I think this is a great tool, but I fear that it's really missing something.  I'm sure the next version will be much better, as is generally true with Microsoft products.  1st versions often take some time to meld, get some good feedback from the general public, and get the usage stories streamlined.

I may be able to take advantage of Migrations, however the DB Project needs to contain all scripts (and they have to be named according to the client's standards).  I wonder if I could create the migrations, execute them, then use sonic.exe to generate the scripts that represent the changes.  I could dump this script in the database project (or import it).

Right now it seems like a Rube-Goldbergian mess.  Any thoughts, ideas, suggestions?

Thursday, October 04, 2007

See you at ALT.NET

Get ready folks.  History is in the making.  The Earth will shatter.  People will be enlightened.  The sky will rain candy...

Ok, I'll stop now.

As you can see I'm really excited about the ALT.NET Conference going on this weekend.  I'm especially looking forward to (finally) meeting:
Sadly, I won't be able to meet Ayende Rahien as he won't be able to make it.  I'm really bummed about that.  Also, there are a ton of folks I've met before that I'm eager to catch up with.  And, of course, I'm really interested in meeting NEW people!  It's amazing the amount of excitement and vigor around this community.

I'll be driving in tomorrow night and should arrive around 8pm, so if you want to meet up for dinner/drinks (or if there is something official going on at that time) then drop me a line at ben {at} scheirman {dot} com.

I'm bringing my wife, however she's not so interested in the ALT.NET stuff.  She's more interested in hanging out, having fun, and (probably) shopping.  Maybe I can get her to attend 1 session, who knows.  Maybe we can get her to stop teaching Spanish and start programming.

See you in Austin!

Wednesday, September 12, 2007

GridView Cell.Text Versus Cell.Controls.Add

I'm sure I've come across this before, but I'm writing this down so that I don't forget it later.

I'm working with a pretty hefty custom GridView and it's really trying my patience for this control.  Yeah yeah, it's all great if you want to bind a list of data coming from a SQL Query written in your aspx in plain-text.  The minute you start to customize it all that goodness turns into a mess of weird templating and strange quirks about ASP.NET, but I digress.

Anyway, this post relates to the fact that the TableCell class has a Text property and a controls collection.

If you are creating custom rows of data, you have to choose between doing
cell.Text = "content";
or
cell.Controls.Add( new LiteralControl("content") );
The difference is that the two are mutually exclusive.  If you have controls inside the table cell, then the Text property will be empty.  If you have the Text property set, then there can't be any controls.

So in my case I was setting the Text property, then trying to insert a LinkButton control right before the text.  So I diligently put
row.Cells[index].Controls.AddAt(0, theLinkButton);
Which happily wipes everything that was previously in the Text property.  Ugh.
Sunday, August 26, 2007

HoustonTechFest 2007 was a Hit

Houston Tech Fest 2007 was yesterday and it was an amazing success.  Over 600 people were present and I was able to see a lot of old friends and meet some new & interesting people.

I got to chill out with Brad Abrams and a few other folks from Microsoft, and it was great to meet Scott Bateman (fellow Houston blogger and advocate of Continuous Integration).  His talk was most excellent, he was very informative and it showed that he not only understood the concepts, but he was able to explain it all in a way that (I thought) was easily grasped by the audience.

Some of the other speakers included Mike Azocar, John Cook, Tim Rayburn (sorry I missed your talk again Tim!), and David Walker.

Funny thing about Tim’s talk.  I was in the room next door listening to David Walker talk about SOA and WCF, and we could hear Tim through the wall partition.  At one point I heard Tim say, “If you can’t hear me in the back, please shout out and let me know.”  I felt like shouting from our room .

I had two sessions, Advanced CSS & Javascript and ORM with NHibernate.  In the first session, I had a full room (over 100 people!) and the audience was very engaging.  It’s great to have an audience that has so many questions and comments on what you are saying.  It becomes more of a dialog, which I think makes the content so much more valuable for everyone. 

Sometime in the midway point of the talk the projector just turned off.  It’s hard to give a talk on CSS without some visuals, so I continued typing and said “Imagine if you wil…” to a room full of laughter.  About that time the projector turned on again.  I didn’t find out until later, but my friend Wes had sat on the cord and unplugged it, then silently plugged it back in.  Funny how a room full of geeks and nobody thought to check the plug when it turned off.  Ah well.

At the end of the talk I had a couple people come up to shake my hand and a little 4–year old girl came up, touched my arm, then ran away giggling.  (Don’t ask me…).  I really enjoy giving this talk and I would like to branch outside of Houston and start giving it elsewhere around Texas (and the U.S.).

My second session was on NHibernate and it was more cozy, with only 15 people or so.  I think NHibernate is a lot harder to make interesting for an intro class because it is a radically different way of developing applications that most people are exposed to.  There is so much material to cover and only a short amount of time, so I tried to focus on the code and keep the examples short and simple.  I think it was effective, though I’d like to branch off this talk and start giving more advanced lectures on NHibernate.

Thanks to all who came to the event (especially my sessions!).  I hope you all had as much fun as I did.

The files from my presentations can be downloaded here:

File Attachment: AdvancedCSSAndJavascript.zip (1161 KB)

File Attachment: nhibernate.zip (4001 KB)

Also, a lot of people were interested in the tools I was using during my demos.  My favorite text editor is E, which you can get at http://www.e-texteditor.com.  My zooming tool that I use is called Zoomit.  My launching utility is called Launchy and it saves me so much time everyday.  I use ReSharper for Visual Studio nirvana (seriously, get this tool).

Some links I mentioned at the talks:

http://www.csszengarden.com

http://www.exploding-boy.com

http://www.mochikit.com

http://www.prototypejs.org

And finally, my favorite CSS book that I keep recommending to everyone:  CSS Mastery.

Wednesday, August 15, 2007

dasBlog 2.0 Released!

The team has been working like mad to get this release out the door and now it’s ready!

http://dasblog.info/

This is a full ASP.NET 2.0 release!   Along with the new release comes a new look for the dasBlog website (designed by me).

Check out the release notes to see all of the great new features.

Friday, August 03, 2007

Decorator - The Cool Pattern with the Stupid Name

So I have a logging class that is implementation agnostic.  Under the hood it uses an Adapter for Enterprise Library Logging, however we could easily switch it out for log4net if needed without changing the code.

So you can imagine that I have an interface that looks like this:

public interface ILogger

{

    void Write(string text);

    void Warn(string text);

    void Error(string text, Exception msg);

}

… and there is currently an implementation of this class called EntLibLogger:

public class EntLibLogger : ILogger

{       

    public void Write(string text)

    {

        //ent. lib write log entry

    }

 

    public void Warn(string text)

    {

        //ent. lib warn

    }

 

    public void Error(string text, Exception msg)

    {

        //ent. lib error

    }       

}

The specific logger that is used is abstracted behind a factory of course.  However, some of the applications that use this component will not have the logging configuration.  It is perfectly feasible to ignore logging in this scenario (ie: swallow exceptions) however this is something that any logging component would do.  I don’t want to add it to each and every implementation of ILogger.

So here’s where the decorator comes in.  This pattern could really use a better name, but I can’t think of one, so I’ll leave that up to you.

A Decorator implements the same interface, however it wraps each method with its own behavior before deferring the call to an inner implementation.  Wow, that doesn’t really make much sense, so how about an example…

public class SilentlyFailLoggingDecorator : ILogger

{

    private readonly ILogger _innerLogger;

 

    public SilentlyFailLoggingDecorator(ILogger innerLogger)

    {

        _innerLogger = innerLogger;

    }

 

    public void Write(string text)

    {

        try

        {

            _innerLogger.Write(text);

        }

        catch

        {

            //swallow exception

        }

    }

 

    public void Warn(string text)

    {

        try

        {           

            _innerLogger.Warn(text);               

        }

        catch

        {

            //swallow exception           

        }

    }

 

    public void Error(string text, Exception exc)

    {

        try

        {

            _innerLogger.Error(text, exc);

        }

        catch

        {

            //swallow

        }

    }

 

}

All of the actual implementation comes from whatever ILogger is sent via the constructor.  All this class does is “decorate” the method calls with additional behavior.  (This time, we’re choosing to silently ignore errors rather than throw exceptions that cause the program to stop)

To wire this up, wherever the factory method resides that creates the actual logger, you’d write…

public static ILogger GetLogger()

{

    //via IoC or just hard-coding

    return new SilentlyFailLoggingDecorator(

         new EntLibLogger()

    );

}

So there you have it!  The decorator pattern can do all kinds of Aspect-Oriented things such as Log a message each time a method is called, or possibly massage parameters before sending them to an inner class.

Sunday, July 29, 2007

My Presentation at OKCodeCamp - DDD with NHibernate

I presented a talk on Domain Driven Design with NHibernate at the OKC code camp yesterday.

It started out a bit rough because I had some missing references and some confusing exceptions, however once I got the ball rolling I think it went pretty well.

I ran way short on time, however, and I promised the crowd that I would post the completed files on my blog tonight .

So, here is the powerpoint, demo applications, and all of the referenced dlls from my presentation.  Let me hear your feedback in the comments!

File Attachment: ddd with nhibernate.zip (7694 KB)

(the file is large because I have the complete references to specific versions of NHibernate and NUnit, so you shouldn’t have to worry about references at all.)

To get the sample running, change the app.config to point to an actual database.  The database should be empty.

Monday, June 18, 2007

VSTS Db Pro - Which Database Project?

I installed Visual Studio Team Edition for Database Professionals the other day and I was about to create my first DB Pro project.

Check out the New Project dialog box.  This is with VSTS Developer, and DB Pro installed:

Image001

and…

Image002

Seeing as how I never used the standard database project in Visual Studio before, I couldn’t tell which one I was supposed to choose. 

It turns out that you need to pick the one in the 2nd screenshot, the Microsoft SQL Server project. 

Wasn’t very intuitive which project to choose.

Tags: ,

ASP.NET Essentials - The Label

After talking to developers for a few days about basic HTML and ASP.NET topics, I find that I always focus on the Label control.

More specifically, I’m talking about the <label> tag in HTML.  What does this tag do?  Why should we care, when we can just write the text before an input control on the page?

For starters, the label has semantic meaning.  The <label> tag gives meaning to a textbox or a dropdown.  If you were blind and browsing using a screen reader, you’d appreciate the little semantic tidbits that give you an easier browser experience.

Another benefit is that we can select and style the label easily, making the transition to table-less forms so much easier.

A third and possibly more useful benefit is that the mouse stays as a pointer, and clicking on the text sets the focus to the corresponding control.

The usage in standard HTML is like this:

<label for='user_name'>User Name:</label>
<input type='text' id='user_name' />

This results in the following example:

(notice how the mouse cursor stays as a pointer, instead of the standard text cursor)

If you were a reasonable person, you’d think that the <asp:label> control would render as an HTML <label>, but you’d be wrong.  ASP.NET renders a standard <asp:label> as a <span>.  ASP.NET 2.0 fixed this, however you have to specify the AssociatedControlID property to change the rendering behavior.

This leads me to another point that I’d like to make with the Label control.  Often times we just want a static label, like in the example above.  If we use the <asp:label> then we’ll have a server-side component as well and a viewstate hit.

Label_render

We certainly don’t need viewstate in this scenario,  Often times we just neglect these things until they are a problem. 

I can hear you say it now… “but Ben, you can disable Viewstate by specifying EnableViewState=’false’ “…  I know you can.  But it’s too easy to just leave it as is.  There’s also an easy alternative.

You can accomplish the same rendering without the viewstate issue by just typing this:

<label for='<%= txtUsername.ClientID %>'>User Name:</label>

This will render the same way, but also ensure that we get the generated ID of the control that we are associating with.  This will not have any server-side component or any correlation to ViewState, and it is actually less characters to type.

Hope you find this information useful!

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