Quickly Building Castle with .NET 3.5


Castle comes with a handy batch script called Release.bat.  I guess in theory the idea is to simply run that and away you go.  However running the script as it is produced the following error:

 

[csc] Compiling 173 files to 'C:\Development\Tools\OSS\Castle-Trunk\build\net-2.0\release\Castle.MicroKernel.dll'.
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(99,12): error CS0246: The type or namespace name 'var' could not be found (are you missing a using directive or an assembly reference?)
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(101,5): error CS1502: The best overloaded method match for 'System.Collections.Generic.Stack<Castle.MicroKernel.IHandler>.Push(Castle.MicroKernel.IHandler)' has some invalid arguments
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(101,28): error CS1503: Argument '1': cannot convert from 'var' to 'Castle.MicroKernel.IHandler'
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(221,4): error CS0246: The type or namespace name 'var' could not be found (are you missing a using directive or an assembly reference?)
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(225,5): error CS1502: The best overloaded method match for 'System.Collections.Generic.Stack<Castle.MicroKernel.CreationContext.ResolutionContext>.Push(Castle.MicroKernel.CreationContext.ResolutionContext)' has some invalid arguments
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(225,26): error CS1503: Argument '1': cannot convert from 'var' to 'Castle.MicroKernel.CreationContext.ResolutionContext'
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Context\CreationContext.cs(227,11): error CS0029: Cannot implicitly convert type 'var' to 'Castle.MicroKernel.CreationContext.ResolutionContext'
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Handlers\DefaultHandler.cs(48,10): error CS0246: The type or namespace name 'var' could not be found (are you missing a using directive or an assembly reference?)
[csc] c:\Development\Tools\OSS\Castle-Trunk\InversionOfControl\Castle.MicroKernel\Releasers\AllComponentsReleasePolicy.cs(63,17): error CS0246: The type or namespace name 'var' could not be found (are you missing a using directive or an assembly reference?)

And a quick peek at the release.bat file reveals the problem:

@echo off
nant -t:net-1.1 -f:release.build package-net-1.1 %*
nant -t:net-2.0 -f:release.build package-net-2.0 %*

So, going with that, the soluton should be:

nant -t:net-3.5 -f:release.build package-net-3.5 %*

Yeah?  Unfortunately not, the release.build doesn't contain a Target called package-net-3.5.  So a quick copy and paste later:

<target name="package-net-3.5">
		<!--
			clean is first target executed so we can get rid of
			any old assemblies
		-->
		<nant buildfile="default.build" target="clean build installer">
			<properties>
				<property name="build.rebuild" value="true" />
				<property name="nant.settings.currentframework" value="net-3.5" />
				<property name="project.config" value="release" />
				<property name="sign" value="true" />
				<property name="build-zipfile" value="${build.dir}/Castle-${project.major}.${project.minor}.${project.build}-${framework::get-target-framework()}-${project.config}-${datetime::get-year(datetime::now())}-${datetime::get-month(datetime::now())}-${datetime::get-day(datetime::now())} (r${svn.revision}).zip" dynamic="true" />
			</properties>
		</nant>
	</target>

Run the command, sit back and wait for your shiney new assemblies.  Success!

NHibernate

I use Castle's NHibernate facilities and did plan on rebuilding Castle with the latest version of NHibernate.  Unfortunately the way NHibernate deals with proxies for lazy loading is changing and Castle hasn't ben updated yet.  This is something I'm going to look at this week as I would like to use the latest NHibernate.  And yes, the Core NHibernate assembly no longer has a dependency on Castle!

author: Chris Canal | posted @ Tuesday, November 11, 2008 2:23 PM | Feedback (0)

Collection Encapsulation and Business Logic


Yesterday Colin Jack and Jimmy Bogard had a fantastic exchange on Twitter about dealing with collections in your Domain model, and Derick Bailey also blogged about his thoughts on the matter.  While I didn't take part in the conversation, I did have a conversation with him at ALT.NET UK about his solution and blog post.

The Twitter conversation lead to a discussion about both proposed solutions with a friend of mine that is starting a Greenfield project and I thought I would join the bigger conversation too.  I'm not going to show any code, as Colin and Derick already have great examples.

Custom Collections

Colin's solution involves using custom collection collections.  This gives him the flexibility of implementing the interfaces he wants to deliver the functionality he requires: read only, management of adding/removing items, etc.

Personally, I'm not keen on this solution.  I've been down this path before a few years ago, and it did not end well.  I felt that it lead to a dilution of business rules, split between the Aggregate Root and the custom collection and added needless complexity where a simpler solution would do the same job.  I also ran into a few issues with introducing new team members, as most of them went the IList<T> route if left on their own.

Colin writes:

I've found that it just results in my aggregate roots and key entities getting bogged down in lots of boring collection work so I prefer to farm out this work to custom collections.

I don't really agree that the collection work is boring; for me, the collection work will generally lead to apply some form of business rules or satisfying bi-directional relationships.

IEnumerable<T>

This solution is presented in Derick's blog post and is my current preferred solution.  We get the functionality we want, a read-only collection exposed on the Entity and we control the interaction with the collection within the Aggregate root and that's where I feel the interaction should be controlled.  I also think it's the simplest possible solution to achieve what we are looking for without compromising the Domain.  I also find it more discoverable and readable when seen in the context of the Aggregate root instead external in a custom collection.

So...

As Derick noted in his post, "Like everything else in software development, there are multiple ways to solve the same problem." and I completely agree.  I've been in my current position for 3months and while the code base and Domain is small, it's already starting to get fairly complex.  My work is a debt management and solutions company, and after working  with e-commerce/warehousing solutions development and marketing agencies for the past 6 years, the domain is completely alien to me.  Encapsulating all the core logic in the Aggregate root has been really beneficial for me so far as it's fairly easy to locate and work with whenever the requirement's change... or when I just get it plain wrong.

Returning to the conversation with my friend, I pushed my own solution at him but made it clear that Colin's solution is worth keeping in mind.  As my companies Domain gets bigger and more complex, I wouldn't think twice about refactoring to Colin's solution if it would ease any headaches that manifest with my current solution.

author: Chris Canal | posted @ Thursday, October 23, 2008 5:32 PM | Feedback (1)

SQLite, NHibernate and In-Memory database - FTW!


I recently posted about using SQLite to speed up integration tests when using NHibernate and one of the issues I was having was the inmemory database being dropped.  I had been meaning to spend some time working out what the problem was but Justin Etheredge has done the hard work and figured out the solution!

Check it out here: http://www.codethinked.com/post/2008/10/19/NHibernate-20-SQLite-and-In-Memory-Databases.aspx  Good job Justin, I owe you a pint!

So, for those of you that use Binsor, the updated script now looks like this:

settings(keymap, item: 'item'):
   provider = 'NHibernate.Connection.DriverConnectionProvider'
   connection.driver_class = 'NHibernate.Driver.SQLite20Driver'
   dialect = 'NHibernate.Dialect.SQLiteDialect'
   connection.connection_string = 'Data Source=:memory:'
   connection.release_mode = 'on_close'
   cache.use_second_level_cache= 'false'

The "connection.connection_string" and "connection.release_mode" are the options that have changed.

author: Chris Canal | posted @ Tuesday, October 21, 2008 11:35 AM | Feedback (1)

ALT.NET Glasgow Drinks - Tonight Waxy O'Conner's 7PM


Tonight was supposed be the ALT.NET Glasgow Python Code Kata, unfortunately this had to be postponed because of problems with the venue.  Instead, we're meeting for drinks at Wax O'Conner's.  I was discussing this with someone who suggested the still having the gathering was a waste of time as we will not be covering any code.

I couldn't disagree more with this.  For me, enabling converstations is one of the main tenents of ALT.NET.  Be it blogging, podcasts, tweets or an argument over a pint, as long as we talking then we're doing out part.  I like to think the things I've covered or suggest at the meeting has been taken on board by other people as I have taken things from other people on board.

For this evening, I have a few things I would like to cover:

  1. Venue
    Our venue, supplied kindly by Paul Cowan, is no longer available after the end of October.  I really want us to try and organise a replacement ASAP.
  2. ALT.NET Scotland Gathering
    I have brought this up a few times, and I am still keen on trying to get something together.  I spoke to a few people at ALT.NET UK, and the consentaneous seemed to be that I was worth doing.
  3. Bring a buddy
    We need to spread the word!  So I would like to propose some incentive for brining a buddy.  Maybe the person who brings the most gets a bootle of Paul's tiple of

That's it really, look forward to see eveything that comes along.  Oh, and if your coming along,

author: Chris Canal | posted @ Monday, October 13, 2008 1:23 PM | Feedback (0)

The case of the disappearing .spark files


We rolled out the first drop of an internal web application today.  Quick trip to TeamCity, fire the Release build and wait for the ZIP to be spat out at the end. Bing!  Less than a minute later we have a fully tested deployable version of the site all zipped up.

We uploaded it to the server, hit the index and... nothing but a Yellow Screen of Death, ""The view 'Index' or its master could not be found.".  Uhoh.

A quick look in the ZIP confirmed that the Views folder held only a lonely looking web.config file.  Not exactly what was supposed to happend.  A quick spin of the build script locally reconfirmed that the content of the View folder was indeed being treated like an ugly step-child.

After a little head scratch, I decided to check out the web projects .csproj file, and found my first clue:

<None Include="Views\CertificateOfPostage\Export.spark" />
<None Include="Views\CertificateOfPostage\Index.spark" />
<None Include="Views\CertificateOfPostage\_CertificateItems.spark" />
<None Include="Views\Home\Index.spark" />
<None Include="Views\Shared\Application.spark" />
<None Include="Views\Shared\_ajaxhelper.spark" />
<None Include="Views\Shared\_datepicker.spark" />
<None Include="Views\Shared\_footer.spark" />
<None Include="Views\Shared\_global.spark" />
<None Include="Views\Shared\_navigation.spark" />
<None Include="Views\Shared\_tooltip.spark" />
<None Include="Views\Shared\_validation.spark" />

"The game is afoot. Not a word! Into your clothes and come!"

A quick peek at the properties of the Spark files confirmed that the Build Action is set to "None".  Duh!

We use MSBuild to actually build the assemblies, so this looked like the most likely cause.  A quick switch to "Content" and a double later we have a releasable build, View files included!  :o)

author: Chris Canal | posted @ Friday, October 10, 2008 4:56 PM | Feedback (1)

Blisteringly fast Integration Tests with NHibernate and SQLite


One thing I love about using NHibernate as my O/RM is being able to push the database schema from the domain.  This lets me create the database from scratch for each integration test fixture and get it into the required state.  Creating the database with NHibernate is quick and simple.  Hell, here is the code to do it:

Configuration cfg = container.Resolve<Configuration>();
SchemaExport export = new SchemaExport(cfg);
export.Execute(true, true, false, true);

Nifty, eh?

But tests that hit the database are sloooow, and these quickly become tests that are not ran. Tests that query the database are slow, and because I regenerate the whole database for each TestFixture, they are reeeeally slow.  I guess one solution would be to not run the integration tests locally, but I don't like this option and I  believe tests should be ran as often as possible.

Luckily; NHibernate provides a number of RDBMS providers.  My first port of call was SQLServer CE, but after the first test run and it failing on anything with a formula I quickly abandoned it.

Enter SQLite, "the most widely deployed SQL database engine in the world".  Awesome.

A quick modification to to the NHibernate and the tests were up and running as fast as a pig to...

Setting everything up was quick and painless. 

First: grab the required assemblies from http://sqlite.phxsoftware.com/ and add a reference. 

Second: set up NHibernate; personally I use the Castle NHibernate facilities and Binsor to configure Castle.  Below is the settings I use:

facility NHibernateFacility:
	configuration:
		@isWeb = false, @useReflectionOptimizer = false
		factory:
			@id = 'nhibernate.factory'
			settings(keymap, item: 'item'):
				provider = 'NHibernate.Connection.DriverConnectionProvider'
				connection.driver_class = 'NHibernate.Driver.SQLite20Driver'
				dialect = 'NHibernate.Dialect.SQLiteDialect'
				connection.connection_string = 'Data Source=intranet.db;Version=3;New=True'
				cache.use_second_level_cache= 'false'
				show_sql = 'true'
			assemblies = [ Assembly.Load("Intranet") ]
facility TransactionFacility

And that is pretty much it.  One gotcha I'm aware of is SQLite on a 64-bit OS.  I haven't experienced this first hand but I will try and dig out some information. Oh, and for the life of me, I can't get it to work in-memory but I'll be posting about this later as soon as I get a solution.

However I digress; there is another part to this awesome story: the Continuous Integration server.  The way I see it, SQLite is perfect for running the tests locally where speed is of the essence and the CI server can take the hit of running against SQL Server.  So let's get a build script that swaps the NHibernate config. 

To accomplish this I used three boo files:

  • container.boo
    This is my main boo file, it sets up all my classes into Windsor
  • sql_server_facilities.boo
    This is the Sql Server version of the facilities file that configures NHibernate to use Sql Server
  • sql_lite_facilites.boo
    As above, but for SQLite

The container.boo looks something like this:

import System.Web.Mvc from System.Web.Mvc
import Spark.Web.Mvc
import Spark
import Spark.FileSystem
import Invocas.Tools.Binsor.Macros from Invocas.Tools

import file from sql_lite_facilities.boo

LoadFacilities()

for type in AllTypesBased of IController("Invocas.Intranet"):
    	component type.FullName, type:
    		lifestyle Transient
    		log

In the container file, I include the sql_lite_facilities.boo file.  This, as you have not doubt figured out, stores the configuration for the facilities.:

import System
import System.Reflection

import Castle.Facilities.AutomaticTransactionManagement
import Castle.Facilities.FactorySupport from Castle.MicroKernel
import Castle.Facilities.NHibernateIntegration from Castle.Facilities.NHibernateIntegration

def LoadFacilities():
	LoadNHibernate()

def LoadNHibernate():
	facility NHibernateFacility:
		configuration:
			@isWeb = false, @useReflectionOptimizer = false
			factory:
				@id = 'nhibernate.factory'
				settings(keymap, item: 'item'):
					provider = 'NHibernate.Connection.DriverConnectionProvider'
					connection.driver_class = 'NHibernate.Driver.SQLite20Driver'
					dialect = 'NHibernate.Dialect.SQLiteDialect'
					connection.connection_string = 'Data Source=intranet.db;Version=3;New=True'
					cache.use_second_level_cache= 'false'
					show_sql = 'true'
				assemblies = [ Assembly.Load("Invocas.Intranet") ]
	facility TransactionFacility

The sql_server_facilities.boo is essntially the same, but eith the provider, driver, dialect and connection string correctly set:

provider = 'NHibernate.Connection.DriverConnectionProvider'
connection.driver_class = 'NHibernate.Driver.SQLite20Driver'
dialect = 'NHibernate.Dialect.SQLiteDialect'
connection.connection_string = 'Data Source=:memory:;Version=3;New=True'

By default, I usually keep the file to include the facilities.boo file set to SQLite and use NAnt to set the correct file.  Below is what's needed for the NAnt file:

<property name="common.booFileName" value="sql_lite_facilities" overwrite="true" readonly="true" />
<property name="common.defaultString" value="sql_lite_facilities" overwrite="true" readonly="true" />
....

<target name="modifyBoo">
	<property name="booContainerFile" value="${build.dir}/container.boo" />
	<property name="valueToFind" value="${common.defaultString}"/>
	<property name="valueToReplace" value="${common.booFileName}"/>
	<script language="C#">
		<imports>
			<import namespace="System.Text.RegularExpressions"/>
			<import namespace="System.IO"/>
		</imports>
		<code>
			<![CDATA[
			public static void ScriptMain(Project project) {
				StreamReader reader = File.OpenText(project.Properties["booContainerFile"]);
				string file = String.Empty;
				try {
					Regex exp = new Regex(project.Properties["valueToFind"]);
					file = reader.ReadToEnd();
					file = exp.Replace(file, project.Properties["valueToReplace"]);
				} finally {
					reader.Close();
				}
				
				TextWriter tw = new StreamWriter(project.Properties["booContainerFile"]);
				try {
					tw.WriteLine(file);
				} finally {
					tw.Close();
				}
			}
				]]>
		</code>
	</script>
</target>

The modifiyBoo target must be called before running the unit tests  but I'm sure you gathered that.  To supply a new boo file, simply use the following:

nant -D:common.booFileName=sql_server_facilities

And there you have, super fast SQLite integration tests locally, and SQL Server tests on the CI server.  Zoom Zoom

 

kick it on DotNetKicks.com

author: Chris Canal | posted @ Friday, October 10, 2008 11:29 AM | Feedback (3)

Using Spark with ASP.NET MVC and Binsor


I use Binsor for configuring Castle and Spark as my default ViewEngine for ASP.NET MVC.  This is how I register and resolve the ViewEngine

container.boo

component "Spark.Web.Mvc.SparkViewFactory", IViewEngine, SparkViewFactory
component "Spark.FileSystem.FileSystemViewFolder", IViewFolder, FileSystemViewFolder

global.asax

container.Install(BinsorScript.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "container.boo")));
ViewEngines.Engines.Add(container.Resolve<IViewEngine>());

author: Chris Canal | posted @ Wednesday, October 01, 2008 12:59 PM | Feedback (0)

First look at Spark ViewEngine for ASP.NET MVC - Part 1


First thing I want to say is that Spark is a very very nice ViewEngine.  After the resulting unpleasantness of using the WebForms ViewEngine and the horrible flashbacks to my ASP days, I decided that I was going to do my best to avoid using it.  I mean c'mon, its 2008, we've progressed beyond having to create spaghetti code and not have to resort to ASP.NET WebControls

I'm gonna go over a few of the things I really like about Spark that I've came across so far.

Application.spark

Spark uses a file called Applicartion.spark as the default master template.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<use namespace="System"/>
<use namespace="System.Web.Mvc"/>
<use namespace="MvcContrib"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <global Title='"Some Company Intranet"' type='string' />
    <title>${Title}</title>
    <macro name="PageTitle" caption="string">
      <set Title='string.Format("{0} - {1}", Title, caption)'/>
    </macro>
    <link href="~/Static/Css/Site.css" rel="stylesheet" type="text/css" />
    <use content="head" />
    <use content="css" />
</head>
<body>
    <div class="page">
        <div id="header">
            <p id="logo">
                <a href="~/">Home</a>
            </p>
            <navigation />
        </div>
        
        <div id="main">
            <div id="content">
                <use content="view" />
            </div>
            <footer />
        </div>
    </div>
    
    <use content="js" />
</body>
</html>

I don't know about you, but I think that's a joy to look at.

Strange Tag #1 - <macro>

Macro's are awesome, they allow you to create a basic helper method that returns a string.  Yeah, I lifted that straight from the documentation, but there isn't really much else to say.  The  above Macro takes a string and uses it to set the page title.  Using it from a view is as simple as this:

${PageTitle("Certificate of Postage")}

Strange Tag #2 - <use>

This is one of the many ways to include a file and I guess it comparable to WebForms ContentPlaceHolder.  Using the head/css/js sections is as simple as this:

<content name="js">
    <script src="~/Static/JS/jquery.simplemodal.js" type="text/javascript"></script>
    <script src="~/Static/JS/jquery.simplemodal.basic.js" type="text/javascript"></script>
</content>

<content name="css">
    <link href="~/Static/Css/jquery.simplemodal.basic.css" rel="stylesheet" type="text/css" />
</content>

Very sexy!  What about the view?  Well, Spark will automatically include the view into the <use content="view" /> tag.

What I like about this is the amount of code you don't have to write.  I'm lazy, and anything that means less code to write and maintain is a good thing.

Strange Tag #3 - <navigation /> <footer />

If you followed my link to the many way to include a file, you will know this is how you include a partial file.  A partial file, for this of you that didn't look, are basically chunks of reusable code that are defined with a file name like: _footer.spark.  I find this leaves code a lot cleaner.  For example, I'm using a lot of jQuery plugins, and I've seperated each out as a partial file.  To make use of these, I would do something like the following:

<jquery />
<modal />
<autocomplete />
<tooltip />

Each of those partial files will setup the correct JS file and css.  The above example for <use /> is what is present in the modal partial.  The _tooltip.spark file contains:

<content name="js">
    <script src="~/Static/JS/jquery.tooltip.js" type="text/javascript"></script>
</content>

<content name="css">
    <link href="~/Static/Css/jquery.tooltip.css" rel="stylesheet" type="text/css" />
</content>

author: Chris Canal | posted @ Wednesday, October 01, 2008 12:51 PM | Feedback (0)

At last, my very own blog!


After a lot of fantastic discussions at this summers ALT.NET meet up, it became clear that I really need to start blogging.  So after much delay, and screaming at FCKEditor to stop screwing up the HTML, I finally got SubText working the way I wanted it.. And maybe I've spent a little too much free time playing Spore

I really want to share the stuff I'm doing (I've fallen in love with exploiting Castle's AOP functionalities with Boo) and find out if I've headed down the wrong track.  I would say the latter point is more likely, but I'm doing alot of stuff with Castle Windor with Boo/Binsor that I would like to share, and I'm trying out the Spark viewengine for ASP.NET MVC so expect more posts about these soon.

author: Chris Canal | posted @ Wednesday, October 01, 2008 10:34 AM | Feedback (0)