About Me

Training

Nothin But .Net Developer Bootcamp

Navigation

Search

Categories

On this page

Calgary Code Camp Material
Calgary Code Camp - Huge Success
Enhancing Images With The Decorator Pattern
Automating Your Builds With NAnt - Part 7
SpeedFiler and Sql Prompt
One Small Request
ReSharper 2.0 Is Officially Here!
Validation In The Domain Layer - Take One
Calgary Code Camp - Topic
Site Issues (Apologies)
Source Code For Build Better Collections With Generics Article
NAnt Starter Series
TDD By Example - Money
Running all of the sql files in a directory
Automating Your Builds With NAnt - Part 6
Dealing with drop down lists with the MVP pattern
Code For Edmonton .Net User Group Meeting (April 27th)

Archive

Blogroll

 Agile Developer Venkat's Blog
 Ayende @ Blog
 B#
 Barry Gervin's Software Architecture Perspectives
 Boy Meets World
 Brad Abrams
 Canadian Developers
 Christopher Steen
 Claritude Software News
 Clemens Vasters: Enterprise Development and Alien Abductions
 Coding Horror
 Coding in an Igloo
 Dare Obasanjo aka Carnage4Life
 Darrell Norton's Blog [MVP]
 David Hayden [MVP C#]
 Don Box's Spoutlet
 Eric Gunnerson's C# Compendium
 EZWeb guy: Jeffrey Palermo [C# MVP]
 Fear and Loathing
 Generalities & Details: Adventures in the High-tech Underbelly
 Greg Young [MVP]
 Greg's Cool [Insert Clever Name] of the Day
 IanG on Tap
 Ingo Rammer's Weblog
 ISerializable - Roy Osherove's Blog
 James Kovacs' Weblog
 Jason Haley
 Jean-Luc David
 Jeremy D. Miller -- The Shade Tree Developer
 JetBrains .NET Tools Blog
 Jimmy Nilsson's weblog
 John Bristowe's Weblog
 John Papa [MVP C#]
 Jon Skeet's Coding Blog
 JonGalloway.ToString()
 Jump the Fence or Walk Around
 Lambda the Ultimate - Programming Languages Weblog
 Larkware News
 Lutz Roeder
 Marquee de Sells: Chris's insight outlet
 Martin Fowler's Bliki
 Mike Nichols - SonOfNun Technology
 MSDN Magazine - .NET Matters
 MSDN Magazine - All Articles
 OdeToCode Blogs
 Onion Blog
 Planet TW
 Raymond Lewallen [MVP]
 Rockford Lhotka
 RodMan's Corner
 Roger Johansson's blog
 Sahil Malik - blah.winsmarts.com
 Sam Gentile's Blog
 Scott Bellware [MVP]
 Scott Hanselman's Computer Zen
 ScottGu's Blog
 secretGeek
 Service Station, by Aaron Skonnard
 Signum sine tinnitu--by Guy Kawasaki
 Stephen Toub
 Steve Eichert's Blog
 Steven Rockarts
 The Blog Ride
 The Coding Hillbilly
 The Daily WTF
 TheServerSide.net: News
 Tim Gifford
 Vance Morrison's Weblog
 you've been HAACKED

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 519
This Year: 28
This Month: 0
This Week: 0
Comments: 1589

 Wednesday, May 31, 2006
Wednesday, May 31, 2006 1:35:18 PM (Mountain Standard Time, UTC-07:00) ( Presentations )

I have uploaded the demo and slide deck for the presentation that I delivered at the Calgary Code Camp this past weekend. The presentation was all about 3 key principles:

  • Test Driven Development
  • Dependency Inversion principle (yes inversion not injection)
  • Dependency Injection

I am going to try to make time to re-record the session on my laptop so that I can put it up for others to view. If you have any questions about the slide deck or the demo, please do not hesitate to contact me.

The zip file is here.

Comments [2] | | # 
Wednesday, May 31, 2006 12:45:53 PM (Mountain Standard Time, UTC-07:00) ( Presentations )
This is a little late (better late than never). This past Saturday marked the hosting of Calgary's first ever .Net Code Camp. The turnout was amazing (especially for a Saturday), and lots of fun was had by all. I delivered a presentation titled : TDD, Dependency Injection and the Data Access Layer. I am going to be posting my code along with a video for all my remote readers who were unable to attend. The next code camp on the horizon is the Edmonton code camp. I have a couple of ideas in my head on presentation material, but it is a long way off so I’ve got lots of time to formulate/receive ideas. Thanks to everyone who provided feedback (positive and negative) on the presentation, it is always appreciated.
Comments [1] | | # 
 Friday, May 26, 2006
Friday, May 26, 2006 2:23:44 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp | Patterns )

I have been thinking for a while about coming up with a series of posts that talk about real world applications of many of the design patterns that get thrown around. I have been meaning to post about the decorator pattern for quite some time. I was trying to come up with an example that would practically demonstrate the Decorator pattern and then it hit me. An image browser. Here is the sample app in action:

MainForm

OpenDialogViewingPlainImage

As you can see, it is pretty standard fare. When the button is clicked, a file dialog browser will pop-up and the user will have the option to choose a file to display. If they pick a file the file will be displayed. If they don’t pick a file nothing will happen. The code-behind for the form is pretty simple:

public partial class ImageBrowser : Form, IImageBrowserView { private OpenFileDialog openFileDialog; private ImageBrowserPresenter presenter; public ImageBrowser() { InitializeComponent(); presenter = new ImageBrowserPresenter(this); openFileDialog = new OpenFileDialog(); HookupEventHandlers(); } private void HookupEventHandlers() { this.retrieveImageButton.Click += delegate { presenter.DisplayImage(); }; } public bool WatermarkRequired { get { return watermarkCheckBox.Checked; } } public string ImagePath { get { openFileDialog.ShowDialog(); return openFileDialog.FileName; } } public void Display(Image image) { this.pictureBox.Image = image; } }

As you can see, I am using the model view presenter, and the presenter has the responsibility of pushing an image to the view that the view will display. This article is not about the MVP so try not to get too hung up on it if you have not seen it before. As you can see from the code, the main work will be performed inside the DisplayImage method of the presenter. The code for the presenter turns out to be very trivial: 

public class ImageBrowserPresenter { private IImageBrowserView view; public ImageBrowserPresenter(IImageBrowserView view) { this.view = view; } public void DisplayImage() { string pathOfImageToDisplay = view.ImagePath; if (IsValid(pathOfImageToDisplay)) { view.Display(Bitmap.FromFile(pathOfImageToDisplay)); } } private bool IsValid(string imagePath) { return !string.IsNullOrEmpty(imagePath); } }

So what is going on here. When the view tells the presenter to “DisplayImage”, the presenter turns back around to the view and asks it for the path of the image that it should display:

string pathOfImageToDisplay = view.ImagePath;
 
 

The view (form) responds to this request by popping up a file open dialog and returning the filename of the dialog to the presenter:

 

public string ImagePath { get { openFileDialog.ShowDialog(); return openFileDialog.FileName; } }

The code in the form is actually feature complete for this example. There will be no changes required to make to the code behind to support new functionality (for this scenario). A scenario that people often run into for commercial web sites it needing to apply a water mark to an image so that people cannot just download their images and use them as their own. This is our first perfect candidate for the decorator pattern. We want to “Decorate” an image with a watermark, that brands it as our own.

What is the Decorator Pattern

Simply (and the decorator is a very simple,elegant pattern) the Decorator pattern allows us to attach additional responsibilities/behaviours to an object without the need for subclassing. The following class diagram shows the structure of a typical decorator implementation:

Decorator(taken from DoFactory.com)

One of the principles of the decorator pattern ensures that to the client, a decorator looks no different that the object it is decorating. In this scenario we want to decorate Images. The base class for Images in the framework (Bitmaps and Metafiles) is the System.Drawing.Image class. Unfortunately I can’t inherit from this as the constructor for an Image is internal. I also can’t inherit from Bitmap as that class is sealed. How can I decorate when I can’t create a Decorator that implements the same interface as the object it is decorating. Adding a small layer of indirection will solve this problem:

 

public interface ICoreImage { Image Picture { get; } }

I now have an interface that can be implemented by a class that really just wraps an image:

 

public class CoreImage : ICoreImage { private Image image; public CoreImage(Image image) { this.image = image; } public Image Picture { get { return image; } } }

As the saying goes "Another layer of indirection will solve any problem!!, now I have an interface that can be readily implemented by any class. Now, I promised that no changes would affect the code-behind of the form in anyway. To make use of this new class, I just need to change the presenter a little:

public void DisplayImage() { string pathOfImageToDisplay = view.ImagePath; if (IsValid(pathOfImageToDisplay)) { view.Display(GetImageFrom(pathOfImageToDisplay).Picture); } } private ICoreImage GetImageFrom(string pathOfImageToDisplay) { return new CoreImage(Bitmap.FromFile(pathOfImageToDisplay)); }

All I have done is introduced a method into the presenter that will retrieve an ICoreImage from a filename. Once the DisplayImage method retrieves the ICoreImage, it invokes the Picture property to return image data to the view. The current model of the application looks as follows:

initialmodel

We now have to deal with a new requirement. When the user has the “Watermark” checkbox checked, the image should display with a watermark rendered on it. To accomplish this new requirement we can come up with a decorator that will add the watermark to the image it is decorating. In this scenario I am only going to utilize a text based watermark. Options for a Watermark are encapsulated in a class called WatermarkOptions:

public class WatermarkOptions { private const int DEFAULT_SIZE = 26; private static readonly Font DEFAULT_FONT = new Font("Consolas", DEFAULT_SIZE, FontStyle.Bold, GraphicsUnit.Point); private Color color; private Font font; private string watermarkText; private Brush brush; private StringFormat format; public WatermarkOptions():this(DEFAULT_FONT,"SAMPLE",new StringFormat(StringFormatFlags.FitBlackBox),new SolidBrush(Color.Red)) { } public WatermarkOptions(Font font, string watermarkText,StringFormat format,Brush brush) { this.font = font; this.watermarkText = watermarkText; this.format = format; this.brush = brush; } public Font Font { get { return font; } } public string WatermarkText { get { return watermarkText; } } public Brush Brush { get { return brush; } } public StringFormat Format { get { return format; } } }

As you can see, all this class contains is different settings for a watermark. Notice the use of the overloaded constructor, which allows people to construct a watermark and settle with defaults. To make use of this class we will create a “WatermarkDecorator”. The decorator (from the clients point of view) has to look the same as the object it is decorating. In our case, the client is the “DisplayImage” method of the presenter. Because we have the ICoreImage interface, I can utilize it to create the WatermarkDecorator:

public class WatermarkDecorator : ICoreImage { private const int BORDER = 4; private ICoreImage coreImageToWatermark; private readonly WatermarkOptions options; public WatermarkDecorator(ICoreImage coreImageToWatermark) : this(coreImageToWatermark, new WatermarkOptions()) { } public WatermarkDecorator(ICoreImage coreImageToWatermark, WatermarkOptions options) { this.coreImageToWatermark = coreImageToWatermark; this.options = options; } public Image Picture { get { return DecorateWithWatermark(coreImageToWatermark.Picture); } } private Image DecorateWithWatermark(Image picture) { using (Graphics graphics = Graphics.FromImage(picture)) { SizeF textSize = graphics.MeasureString(options.WatermarkText, options.Font, picture.Width - BORDER, options.Format); RectangleF textRectangle = new RectangleF(BORDER, BORDER, picture.Width, textSize.Height); graphics.DrawString(options.WatermarkText, options.Font, options.Brush, textRectangle, options.Format); graphics.Flush(); return picture; } } }

Now you can see the Decorator pattern in action. Decorators always need to know about the object they are adding behaviour/functionality to, a great way to accomplish this is through constructor injection. When constructed with only an image, the decorator makes use of the parameterless WatermarkOptions constructor, to create options with default settings. Remember, decorators are adding new functionality to existing objects at runtime, the magic of adding the watermark happens when the Picture property on the decorator gets invoked. Instead of just immediately delegating to the object being decorated, it invokes the “DecorateWithWatermark” method, passing in the image retrieved from the underlying “decorated” ICoreImage. The DecorateWithWatermark method contains the logic to apply a watermark to the image, making use of the WatermarkOptions that got passed in. I am not going to delve into the details of the graphics jargon, for the most part it is pretty simple.

Ok, so I have this decorator, how do I use it? Switching back to the method in the presenter that actually instantiates the CoreImage, I can apply the decorator quickly by performing a quick check as to whether the user wants Watermarks applied:

 

private ICoreImage GetImageFrom(string pathOfImageToDisplay) { ICoreImage image = new CoreImage(Bitmap.FromFile(pathOfImageToDisplay)); return (view.WatermarkRequired ? new WatermarkDecorator(image) : image); }

You will note that the DisplayImage method in the presenter did not need to change at all, why? Because all it cared about was when it called the GetImageFrom method, was that it received an ICoreImage implementation, it doesn't know or care if it is a decorator. If I run the application now any files that are opened while the checkbox is checked will have a watermark drawn over them:

imageshownwithwatermark

Our revised class diagram looks like so:

revisedmodel

To finish off, a decorator also doesn't care what it is decorating either, as long as the object that it is decorating implements the same interface as what it does. So if the customer came to you all of a sudden and said “Regardless of whether the image has a watermark or not, we want a border around all images”, you could satisfy that requirement with another discrete decorator:

 

public class BorderDecorator : ICoreImage { private const int PEN_WIDTH = 10; private ICoreImage imageToDecorate; public BorderDecorator(ICoreImage imageToDecorate) { this.imageToDecorate = imageToDecorate; } public Image Picture { get { return WrapWithBorder(imageToDecorate.Picture); } } private Image WrapWithBorder(Image picture) { using (Graphics graphics = Graphics.FromImage(picture)) { RectangleF border = new RectangleF(0, 0, picture.Size.Width, picture.Size.Height); Pen pen = new Pen(new SolidBrush(Color.Black), PEN_WIDTH); graphics.DrawRectangle(pen,border.X,border.Y,border.Width,border.Height); graphics.Flush(); } return picture; } }

To ensure that all images have borders, I can just apply the new decorator to the existing decorator!!:

 

private ICoreImage GetImageFrom(string pathOfImageToDisplay) { ICoreImage image = new CoreImage(Bitmap.FromFile(pathOfImageToDisplay)); return new BorderDecorator(view.WatermarkRequired ? new WatermarkDecorator(image) : image); }

With that change applied, if I run the application now, all images (watermarked or not) will have a border around them:

plainimagewithborder  watermarkedimagewithborder

Now of course. In this example I had the presenter explicitly wrap the objects with decorators, but think about the flexibility of introducing factories/composite decorators that would allow the code in the presenter to stay static also. But those are patterns for another day!!

If anyone wants the source for this entry, please contact me.

TODO
Comments [5] | | # 
 Thursday, May 25, 2006
Thursday, May 25, 2006 8:14:51 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp | Tools )

It has been quite a bit of time since the last installment of the NAnt Starter Series. We left off being able to successfully compile and test the main libraries of our application, and we progressed to bringing the database into the fold and looked at ways to manage the database in a multiple developer environment. In this installment we are going to talk about compiling and distributing the web portion of the application. Specifically, we are going to write a NAnt target that will build and deploy our entire web application into a directory that can be immediately deployed to a remote server if need be. Take a look at the current solution structure that is set up:

SolutionStructure

As you can see from the diagram, in this example I am going to be using the web-site project model, as opposed to the newly available Web Application Project model. You will quickly see that the only file that exists in this project is the ViewCustomers.aspx file. I am not using any of the new directories like the App_Code, App_Data etc. My web project should be extremely simple, consisting of purely UI elements like:

– Web Pages

– User Controls

– JavaScript Libraries

– Styles and Templates

 

By limiting the amount of code that is placed in this project, I can write unit tests against the real objects that will actually get work done. These objects , of course, live in projects separate from the web application. You might be asking yourself “Where is the web.config file?”. That file is actually a template file that will have pre-processing done on it during the build process. The contents of that file before processing look as follows:

<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">       
 <appSettings>  
  <add key="DatabaseConnection" value="SqlServer"/>
 </appSettings>
 
 <connectionStrings>
  <add name="SqlServer"
   connectionString="@CONFIG_CONNECTION_STRING@" 
   providerName="System.Data.SqlClient"
  />
 </connectionStrings>
 <system.web>
  <compilation debug="true"/>
  <authentication mode="Windows"/>
   <authorization>
       <deny users="?" />
   </authorization>
  <customErrors mode="Off" />
  <sessionState mode="Off" />  
 </system.web> 
</configuration>

If you look at the connectionStrings element, you will notice that the SqlServer connectionString is set up as a replaceable token in the Web.config.template file. Again, this is to ensure that at deploy time, the connectionString will be replaced with the appropriate string based on the environment that is getting deployed to.

Ok, let’s turn our attention to the process of building and deploying the application. Take a look at a new target that will compile our web application from inside of NAnt:

 <target name="asp.compile" description="Compiles the webapp" depends="init, compile">
        <delete dir="build\dist" if="${directory::exists('build\dist')}" />
       
        <loadtasks assembly="tools\nant\NAnt.Contrib.Tasks.dll" />
 
 <delete>
     <fileset basedir="build\aspprecompile">
  <include name="**\*" />
     </fileset>
 </delete>
        <copy todir="build\aspprecompile">
            <fileset basedir="src\app\DotNetRocks.Web.UI">
                <include name="*" />
                <include name="images\**\*.*" />
                <include name="javascript\**\*.js" />
            </fileset>
        </copy>

        <copy todir="build\aspprecompile\bin">
            <fileset basedir="build">
                <include name="*.dll" />
            </fileset>
        </copy>

        <mkiisdir dirpath="build\aspprecompile" vdirname="aspprecompile" />
        <exec program="C:\WINDOWS\Microsoft.NET\Framework\${framework.version}\aspnet_compiler.exe"
  useruntimeengine="true">
            <arg value="-p" />
            <arg value="build\aspprecompile" />
            <arg value="-v" />
            <arg value="aspprecompile" />
            <arg value="build\dist" />
        </exec>
        <deliisdir vdirname="aspprecompile" />       
    </target>

Whoa, there is a lot going on here so let’s break it down piece by piece. We are making use of the “depends” attribute to ensure that the asp.compile target cannot be run until all of the supporting libraries have been compiled:

                         target name="asp.compile" description="Compiles the webapp" depends="init, compile"

Don’t worry about the deletes that are happening at the beginning of the target, they are just ensuring that cleanup happens from a prior build process. The first step to compiling the ASP application is copying all of the files that the ASP.Net precompiler will require for compilation into a transient build directory (I don’t want to affect my main web project directory in any way whatsoever):

<copy todir="build\aspprecompile">
            <fileset basedir="src\app\DotNetRocks.Web.UI">
                <include name="*" />
                <include name="images\**\*.*" />
                <include name="javascript\**\*.js" />
            </fileset>
</copy>

I continue by copying all of the assemblies that the web project uses into an appropriate bin directory under the aspprecompile directory. Again, I am just pulling from the build directory any dll’s that would have been created during the running of the compile target:

 <copy todir="build\aspprecompile\bin">
            <fileset basedir="build">
                <include name="*.dll" />
            </fileset>
 </copy>

If I were to stop the target there my build directory would look as follows:

BuildDirectory

The aspprecompile directory would look like this:

AspprecompileDirectory

And the aspprecompiles bin directory would look like this:

AspPrecompileBinDirectory

You will see that I am copying pretty much all of the files from the DotNetRocks.Web.UI directory into this transient precompile directory. That’s right every file, including code-behind files. Notice how at the beginning of the target I used the loadtasks task :

<loadtasks assembly="tools\nant\NAnt.Contrib.Tasks.dll" />

LoadTasks will load any custom NAnt tasks that are contained in the named assembly and make them available to you for use during the build process. The NAntContrib library, is an open source library that contains a plethora of tasks that you can make use of during your own build processes. The ones that I need specifically are the ones that let me manipulate IIS Virtual Directories. I create a new virtual directory called aspprecompile that will point to the build\aspprecompile directory:

 <mkiisdir dirpath="build\aspprecompile" vdirname="aspprecompile" />

All right the stage is set. The last time we compile a project we used the standard NAnt csc task that would compile a set of C# class files into a library. Even though there are cs files in the aspprecompile directory we cannot use the csc task to compile the web project. I need to take advantage of the ASP .Net precompiler to compile the web application for me. With .Net 2.0, you could actually deploy all of your *.cs files for the project into the web directory and the ASP.Net runtime would compile the cs files dynamically when the pages are requested. I am not a fan of this approach, I would rather just keep my source files out of the web directory completely. To allow you to do this, you have to take advantage of the ASP.Net precompiler. If you are not familiar with the ASP.Net precompiler you can read some more information about it here. I use the NAnt exec task to shell out to the asp.net precompiler to compile my site in place:

<exec program="C:\WINDOWS\Microsoft.NET\Framework\${framework.version}\aspnet_compiler.exe"
  useruntimeengine="true">
            <arg value="-p" />
            <arg value="build\aspprecompile" />
            <arg value="-v" />
            <arg value="aspprecompile" />
            <arg value="build\dist" />
        </exec>

 Notice I am using a modified method to pass parameters to the aspnet_compiler executable. The full commandline would expand to this:

aspnet_compiler.exe -p “build\aspprecompile” -v “aspprecompile” “build\dist”

The meaning of each of the arguments is a follows:

  • -p : Specifies the full network path or local disk path of the root directory that contains the application to be compiled. This option must be combined with the -v option.
  • -v : Specifies the virtual path of the application to be compiled
  • targetdir : This is not a named argument but if provided, specifies the directory to which the asp_compiler will place the final files for deployment

After running the target the build\aspprecompile directory looks no different that the before the compilation happened, but notice that a new directory has been added to the build directory:

DistDirectory

     The following screenshots show the contents of this directory:

    DistDirectoryContents   DistBinDirectoryContents

    Take a look at the interesting names that the aspnet_compiler generates for us!! Notice also, that although the aspprecompile directory contained a .cs file the the ViewCustomers.aspx page, the dist folder has no source files whatsoever!! The dist folder now contains everything that we would need to deploy to a production server. With the compilation safely taken care of I can go ahead and remove the temporary virtual directory I created for asp precompile purposes:

     <deliisdir vdirname="aspprecompile" />

    Again, the deliisdir task lives is a task that is defined in the NAntContrib library.

    To wrap it up, I can quickly add a target that will deploy the application to a local directory on my machine :

     

    <target name="deploy" depends="asp.compile">
            <deliisdir vdirname="DotNetRocks" failonerror="false" />
            <delete>
                <fileset basedir="deploy">
                    <include name="**/*" />               
                </fileset>
            </delete>
            <mkdir dir="deploy" />
            <copy todir="deploy">
                <fileset basedir="build\dist">
                    <include name="**\*" />               
                </fileset>
            </copy>
            <copy file="config\Web.Config" tofile="deploy\Web.config" /> 
            <mkiisdir dirpath="deploy" vdirname="DotNetRocks" authntlm="true" defaultdoc="Default.aspx" />
        </target> 

     

    I am not going to break this target down, as you have already seen all of the tasks that I am using. At the end of this target running I will be able to navigate to the ViewCustomers.aspx page by opening up my browser and typing in : http://localhost/DotNetRocks/ViewCustomers.aspx which brings me to:

    ViewCustomers

     

    TODO
    Comments [9] | | # 
    Wednesday, May 24, 2006 11:00:16 PM (Mountain Standard Time, UTC-07:00) ( Tools )

    I have been using SpeedFiler for the last couple of weeks and love the productivity it has provided with regards to managing my email. After reading the Igloo Coder mentioning SQL Prompt, I thought I would download it and give it a whirl. I won’t say no to intellisense for SQL!! It was shortly after this that I started noticing issues with SpeedFiler. I would go to file an item using the CTRL-SHIFT-V shortcut and the standard outlook Move-To dialog would pop up. The same applied for SpeedFilers “Go To Folder” command. I could however, successfully invoke these commands if I explicitly used the SpeedFiler menu items that activated the custom dialogs. I was emailing back and forth with the founder of SpeedFiler (that’s right, he truly stands behind his product) for a little while and he was offering lots of good tips to ensure that I was not messing anything up. It never even dawned on me that SQL Prompt could be the problem. Until, 20 minutes ago I realized that the only thing that differed between my machine configuration of today to yesterday was the installation of SQL Prompt. I fired up the options dialog of SQL Prompt :

    SqlPromptOptionsWindow

    By default, SQL Prompt runs “Enabled” in the tray. When I changed the status to “Off”, bang, speedfiler worked again like a charm. I mailed Itzy and let him know that this may be an issue to look into. But for now, I’ll know to turn SQL Prompt off, when I’m not doing any DB work.

    Comments [0] | | # 
     Wednesday, May 24, 2006
    Wednesday, May 24, 2006 10:34:31 AM (Mountain Standard Time, UTC-07:00) ( )

    To all the awesome readers of this blog, I am requesting your help with promoting some of these entries on DotNetKicks.com. All of my new posts (I am trying to revisit the old ones) will have a link to kick the story to dotnetkicks. If you are a member, please kick these stories so that a wider audience can view them. I have already kicked up each of the posts in the entire NAnt Starter Series, so please feel free to add your own kicks to these items, as well as the main starter series link also!!

    Thanks so much. And the front to back sampler, starts later on today!!

    Comments [1] | | # 
     Tuesday, May 23, 2006
    Tuesday, May 23, 2006 9:06:59 PM (Mountain Standard Time, UTC-07:00) ( Tools )

    Rs2banner

    Well, it is finally official (I am late with this post, as my blog has been having issues). ReSharper 2.0 is now unleashed for public “stable” consumption. What is ReSharper? In my opinion, one of the most kick-butt tools for code-centric .Net 2.0 developers. The list of features of this product is fantastic, for me the top of the list are :

    • Refactorings (too many to name)
    • Move type to new namespace
    • Code Generation features inline with TDD developers
    • Find Usages - Rocks
    • Go To Type – CTRL -N (start typing and list will filter to match types with name)
    • Go To File – CTRL – SHIFT – N (start typing and list will filter)
    • Integrated unit test runner
    • Live Templates (extremely easy template syntax for creating your own Live templates)
    • File Templates
    • NAnt and MSBuild intellisense

    I could go on and on, but the list of features that I use on a given day are too many to mention here. Download the trial and give it a whirl!!

    Comments [0] | | # 
     Friday, May 19, 2006
    Friday, May 19, 2006 1:45:19 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp )

    I have been receiving a lot of email's centered around the topic of validation in the domain layer. If you are a developer who is trying to utilize a rich domain layer in your applications, then you might have struggled with the whole issue of validation. Conceptually, most of us know how to perform validation using some predefined set of business rules. Unfortunately, the way the validation is implemented often leaves us with a solution where validation is scattered haphazardly throughout multiple layers in the application. Worse yet, is the case where validation is duplicated in multiple layers in the application, and changing a rule entails changing the code in multiple places. To demonstrate one solution to this issue I am going to focus on building a simple voting application. Some of the business rules are as follows:

    • Must be between the age of 18 – 75 to vote (yes there is an upper limit!!)
    • Must live in the country the candidate is running for

    Ok, so my rules about the voting process are a little weird to say the least, but hey, it’s just an example. As well as the rules for voting, upon submitting a vote the person voting has to supply all of the required voter information:

    • FirstName
    • LastName
    • Age
    • Address
    • Gender
    • CountryOfResidence

    Take a look at the class diagram for the initial domain model:

    InitialClassDiagram

    As you can see. This is a pretty simple domain. Let’s switch back to validating the simple properties for now. Let’s start with the strings (firstname,lastname,address). Remember, I am going to be performing all of my validation in the domain layer, so the buck stops here. I am not trusting anything that may have come from the UI. I am going to write a test to capture the validation I want to perform against the first name of a person:

     

    [Test]
    public void ShouldValidateUsingRule()
    {
    IBusinessRule
    <Person> firstNameRule = new BusinessRule<Person>(delegate(Person person)
    {
    return string.IsNullOrEmpty(person.FirstName);
    });

    Person personWithInvalidFirstName
    = new Person("", "", "", 0, null, null);
    Person personWithValidFirstName
    = new Person("JP", "", "", 0, null, null);

    Assert.IsTrue(firstNameRule.IsBrokenBy(personWithInvalidFirstName));
    Assert.IsFalse(firstNameRule.IsBrokenBy(personWithValidFirstName));


    }

    As you can see from this test. I am trying to encapsulate the simple business rule “A person must have a non-null firstname” into a full fledged BusinessRule object instance. You will notice the use of the Predicate delegate that I plan on passing into the constructor of the BusinessRule class. This is the method that will perform the validation against the person. The implementation of this class should prove to be fairly simplistic:

     

    public class BusinessRule<T> : IBusinessRule<T> { Predicate<T> brokenPredicate;

    public BusinessRule(Predicate<T> brokenPredicate)
    {
    this.brokenPredicate = brokenPredicate;
    }

    public bool IsBrokenBy(T item)
    {
    return brokenPredicate(item);
    }
    }

    Notice how I am making use of generics so that I can use the BusinessRule to work with any type. When I instantiate the BusinessRule for a certain type it will also constrain the type for the Predicate. If you take a look at the IBusinessRule<T> interface. You will notice that there is not much to it:

     

    public interface IBusinessRule<T> { bool IsBrokenBy(T item);
    }
     
     
     

    I now want a way to encapsulate a set of rules that need to be checked against an entity. Let’s take a look at another test:

     

    [Test]
    public void ShouldRetrieveAllRulesBrokenByItem()
    {
    IBusinessRule
    <Person> mockRule1 = mockery.CreateMock<IBusinessRule<Person>>();
    IBusinessRule
    <Person> mockRule2 = mockery.CreateMock<IBusinessRule<Person>>();
    IBusinessRule
    <Person> mockRule3 = mockery.CreateMock<IBusinessRule<Person>>();

    Person person
    = new Person("", "", "", 0, null, null);
    Expect.Call(mockRule1.IsBrokenBy(person)).Return(
    true);
    Expect.Call(mockRule2.IsBrokenBy(person)).Return(
    true);
    Expect.Call(mockRule3.IsBrokenBy(person)).Return(
    false);


    mockery.ReplayAll();

    IBusinessRuleSet
    <Person> ruleSet = new BusinessRuleSet<Person>(mockRule1, mockRule2, mockRule3);
    IBusinessRuleSet
    <Person> brokenRules = ruleSet.BrokenBy(person);
    Assert.AreEqual(
    2,brokenRules.Count);
    }

     

    Once again, I am making use of RhinoMocks to mock out the business rules. As you can see, you can ask a BusinessRuleSet for all of the rules that are broken by an item. With the test in place, the implementation becomes a breeze:

     

    public class BusinessRuleSet<T> : IBusinessRuleSet<T> { private IList<IBusinessRule<T>> rules;

    public BusinessRuleSet(params IBusinessRule<T>[] rules) : this(new List<IBusinessRule<T>>(rules))
    {
    }

    public BusinessRuleSet(IList<IBusinessRule<T>> rules)
    {
    this.rules = rules;
    }

    public IBusinessRuleSet<T> BrokenBy(T item)
    {
    IList
    <IBusinessRule<T>> brokenRules = new List<IBusinessRule<T>>();

    foreach (IBusinessRule<T> rule in rules)
    {
    if (rule.IsBrokenBy(item))
    {
    brokenRules.Add(rule);
    }
    }
    return new BusinessRuleSet<T>(brokenRules);
    }

    public int Count
    {
    get { return rules.Count; }
    }
    }

    With the business rule set in place let’s turn our attention to how we could go about asking domain objects to validate themselves:

     

     

    [Test]
    public void ShouldValidateUsingBusinessRuleSet()
    {
    IBusinessRuleSet
    <Person> mockRuleSet = mockery.CreateMock<IBusinessRuleSet<Person>>();
    IBusinessRuleSet
    <Person> mockBrokenRules = mockery.CreateMock<IBusinessRuleSet<Person>>();

    Person person
    = new Person("", "", "", 0, null, null,mockRuleSet);

    Expect.Call(mockRuleSet.BrokenBy(person)).Return(mockBrokenRules);
    mockery.ReplayAll();

    IBusinessRuleSet
    <Person> brokenRules = person.Validate();
    Assert.AreEqual(mockBrokenRules,brokenRules);
    }

     

    Being a big fan of dependency injection, I am making the decision that domain objects will be constructed with the rules they can use to validate themselves. This is especially handy in situations where the validation is context sensitive ie. In migration you often relax validation rules. I have decided that I will be able to ask a domain object to validate itself, and the result of this call will be a IBusinessRuleSet<T> containing all of the broken rules. With what we already have in place this should be fairly trivial:

     

    public Person(string firstName, string lastName, string address, int age, Country countryOfResidence, Gender gender, IBusinessRuleSet<Person> ruleSet)
    {
    this.firstName = firstName;
    this.lastName = lastName;
    this.address = address;
    this.age = age;
    this.countryOfResidence = countryOfResidence;
    this.gender = gender;
    this.ruleSet = ruleSet;
    }

    public IBusinessRuleSet<Person> Validate()
    {
    return ruleSet.BrokenBy(this);
    }

     

    That’s it. In the constructor for the Person class I pass in the rule set that it can use for validation, and the Validate method becomes a simple one line delegation. The solution I have used to encapsulate the business rules can easily allow me to utilize the flyweight pattern to share RuleSet’s between multiple instances of the same type. More on that later. Let’s look at the completed code required to validate a person class:

     

    public class Person
    {
    private string firstName;
    private string lastName;
    private string address;
    private int age;
    private Country countryOfResidence;
    private Gender gender;
    private readonly IBusinessRuleSet<Person> ruleSet;

    public Person(string firstName, string lastName, string address, int age, Country countryOfResidence, Gender gender):this(firstName,lastName,address,age,countryOfResidence,gender,Rules.Default)
    {

    }

    public Person(string firstName, string lastName, string address, int age, Country countryOfResidence, Gender gender, IBusinessRuleSet<Person> ruleSet)
    {
    this.firstName = firstName;
    this.lastName = lastName;
    this.address = address;
    this.age = age;
    this.countryOfResidence = countryOfResidence;
    this.gender = gender;
    this.ruleSet = ruleSet;
    }

    public IBusinessRuleSet<Person> Validate()
    {
    return ruleSet.BrokenBy(this);
    }


    public string FirstName
    {
    get { return firstName; }
    }

    public string LastName
    {
    get { return lastName; }
    }

    public string Address
    {
    get { return address; }
    }

    public int Age
    {
    get { return age; }
    }

    public Country CountryOfResidence
    {
    get { return countryOfResidence; }
    }

    public Gender Gender
    {
    get { return gender; }
    }

    public sealed class Rules
    {
    private Rules()
    {

    }

    public static IBusinessRule<Person> FirstName
    {
    get { return new BusinessRule<Person>(delegate(Person person)
    {
    return ! string.IsNullOrEmpty(person.FirstName);
    });
    }
    }

    public static IBusinessRule<Person> LastName
    {
    get { return new BusinessRule<Person>(delegate(Person person)
    {
    return ! string.IsNullOrEmpty(person.LastName);
    });
    }
    }

    public static IBusinessRule<Person> Address
    {
    get { return new BusinessRule<Person>(delegate(Person person)
    {
    return ! string.IsNullOrEmpty(person.Address);
    });
    }
    }

    public static IBusinessRule<Person> Age
    {
    get { return new BusinessRule<Person>(delegate(Person person)
    {
    return person.Age > 0;
    });
    }
    }

    public static IBusinessRule<Person> Country
    {
    get { return new BusinessRule<Person>(delegate(Person person)
    {
    return person.CountryOfResidence != null;
    });
    }
    }


    public static IBusinessRule<Person> Gender
    {
    get { return new BusinessRule<Person>(delegate(Person person)
    {
    return person.Gender != null;
    });
    }
    }


    public static IBusinessRuleSet<Person> Default
    {
    get { return new BusinessRuleSet<Person>(FirstName, LastName, Age, Address, Country, Gender);
    }
    }
    }
    }
     
     

    Notice how I am making use of the nested rules class inside of Person to place all of the distinct business rules for a person inside of the Person class itself. This is for demonstration, and to not go to the full blown effort of creating a RuleRegistry or the like. Notice how the constructor for the Person class that does not take a rule set, calls into the greedy constructor passing in the Default rule set, which is composed of each of the individual business rules. Let’s write some quick tests to verify that the default validation actually works:

     

    [Test]
    public void ShouldValidateFirstNameUsingDefaultRules()
    {
    Person person
    = new Person("", "JP", "Address", 1, Country.CANADA, Gender.MALE);
    IBusinessRuleSet
    <Person> broken = person.Validate();
    Assert.AreEqual(
    1,broken.Count);
    Assert.IsTrue(broken.Contains(Person.Rules.FirstName));
    }

    Currently the test will not compile because the IBusinessRuleSet interface does not provide the contains method. I need to implement the method (which I won’t bother showing) and then I can run the test. Once I have added the necessary code I will still get a failure because the object references for the 2 rules are not the same, even though in reality the rules are identical. To circumvent this issue we can add a custom equals implementation for the BusinessRule class. To make it simpler, I am going to add a new field to the business rule class to store the name of the business rule:

     

     

    [Test]
    public void BusinessRulesForATypeWithTheSameNameShouldBeEqual()
    {
    IBusinessRule
    <Person> firstNameRule = new BusinessRule<Person>("FirstName",delegate(Person person)
    {
    return false;
    });

    IBusinessRule
    <Person> firstNameRule2 = new BusinessRule<Person>("FirstName",delegate(Person person)
    {
    return false;
    });

    Assert.IsTrue(firstNameRule.Equals(firstNameRule2));
    }

    Initially this test will fail, this is because I need to add a custom equals implementation for the BusinessRule class:

     

    public override bool Equals(object obj)
    {
    IBusinessRule
    <T> other = obj as IBusinessRule<T>;
    return (other == null ? true : this.Name.Equals(other.Name));
    }

    public override int GetHashCode()
    {
    return brokenPredicate.GetHashCode() + 29*name.GetHashCode();
    }

    With this code in place the equals method will now work. Of course, with this refactoring I need to go back to the Rules class inside of person, and change all of the rules so a name is passed in also. An example of one such rule change is as follows:

     

    public static IBusinessRule<Person> Country
    {
    get { return new BusinessRule<Person>(MethodInfo.GetCurrentMethod().Name,delegate(Person person)
    {
    return person.CountryOfResidence != null;
    });
    }
    }

    Notice, in this initial incarnation I am using the Name of the property itself to determine the rule name!! Ok, this post is quickly turning into an essay, so I am going to cover one more point and then carry on another day. Take a look at the following rules in the Person class:

     

     

                public static IBusinessRule FirstName
    {
    get
    {
    return new BusinessRule(MethodInfo.GetCurrentMethod().Name,delegate(Person person)
    {
    return ! string.IsNullOrEmpty(person.FirstName);
    });
    }
    }

    public static IBusinessRule LastName
    {
    get
    {
    return new BusinessRule(MethodInfo.GetCurrentMethod().Name,delegate(Person person)
    {
    return ! string.IsNullOrEmpty(person.LastName);
    });
    }
    }

    public static IBusinessRule Address
    {
    get
    {
    return new BusinessRule(MethodInfo.GetCurrentMethod().Name,delegate(Person person)
    {
    return ! string.IsNullOrEmpty(person.Address);
    });
    }
    }

    You will notice that I am making use of the same method call in each argument string.IsNullOrEmpty. Unfortunately, what happens for any one of those checks when the string for any one of them is " ". The IsNullOrEmpty method will not catch this scenario. I need to fix the string checks so that they all behave the same. So now I have three pieces of code to change. Let me show you a way to encapsulate the checks:

    public interface ISpecification<T>
    {
    bool IsSatisfiedBy(T item);
    }

    public class NonEmptyStringSpecification : ISpecification<string> { public bool IsSatisfiedBy(string item)
    {
    return (! string.IsNullOrEmpty(item)) && item.Trim().Length > 0;
    }
    }

    I am making use of a toned down Specification pattern. If you are not familiar with that pattern, go ahead and pick up a copy of Eric Evans Domain Driven Design book. I promise I will devote a separate post to the Specification pattern (if people remind me!!). With the NonEmptyStringSpecificaton in place I can change the code in the Person rules class to the following:

     

    public static IBusinessRule<Person> FirstName
    {
    get { return new BusinessRule<Person>(MethodInfo.GetCurrentMethod().Name,delegate(Person person)
    {
    return new NonEmptyStringSpecification().IsSatisfiedBy(person.FirstName);
    });
    }
    }

    public static IBusinessRule<Person> LastName
    {
    get { return new BusinessRule<Person>(MethodInfo.GetCurrentMethod().Name,delegate(Person person)
    {
    return new NonEmptyStringSpecification().IsSatisfiedBy(person.LastName);
    });
    }
    }

    Notice that because the check for a Non-Empty string is now encapsulated in “another object”, if the rules for a non empty string change, I now only need to change one place!! I could carry on and add a NonNullObject specification that would encapsulate the null checks, this would be added solely for consistency and readability.

    Ok, so we now have a faily flexible validation engine in place, we have one problem. I can perform validation, but how am I going to get validation errors back to the client? Let’s write a quick test to prove out how I can go about this. In my head I think that it is going to take another change to the business rule class as well as the rule set:

     

     

    [Test]
    public void ShouldRetrieveMessagesForAllRules()
    {
    IBusinessRule
    <Person> mockRule1 = mockery.CreateMock<IBusinessRule<Person>>();
    IBusinessRule
    <Person> mockRule2 = mockery.CreateMock<IBusinessRule<Person>>();

    Expect.Call(mockRule1.Description).Return(FIRST_NAME_MESSAGE);
    Expect.Call(mockRule2.Description).Return(LAST_NAME_MESSAGE);

    mockery.ReplayAll();

    IBusinessRuleSet
    <Person> rules = new BusinessRuleSet<Person>(mockRule1, mockRule2);
    IList
    <string> ruleMessages = rules.Messages;

    Assert.AreEqual(
    2,rules.Count);
    Assert.Contains(FIRST_NAME_MESSAGE,(IList)ruleMessages);
    Assert.Contains(LAST_NAME_MESSAGE,(IList)ruleMessages);
    }

    The addition of a description for the rule requires me to add a new field and constructor to the BusinessRule class (the Description property gets added to the IBusinessRule interface):

     

     

    public class BusinessRule<T> : IBusinessRule<T> { Predicate<T> brokenPredicate;
    private string name;
    private string description;

    public BusinessRule(string name,string description,Predicate<T> brokenPredicate)
    {
    this.name = name;
    this.description = description;
    this.brokenPredicate = brokenPredicate;
    }

    public bool IsSatisfiedBy(T item)
    {
    return brokenPredicate(item);
    }

    public string Name
    {
    get { return name; }
    }

    public string Description
    {
    get { return description; }
    }

    public override bool Equals(object obj)
    {
    IBusinessRule
    <T> other = obj as IBusinessRule<T>;
    return (other == null ? true : this.Name.Equals(other.Name));
    }

    public override int GetHashCode()
    {
    return brokenPredicate.GetHashCode() + 29*name.GetHashCode();
    }


    }
     

    With that change in place. I need to update the rules that I create in the person class to add a description (you can check that out in the actual code). The code needed to implement the Messages property on the BusinessRuleSet class becomes a snap (with the aid of another anonymous delegate):

     

    public IList<string> Messages
    {
    get
    {
    return new List<IBusinessRule<T>>(rules).ConvertAll<string>(delegate(IBusinessRule<T> rule)
    {
    return rule.Description;
    });
    }
    }

    I make use of the ConvertAll method on the List class, to convert each of the rules into a plain old string, by passing in a delegate that just retrieves the Description from the rule!! Great. Everything is in place, let’s put all of this stuff through its paces. Take a look at the following WinForm:

     

    PersonWinForm

    This form will allow the user to enter in all of the basic information (minus Country and Gender). An accompanying presenter that can be consumed from this view is as follows:

     

     

    public class PersonPresenter
    {
    private IPersonView view;

    private IBusinessRuleSet<Person> rulesInContext = new BusinessRuleSet<Person>(Person.Rules.FirstName, Person.Rules.LastName, Person.Rules.Address, Person.Rules.Age);

    public PersonPresenter(IPersonView view)
    {
    this.view = view;
    }

    public void Submit()
    {
    IBusinessRuleSet
    <Person> broken = CreateFromView().Validate();
    if (broken.Count > 0)
    {
    view.DisplayErrors(broken.Messages);
    }
    else { view.DisplaySuccess(); } } private Person CreateFromView()
    {
    int age = 0;
    int.TryParse(view.Age, out age);

    return new Person(view.FirstName, view.LastName, view.Address, age, Country.CANADA, Gender.MALE);
    }
    }

    With that code in place (plus an accompanying view interface), if you run the app you will notice that the rules (for the context of the presenter) are being utilized to perform validation. I think I have probably given you a bit to think about. And keep in mind, this is one of several ways that validation in the domain layer can be performed. There are more refactorings that can be performed, and I still have not even looked at how we are going to perform the validation for the real voting scenario. I'll leave that for another day, unless one of my readers feels like submitting an extension to this piece to support the extended scenario.

    Please take the time to provide feedback if you have any. One of the main reasons that I try to post quality content is knowing that people out there are getting something from it. For the many who take the time to respond, it is greatly appreciated. I had to re- enable the captcha image, as I got spammed hard the other day. If you cannot place comments on the blog feel free to email me at bitwisejp@gmail.com

    The complete code (so far) for this entry is here.

    TODO
    Comments [8] | | # 
     Thursday, May 18, 2006
    Thursday, May 18, 2006 9:44:52 AM (Mountain Standard Time, UTC-07:00) ( Presentations )

    I finally submitted my presentation topic for the Calgary Code Camp . The session is titled TDD, Dependency Injection and the Data Access Layer: 

    • In this session attendees will learn how to utilise the concepts of TDD and Dependency Injection to build up a data access layer piece by piece. During the course of the session attendees will learn the value of coding to interfaces as well as how applying the technique of dependency injection can help you build objects that are more loosely coupled to one another.

    I look forward to speaking with any reader of this blog who attends the code camp.

    Comments [4] | | # 
     Tuesday, May 16, 2006
    Tuesday, May 16, 2006 10:01:35 AM (Mountain Standard Time, UTC-07:00) ( )

    Hey Everyone. I have to apologize for the recent downtime that the site has experienced. The service provider contacted me a few minutes ago and let me know that they had resolved the issue. I am out of town for the next 2 days and when I get back I plan to get started building out a comparative solution to the application that I build on DNRTv. Stay tuned.

    Thanks for your patience.

    Comments [4] | | # 
     Thursday, May 11, 2006
    Thursday, May 11, 2006 9:05:42 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp | Articles )

    I am posting the code for an article  that will appear in the May issue of Visual Studio Magazine. When the article was originally written it was written from a TDD perspective (which the tests will reflect). Unfortunately, my editor felt that the TDD approach detracted from the content of the article.  For those of you who know me personally, you know that I have a passion for showing people how to practically apply TDD to solve business problems. To that end, I have ensured that the source code that accompanies the article contains all of the tests that I wrote to drive out the functionality of the AddressBook.

    Please feel free to provide feedback on the article, I am constantly looking for ways to improve my writing skills to achieve greater impact on the masses.

    Thanks.

    JP

    Comments [1] | | # 
     Wednesday, May 10, 2006
    Wednesday, May 10, 2006 6:09:06 AM (Mountain Standard Time, UTC-07:00) ( Agile | Tools )

    Currently some of my links in dasblog are not working correctly and some people are having problems with accessing the entire NAnt series of posts. To ensure that everyone can read them in their entirety here are the links to the current 6 posts:

    Enjoy.



    TODO
    Comments [6] | | # 
     Friday, May 05, 2006
    Friday, May 05, 2006 3:20:02 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp )

    I thought I would take the time to post a simple example of TDD that people can use to build a class that could potentially add value to their current project. I am going to build a Money class test first. Lots of us work on projects that have to manipulate money in one form or another. For me, when I work on e-commerce apps I typically have to perform many different operations that deal and manipulate with monetary values. Traditionally people would use decimal or double types to represent the monetary amount. Unfortunately, this also meant that logic to perform rounding related issues was usually placed in some utility class or worse yet, in multiple places in the code where money was being manipulated. I don’t want to delve to far into discussion, as I feel that code speaks louder than words. Let’s start with the first test:

    1 [TestFixture]
    2 public class MoneyTest
    3 {
    4 [Test]
    5 public void ShouldBeAbleToCreateMoney()
    6 {
    7 Money money = new Money(20.00);
    8 Assert.AreEqual(20.00,money.Amount);
    9 Assert.AreEqual(2000,money.Cents);
    10
    11 money = new Money(10.25);
    12 Assert.AreEqual(10.25,money.Amount);
    13 Assert.AreEqual(1025,money.Cents);
    14 }
    15 }
    16

    As you can see. This test is pretty simple. It is just asserting that I can construct a new money instance that can be used to represent some monetary amount. Currently I am not in a build state, so I need to write enough code to make the test compile, and then pass. The following snippets show the progression of the Money class to make the test compile

     

    1 public class Money
    2 {
    3 public Money(double amount)
    4 {
    5 throw new NotImplementedException();
    6 }
    7 }
    8

     

    1 public class Money
    2 {
    3 public Money(double amount)
    4 {
    5 throw new NotImplementedException();
    6 }
    7 8 public double Amount
    9 {
    10 get { throw new NotImplementedException(); }
    11 }
    12 }
    13
    1 public class Money
    2 {
    3 public Money(double amount)
    4 {
    5 throw new NotImplementedException();
    6 }
    7 8 public double Amount
    9 {
    10 get { throw new NotImplementedException(); }
    11 }
    12 13 public int Cents
    14 {
    15 get { throw new NotImplementedException(); }
    16 }
    17 }
    18

    Ok, so we can easily see that there is no hope for these tests passing (from this point on I will skip showing the class generation step using ReSharper). Let’s write enough code to make the tests pass.

     

    1 public class Money
    2 {
    3 private readonly double amount;
    4 5 public Money(double amount)
    6 {
    7 this.amount = amount;
    8 }
    9 10 public double Amount
    11 {
    12 get { return this.amount; }
    13 }
    14 15 public int Cents
    16 {
    17 get { return Convert.ToInt32(amount * 100); }
    18 }
    19 }
    20

    Hopefully we are all in agreement that at the outset, this is currently the simplest way to implement the functionality described by the test. Which is exactly the point. Solve problems in small increments. Don’t future proof your designs. If a requirement changes or gets added, account for that fact by adding a new test and implementing the change/ new functionality. Ok, let’s write a test that is definitely going to cause us to rethink the design:

     

    1 [Test]
    2 public void ShouldRoundOnCreation()
    3 {
    4 Money money = new Money(20.678);
    5 Assert.AreEqual(20.68,money.Amount);
    6 Assert.AreEqual(2068,money.Cents);
    7 }

    If you add this new “requirement” you will quickly see that the current scheme I have come up with for storing the internal amount of the money as double is going to cause grief. The following ReSharper dialog shows the failure that occurs when this test is run:

     

    Exception1

    I am fairly confident that most of us are aware of some of the rounding issues that can arise from using double as a storage type for money. For that reason I am going to refactor the money class to use an int to store the number of pennies that the money consists of :

     

    1 public class Money
    2 {
    3 private readonly int cents;
    4 private double roundedAmount;
    5 6 public Money(double amount)
    7 {
    8 roundedAmount = Math.Round(amount, 2);
    9 cents = Convert.ToInt32(roundedAmount * 100);
    10 }
    11
    12 public double Amount
    13 {
    14 get { return roundedAmount; }
    15 }
    16 17 public int Cents
    18 {
    19 get { return cents; }
    20 }
    21 }

    As you can see the implementation of the class has not changed all that much. With the addition of the call to round and a field to now store the amount of the money object in pennies. You may ask why I bother to keep the field “roundedAmount” which stores the double value of the money as opposed to just calculating it every time the Amount property is accessed. Because Money is a classic “value object” once constructed it is completely immutable (read-only). For that reason, I don’t really care to recalculate every time the Amount property is accessed, as it will never change for a particular instance of Money. I perform the rounding right off the bat, and then continue to use it from that point on.

    If I run the tests, everything will now be passing. Unfortunately I am not done yet. Due to the way that the .Net framework implements rounding, I am going to run into a problem when I add the following new lines to the existing test for rounding:

     

    1 [Test]
    2 public void ShouldRoundOnCreation()
    3 {
    4 Money money = new Money(20.678);
    5 Assert.AreEqual(20.68,money.Amount);
    6 Assert.AreEqual(2068,money.Cents);
    7
    8 money = new Money(37.535);
    9 Assert.AreEqual(37.54,money.Amount);
    10 }

    The assertion on line 9 will fail. I could try using overloads of the Math.Round method, but they will all produce the same result. So once again, I am going to have to refactor the Money class to perform the rounding itself.

     

    1 public class Money
    2 {
    3 private readonly int cents;
    4 private double roundedAmount;
    5 6 public Money(double amount)
    7 {
    8 double quotient = amount / 0.01;
    9 int wholePart = (int)quotient;
    10 decimal mantissa = ((decimal)quotient) - wholePart;
    11
    12 roundedAmount = mantissa >= .5m ? .01 * (wholePart + 1) : .01 * wholePart;
    13 cents = Convert.ToInt32(roundedAmount * 100);
    14 }
    15
    16 public double Amount
    17 {
    18 get { return roundedAmount; }
    19 }
    20 21 public int Cents
    22 {
    23 get { return cents; }
    24 }
    25 }

    Ok, all of the tests are now passing and I am taking care of rounding myself. Unfortunately, the constructor has gotten a little hairy. Remember the mantra “Red – Green – Refactor”. I think we are sorely in need of a refactoring at this point. Let’s try and extract some methods out of the constructor. First off, let’s get the rounding calculation out of there:

     

    1 public class Money
    2 {
    3 private readonly int cents;
    4 private double roundedAmount;
    5 6 public Money(double amount)
    7 {
    8 roundedAmount = RoundToNearestPenny(amount);
    9 cents = Convert.ToInt32(roundedAmount * 100);
    10 }
    11
    12 private double RoundToNearestPenny(double amount)
    13 {
    14 double quotient = amount / 0.01;
    15 int wholePart = (int)quotient;
    16 decimal mantissa = ((decimal)quotient) - wholePart;
    17 18 return mantissa >= .5m ? .01 * (wholePart + 1) : .01 * wholePart;
    19 }
    20
    21 public double Amount
    22 {
    23 get { return roundedAmount; }
    24 }
    25 26 public int Cents
    27 {
    28 get { return cents; }
    29 }
    30 }
    31

    Things are looking a little better. One more thing that I want to do, even though it is a one liner, is extract out the conversion to pennies:

    1 public class Money
    2 {
    3 private readonly int cents;
    4 private double roundedAmount;
    5 6 public Money(double amount)
    7 {
    8 roundedAmount = RoundToNearestPenny(amount);
    9 cents = ToPennies(roundedAmount);
    10 }
    11 12 private int ToPennies(double amount)
    13 {
    14 return Convert.ToInt32(amount * 100);
    15 }
    16
    17 private double RoundToNearestPenny(double amount)
    18 {
    19 double quotient = amount / .01;
    20 int wholePart = (int)quotient;
    21 decimal mantissa = ((decimal)quotient) - wholePart;
    22 23 return mantissa >= .5m ? .01 * (wholePart + 1) : .01 * wholePart;
    24 }
    25
    26 public double Amount
    27 {
    28 get { return roundedAmount; }
    29 }
    30 31 public int Cents
    32 {
    33 get { return cents; }
    34 }
    35 }
    36

    Ok, things are looking good. The 2 new methods we introduced as part of the refactoring are getting tested by the tests that already exist. Of course, there is no problem with increasing the visibility of these new methods if you wanted to directly exercise them. We can be assured that they are being exercised as the constructor makes direct use of them. So with rounding taken care of we can now move on to add new functionality to the money class.

    Remember the Money class is completely immutable, so once constructed there is no way to change the value that the Money object represents. That being said, we should be able to treat our Money class like any of the intrinsic value types in the framework (note that currently the Money type is a class not a struct), meaning we should be able to add two Monies together, subtract, multiply etc. Let’s first write a test to ensure that two different instance of the same value of money evaluate to be equal to one another:

     

    1 [Test]
    2 public void IdenticalMonetaryValuesShouldBeEqual()
    3 {
    4 Money tenDollars = new Money(10.00);
    5 Money anotherTenDollars = new Money(10.00);
    6
    7 Assert.AreEqual(tenDollars,anotherTenDollars);
    8 }

    Initially this test will fail because by default, all reference types use ReferenceEquals to determine object equality. I can quickly get the test passing by changing the Money class to be a struct (value type). To make that possible I will need to make the ToPennies and RoundToNearestPenny methods static:

     

    1 public struct Money
    2 {
    3 private readonly int cents;
    4 private double roundedAmount;
    5 6 public Money(double amount)
    7 {
    8 roundedAmount = RoundToNearestPenny(amount);
    9 cents = ToPennies(roundedAmount);
    10 }
    11 12 private static int ToPennies(double amount)
    13 {
    14 return Convert.ToInt32(amount * 100);
    15 }
    16
    17 private static double RoundToNearestPenny(double amount)
    18 {
    19 double quotient = amount / .01;
    20 int wholePart = (int)quotient;
    21 decimal mantissa = ((decimal)quotient) - wholePart;
    22 23 return mantissa >= .5m ? .01 * (wholePart + 1) : .01 * wholePart;
    24 }
    25
    26 public double Amount
    27 {
    28 get { return roundedAmount; }
    29 }
    30 31 public int Cents
    32 {
    33 get { return cents; }
    34 }

    Again, with that “small” change, I can run the test for equality and it will now pass. Let’s now write a test to add two money objects together:

     

    1 [Test]
    2 public void ShouldBeAbleToAddMoney()
    3 {
    4 Money tenDollars = new Money(10.00);
    5 Money tenFifty = new Money(10.50);
    6
    7 Assert.AreEqual(new Money(20.50),tenDollars.Add(tenFifty));
    8 }

    You may be asking why I am not using operator overloading. No particular reason! With that failing test in place, we can carry on to add what proves to be a very simple method (thanks to all of the work we already did with the Rounding and Conversion)  (from this point I will only include new code fragments as opposed to the entire class):

     

    1 public Money Add(Money other)
    2 {
    3 return new Money(this.Amount + other.Amount);
    4 }

    As you can see. This does not break the immutabilty rule of the Money class, as the Add method returns a brand spanking new instance of Money that reflects that new value. Finishing off for today (there are other pieces of functionality that could be added, but I will leave that to you) let’s deal with one more piece of functionality – Multiplication. Multiplication is a good one as we are often wanting to calculate the GST for a certain amount of money when performing order totalling for E-comm sites. Let’s write a test to ensure that we can use Money to calculate GST correctly:

     

    1 [Test]
    2 public void ShouldCalculateGSTCorrectly()
    3 {
    4 Money tenDollars = new Money(10.00);
    5 Assert.AreEqual(new Money(.70),tenDollars.MultiplyBy(.07));
    6 }
    7

    Once again, implementing this new piece of functionality proves to be very simple:

    1 public Money MultiplyBy(double multiplicationFactor)
    2 {
    3 return new Money(this.Amount * multiplicationFactor);
    4 }

    Although there are other operations that could be added onto this money class (as well as the ability to have a Money class that can be used for multiple currencies), because we have Money encapsulated as an object in the domain we can now perform complex operations that previously would have been messily placed in utility classes and the like. This last "large" segment of code shows a family of classes taking advantage of the Money class for an Order scenario: 

    1 [Test]
    2 public void ShouldTotalOrderCorrectly()
    3 {
    4 Item chocolate = new Item(new Money(20.00),"Specialty Chocolate" );
    5 Item pop = new Item(new Money(10.00),"Pop" );
    6 Item chips = new Item(new Money(25.00),"Chips" );
    7
    8 Order order = new Order();
    9 order.Add(chocolate);
    10 order.Add(pop);
    11 order.Add(chips);
    12
    13 Assert.AreEqual(new Money(3.85),order.TotalGST);
    14 Assert.AreEqual(new Money(55.00),order.SubTotal);
    15 Assert.AreEqual(new Money(58.85),order.Total);
    16
    17 }
    18
    19 private class Order
    20 {
    21 private IList<Item> items;
    22 private delegate Money Summarize(Item item);
    23
    24 public Order():this(new List<Item>())
    25 {
    26
    27 }
    28
    29 public Order(IList<Item> itemsInOrder)
    30 {
    31 items = itemsInOrder;
    32 }
    33
    34 public void Add(Item item)
    35 {
    36 items.Add(item);
    37 }
    38
    39 public Money TotalGST
    40 {
    41 get 42 {
    43 return TotalUsing(delegate(Item item)
    44 {
    45 return item.GST;
    46 });
    47 }
    48 }
    49
    50 public Money SubTotal
    51 {
    52 get 53 {
    54 return TotalUsing(delegate(Item item)
    55 {
    56 return item.Price;
    57 });
    58 }
    59 }
    60
    61 private Money TotalUsing(Summarize summarizer)
    62 {
    63 Money result = new Money();
    64 65 foreach (Item item in items)
    66 {
    67 result = result.Add(summarizer(item));
    68 }
    69 70 return result;
    71 }
    72
    73
    74
    75 public Money Total
    76 {
    77 get 78 {
    79 return SubTotal.Add(TotalGST);
    80 }
    81 }
    82 }
    83
    84 private class Item
    85 {
    86 private const double TAX_RATE = .07;
    87 private Money price;
    88 private string name;
    89 90 public Item(Money price,string name)
    91 {
    92 this.price = price;
    93 this.name = name;
    94 }
    95 96 public Money GST
    97 {
    98 get 99 {
    100 return price.MultiplyBy(TAX_RATE);
    101 }
    102 }
    103
    104 public Money Price
    105 {
    106 get 107 {
    108 return price;
    109 }
    110 }
    111
    112 public string Name
    113 {
    114 get 115 {
    116 return name;
    117 }
    118 }
    119 }
    120 }
     

    Enjoy.


    TODO
    Comments [4] | | # 
     Thursday, May 04, 2006
    Thursday, May 04, 2006 5:21:37 PM (Mountain Standard Time, UTC-07:00) ( Agile | Tools )

    Just got asked a question by Scott Cowan :

    Q:  is there a way in nant to run a call for each .sql file in a dir ?

    A: If you wanted to execute the scripts for a whole directory of sql files (and the order of the files running is not important), then you can take advantage of the NAnt <foreach> task.   Here is an example of a target that you could set up to run all of the sql files in a specific folder:

    <target name="exec.sql.folder">
        <foreach item="File" property="filename">
           <in>
              <items basedir="${folder}">
                 <include name="*.sql"/>     
              </items>
          </in>
          <do>
              <property name="target" value="${filename}"/>
              <call target="exec.sql.template"/>
          </do>  

    </foreach>

    </target>

    Notice that you would want to call this target from another target that sets the folder property to execute against:

    <target name="exec.all.sql">

         <property name="folder" value="sql"/>

        <call target="exec.sql.folder"/>

    </target>

    Hope this helps.

    JP

    Comments [0] | | # 
    Thursday, May 04, 2006 12:04:16 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp | Tools )

    Ok, it's been a few weeks since my last post on automating your build with NAnt. We left off being able to compile and run all of the unit tests for the code. This is an essential step to be able to perform quickly. When solution sizes get bigger and the codebase gets larger, you will be glad that you spent the time automating the build process. There is a large difference between the time required to perform build activities at the command line using NAnt vs Studio. So far, we have not even talked about the database. As most of us are building applications with some sort of database back-end, it is essential that we can also automate the steps necessary to prep the database for use in our builds. Remember back to folder structure for our root directory?

    folderstructure1

    It is now time to shift our attention to the “sql” directory. In this post, I am making the assumption that the schema you will be creating will be your own (ie. You are not needing to deal with 3rd party databases that you need to integrate with. That is a story for another day). Let’s take a quick look at the contents of the sql directory. Here are the files that I have set up so far:

    • data.sql.template – File containing any seed data that is required to actually run the application.
    • nwind.sql.template – File containing the sql necessary to recreate the database,tables,indexes etc
    • security.sql.template – File containing the sql necessary to add roles,grant roles, add users etc to the database
    • storedProcedures.sql.template - File containing the CRUD procedures for data access
    • views.sql.template – File containing any views required by the application

    As you can see. This list is pretty short, and you could add files for different responsibilities very easily.

    You are probably asking yourself what the .template extension is for? Take a look at the first couple of lines in the nwind.sql.template file (pay attention to the items that have the red boxes around them):

    StartOfSqlScript All of the items that are surrounded by the @ symbol will actually get replaced at build time by values that NAnt retrieves from a local settings file for the user. This is what will allow multiple developers on the team to build the database to whatever location they want on their own hard drives, as well as naming the catalog for the database whatever they want. This allows for a lot of flexibility when it comes to how individual developers configure their workstations and dev environments. With this (and the other sql files in place), I need to add a target(s) to actually build the database using NAnt.

    The first thing I am going to do is add a couple of new properties to the top of the build file:

        <!-- environment-specific properties -->   
        <property name="osql.exe" value="C:\program files\microsoft sql server\90\Tools\Binn\osql.exe" />
        <property name="osql.ConnectionString" value="-E" />   
        <property name="env.COMPUTERNAME" value="${environment::get-variable('COMPUTERNAME')}" />
        <property name="aspnet.account" value="${env.COMPUTERNAME}\ASPNET" />   
        <property name="framework.version" value="v2.0.50727" />   

    Notice that I have specified values for the location of osql and the connection string with which to connect to OSQL. Now of course, I can’t assume that everyone on my team has loaded SQL to the default location. In which case, their path to SQL will be different. I also can’t assume that all of the developers on my team have integrated windows authentication enabled on their sql server install. If they don’t the -E switch for OSQL won’t work. Let me stress a point I am about to make “All Developers On A Team Regardless of machine configuration, should be able to utilise the build file without changing it”. Now as you can see, if I relied solely on the properties that I have created in the buildfile, I would be constraining the machine configurations of my team to have to use the exact same settings. This is where local property files come into play. Notice in the root directory I have a file named local.properties.xml.template. LocalPropertiesXmlTemplate

    The local.properties.xml.template file contains all of the properties that could possibly differ on each individual developers workstation. The template file is actually a repository artifact. So when a new setting gets introduced that could potentially be different of each persons machine, it is added to the template file. Take a look at the contents of the template file:

    <?xml version="1.0"?>
    <properties>
      <property name="sqlToolsFolder" value="C:\Program Files\Microsoft SQL Server\90\Tools\Binn"/>
      <property name="osql.ConnectionString" value="-E"/>
      <property name="initial.catalog" value="Northwind"/>
      <property name="config.ConnectionString" value="data source=(local);Integrated Security=SSPI;Initial Catalog=${initial.catalog}"/> 
      <property name="database.path" value="C:\root\development\databases" />
      <property name="osql.exe"  value="${sqlToolsFolder}\osql.exe" />
    </properties>

    Notice that it is a well formed xml document. You should also notice that the names of some of the properties are named identically to the names of properties that already exist in the build file (osql.ConnectionString, osql.exe). When a developer performs a fresh check out or the template file is changed, they will copy the template file into the same directory as the template file and rename it to local.properties.xml. Once renamed, the developer will open up the local.properties.xml file (not under source code control), and change the value of any of the properties that they need to, to reflect the configuration of their own machines. Ok, so this is great, but how do the settings in this file make integrate themselves into the actual build file? If I switch back to my build file, I will now add a check to include the settings from the local.properties.xml file, if the file is present:

    <!-- environment-specific properties -->   
        <property name="osql.exe" value="C:\program files\microsoft sql server\90\Tools\Binn\osql.exe" />
        <property name="osql.ConnectionString" value="-E" />   
        <property name="env.COMPUTERNAME" value="${environment::get-variable('COMPUTERNAME')}" />
        <property name="aspnet.account" value="${env.COMPUTERNAME}\ASPNET" />   
        <property name="framework.version" value="v2.0.50727" />    
                
        <if test="${file::exists('local.properties.xml')}">
            <echo message="Loading local.properties.xml" />
            <include buildfile="local.properties.xml" />
        </if>

    Notice I am telling NAnt to include an external file into the buid file. If the developer has created and modified their local.properties.xml file, then all of the settings they specified in that file will overwrite the default values of the properties that were already in the build file. Voila, multi-dev setup taken care of.

    Now it is time to focus on performing activities with the database. The first thing we need to take care of is changing the template files in the sql directory into the appropriate .sql files. Remember, as I said before. The .template files are the files that actually get placed/versioned in the repository. The .sql files will get automatically created by NAnt but not get stored in the repository. Let’s add a new target that will be able to convert a .template file into a file that can actually get worked with.

    <target name="convert.template">
            <copy file="${target}.template" tofile="${target}" overwrite="true">
                <filterchain>
                    <replacetokens>
                        <token key="INITIAL_CATALOG" value="${initial.catalog}" />                   
                        <token key="ASPNETACCOUNT" value="${aspnet.account}" />
                        <token key="OSQL_CONNECTION_STRING" value="${osql.ConnectionString}" />
                        <token key="CONFIG_CONNECTION_STRING" value="${config.ConnectionString}" />                   
                        <token key="DBPATH" value="${database.path}"/>
                    </replacetokens>
                </filterchain>
            </copy>
        </target>

    The convert.template target will copy a file with the .template extension to a file without the .template extension. At the same time, I am taking advantage of NAnt ability to apply filters during the copy process. In this scenario I am using the replacetokens filter to replace any occurrence of a token in the file (tokens in NAnt are specified by surrounding the item with the @ symbol), with a specific value. If you look back to the beginning of the nwind.sql.template file you will see that there are several tokens that will be replaced with settings pulled from my local settings file:

    • All instances of @INITIAL_CATALOG@ will be replaced by the value of the initial.catalog property (“Northwind”)
    • All instances of @DBPATH@ will be replaced by the value of the database.path property (“C:\root\development\databases”)

    Some of the other files in the sql directory make use of some of the other tokens. Some of the tokens do not exist in any of the sql files, but exist in other template files that I will talk about in future posts. With the “convert.template” target in place. I now want to create a target that I can use to execute a sql script:

     <target name="exec.sql.template">
            <call target="convert.template" />
            <exec program="${osql.exe}" commandline="${osql.ConnectionString} -n -b -i ${target}" />
     </target>

    Notice that the exec.sql.template is taking advantage of the fact that each developer could have a different location and connection specifics for osql. For the astute reader, you will note that if you were to just call exec.sql.template on its own, nothing would happen as the convert.template target assumes that a ${target} property has been set up before being invoked. You will notice that the exec.sql.template does not provide a value for the ${target} property, it is also attempting to make use of a ${target} property that should have already been assigned. For this reason, the exec.sql.template target is meant to be called from a target that will actually execute the scripts for db creation in the correct order. And here it is:

    <target name="builddb">
            <property name="target" value="sql\nwind.sql" />
            <call target="exec.sql.template" />
        
            <property name="target" value="sql\views.sql" />
             <call target="exec.sql.template" />

             <property name="target" value="sql\storedProcedures.sql" />
             <call target="exec.sql.template" />
                    
             <property name="target" value="sql\security.sql" />
             <call target="exec.sql.template" />
    </target>

    Notice that the builddb target knows the correct order in which to execute the sql scripts. Also notice the use of the call task that can be used to invoke targets from other targets. You will see that before the execution of the exec.sql.template target, the builddb target will set the value for the ${target} property for the file to act against next. Remember, first time builddb is run there will be no .sql files in the sql directory only .sql.template files. The convert.template target knows to tack on the .template extension and copy/transform accordingly.

    After running the builddb target, the database will be completely rebuilt from scratch (it will be deleted if it exists already). Again, something that I haven't talked about is the usefulness of keeping all of the db in .sql files. They are easy to maintain in the repository. When another developer on your team adds a table,view etc (making sure that they make changes to the .template files not the .sql files). You just need to update your sql directory and run your builddb target again. If 2 or more of you have made changes to the same table, worst case scenario you will need to use your merge/diff tool to see the differences. Best case scenario, your files will merge together seamlessly with all of your combined changes. Once the application has been deployed to production you can create subdirectories under the sql directory corresponding to each release/db update. These folder would only contain alters/new table additions. Once you have deployed to production you will want to leave the existing scripts under the sql directory as is. That way when you do a builddb, your database will get deleted created from the original sql scripts, and then all of the alters that have been applied in production will be applied against your local database. This is a much better process that changing the original sql files, as your DB’s probably don’t have the luxury of tearing down/recreating the database whenever a change goes into place. It also makes providing sql for the DB’s easy as you can just send them the alter file that you will also have in your repository. Of course, I can post about strategies for maintaining DB’s for deployed apps another time. After the builddb target runs, the sql directory will now look like this:

    SqlDirectoryAfterBuildDb

     

     

     

     

     

     

     

     

     

    As you can see, NAnt took care of copying the files and renaming them as necessary. If you take a look at the first couple of lines in the nwind.sql file (pay attention to the items in the red boxes) StartOfSqlScriptAfterTransform.

     

     

     

     

     

     

     

     

     

     

     

     

     

    You will notice that what use to be tokens are now concrete settings specific to my machine!! Feel free to ask questions, provide feedback etc. Enjoy automation.

     

     

    TODO
    Comments [3] | | # 
     Tuesday, May 02, 2006
    Tuesday, May 02, 2006 3:25:51 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp | Patterns )

    I just had a great question asked by David Woods about one scenario that often comes up when utilising the Model View Presenter pattern:

    Q: How do you deal with drop down lists? They vary from web to windows and I want to refactor my app so that it can use either

    A: The code for this post shows one solution to the problem. An interface (ILookupList) is created to abstract the details of the UI specific list controls from the presenter:

     

    namespace Lists.Web.Controls.Test
    { public interface ILookupList
    { void Add(ILookupDTO dto); void Clear(); } }

     

    One concrete implementation of this interface is the WebLookupList class:

     

    using System.Web.UI.WebControls;
    
    namespace Lists.Web.Controls.Test
    { public class WebLookupList : ILookupList
    { private readonly ListControl listControl; public WebLookupList(ListControl listControl) { this.listControl = listControl; } public void Add(ILookupDTO dto) { listControl.Items.Add(new ListItem(dto.Text, dto.Value)); } public void Clear() { listControl.Items.Clear(); } } }
    Notice how all the WebLookupList does is delegate to an actual “Web” ListControl. ListControl is the base class for both DropDownList and ListBox, so it is useful to use the superclass in this case. The last piece of the puzzle is the LookupCollection class:
    using System.Collections.Generic;
    
    namespace Lists.Web.Controls.Test
    { public class LookupCollection
    { private readonly IEnumerable<ILookupDTO> dtos; public LookupCollection(IEnumerable<ILookupDTO> dtos) { this.dtos = dtos; } public void BindTo(ILookupList list) { list.Clear(); foreach (ILookupDTO dto in dtos) { list.Add(dto); } } } }
    A LookupCollection gets instantiated with an IEnumerable<ILookupDTO> and can then be told to bind itself to any ILookupList. The ILookupDTO interface is just an interface that can be implemented by objects that want to be used as values in a lookup list. With all of these pieces in place it becomes relatively trivial to populate a list on a web page with all of the customers in the system. Take a look at an interface for such a view:
    namespace Lists.Web.Controls.Test
    { public interface IViewContactView
    { ILookupList Contacts { get;} } }

    Notice that the Contacts property is readonly. A presenter that can work with this view looks as follows:

     

    using System.Collections.Generic;
    
    namespace Lists.Web.Controls.Test
    { public class ViewContactsPresenter
    { private IViewContactView view; public ViewContactsPresenter(IViewContactView view) { this.view = view; } public void Initialize() { new LookupCollection(GetAllContacts()).BindTo(view.Contacts); } public IEnumerable<ILookupDTO> GetAllContacts() { for (int i = 0; i < 20; i++) { yield return new ContactDTO(i.ToString("Name 0"), i.ToString("Address 0"), i.ToString()); } } } }
    In this example, assume that the GetAllContacts method actually lives in a service layer. The code in the Initialize method is now taking advantage of the LookupCollection class to populate the list on the view. The resulting code-behind for a web page becomes much tighter
    using System;
    using System.Web.UI;
    using Lists.Web.Controls.Test;
    
    public partial class _Default : Page,IViewContactView
    { ViewContactsPresenter presenter; protected void Page_Load(object sender, EventArgs e) { presenter = new ViewContactsPresenter(this); if (! IsPostBack) { presenter.Initialize(); } } public ILookupList Contacts
    { get { return new WebLookupList(this.contactDropDown); } } }

    Hope this brief explanation, along with the accompanying source code, gives you a place to start David!!

     

    For those of you who are curious about the order I wrote the tests (as this was done using TDD) here it  is:

    • 1)WebLookupListTest.cs – ShouldAddItemToUnderlyingList
    • 2)WebLookupListTest.cs – ShouldClearUnderlyingList
    • 3)LookupCollectionTest.cs – ShouldBindToLookupList

    Those 3 tests alone helped drive out the interfaces,classes etc. I did not write tests for the presenter and the view as MVP was not the main focus of the post, as much as how to have the presenter talk to the list controls. If you have any questions or feedback, please don’t hesitate to ask.

     

    Resources:


    TODO
    Comments [2] | | # 
     Monday, May 01, 2006
    Monday, May 01, 2006 3:27:33 PM (Mountain Standard Time, UTC-07:00) ( Presentations )

    Well, the first meeting of the Edmonton .Net Users Group was fantastic. The Edmonton crowd came out in great numbers (despite the hockey game). There were lots of intelligent questions and the hospitality of the hosts was amazing. As promised, I told the attendees that I would release the source for the project that we tried to build during the session. I have left the code exactly where I left off in the presentation, this will give people an opportunity to finish it up for themselves. In two weeks I will release the completed version of the project, which people can use as a comparison to their own solutions.

    Thanks again to the Edmonton .Net Users Group for inviting me up there!!

     

     

     

    Comments [2] | | #