vrijdag 29 augustus 2008

Google maps support for your asp.net site

I used the club starter kit as a base website template for my soccer team.  It has a location feature where you can put the locations of certain important events (where our next game is, where do we meet up front, where are we having drinks afterwards, etc...).  I though it would be nice to add support for Google maps so we can see where we'll have to play and give my teammates directions.  This way I would already resolve the lame excuses that they usually have for being late.

At first I just looked at the Google website.  Where else would you check how to integrate Google maps in your web app?  I found an entire JavaScript api ready for use so I started hacking away.  Now I must admit JavaScript is not my favorite language, I can manage but that's about it.  Since I believe there will be other developers just like me, someone must have written server controls for it.  And yes there is one available Googlemaps.subgurim (Free for non commercial use)

Just drag an drop the map control into your page, size it decently and put code to position the map in the page_load event handler.  The website contains many useful and simple samples so I won't bore you with implementation details.  You can see the map in action on my soccer's team (gilsboys) website (click the location list hyperlink for more locations).  But I have to warn you if you decide to explore more of the site is in Dutch and my team is not famous for the way we play soccer but more for the drinks and parties afterwards.  I guess it's my way of apologizing already for the pictures that are already available :-)

Check with you later !

dinsdag 26 augustus 2008

Template your way into the hearts of your users !

This week we discussed our communication strategy at work.  As already told previously we are writing a security service which involves creating users, adding and removing permissions and so on...  Any of these actions can be performed by various actors (the user himself, an administrator, some batch job, ....) and thus the user must be notified about any change!  Of course requirements are that the business should be able to change the emails, so hard coding them is out of the question (as always :-).

I had a look at a couple of template engines this weekend to solve the problem.  Since I used Stringtemplate before I decided to go along with that one.  The beauty of a template engine is that you can pass in an object graph and let the template figure out what to write and more importantly how to write it.  First task was to make a simple email template that could be sent to the user:

1 group TemplateEmail; 2 3 Email(person, action) ::= << 4 5 \<html\> 6 \<body\> 7 Dear <person.name>, 8 \<br\> 9 \<br\> 10 11 You receive this email because the following action \<b\> "<action.Name>" \</b\> has occurred. 12 \<br\> 13 \<br\> 14 15 This leads to changes in the permissions you have on our applications. 16 \<br\> 17 18 Please logon into our application to validate your permissions. 19 20 \<br\> 21 \<br\> 22 \<br\> 23 Sincerly, 24 Patrick 25 \</html\> 26 \</body\> 27 >>

Done, this template creates a personal email with a header including the user's name and a subject containing the action that has occurred.  Please not that the html syntax is entirely escaped because the < and > are used to refer to parameters and other templates.  According to the documentation you should be able to use $ as well, but in my template these templates were never replaced.  Is it because the dollar is that low?  :-)). 

The two templates that need replacing are <person.name> and <action.name>, the engine will try to find a property name on both of these objects (person and action), which need to be handed to the template engine.  (If it cannot find this, the templates results in an empty string).  Next we need to convert this template into a email with all values filled in, the following code does just about that:

1 var group = new StringTemplateGroup(new StreamReader("templates\\TemplateEmail.st")); 2 var template = group.GetInstanceOf("Email"); 3 4 template .SetAttribute("person", person); 5 template .SetAttribute("action", action); 6 7 var emailBody = query.ToString();

Again, piece of cake, if you put the result of the toString() into your email body you have nicely formatted email.  How did this work?  The first line reads the file from the disk in which the templates are stored.  You get a group of templates as result, you then ask it for your named template.  If you require attributes you can set them here by using the SetAttribute methods.  Finally let the template engine do its work by calling the toString() on it.

All right, seems that basic templating is easy, let's switch to the next gear and divide our template into several little reusable templates.  After all we will want to send different mails based on what action has been performed, the type of user who has performed the action, ....  So let us create some templates for a mail header, mail subject and mail footer:

1 WriteMailHeader(person) ::= << 2 3 \<html\> 4 \<body\> 5 \<div\> 6 Dear <person.name>, 7 \</div\> 8 \<br\> 9 \<br\> 10 >> 11 12 WriteMailAction(action) ::= << 13 14 You receive this email because the following action \<b\> "<action.Name>" \</b\> has occurred. 15 \<br\> 16 \<br\> 17 >> 18 19 WriteEmailFooter() ::= << 20 \<br\> 21 \<br\> 22 \<br\> 23 Sincerly, 24 Patrick 25 \</html\> 26 \</body\> 27 >>

As you can see all multi line templates start with the template name followed by the argument list.  The ::= << sign means the templates starts here and ends with the >> sign.  Our mail template can now be rewritten as follows:

1 group TemplateEmail; 2 3 Email(person, action) ::= << 4 <WriteEmailHeader(person)> 5 <WriteEmailAction(action)> 6 7 This leads to changes in the permissions you have on our applications. 8 \<br\> 9 10 Please logon into our application to validate your permissions. 11 <WriteEmailEnding()> 12 >> 13

The following step is to make our mail more useful by providing extra information.  Lets assume that our Person has a property AuthorizationSet which holds two collections (one for the applications you are authorized to use and one for the functionalities you can execute).  Our template can now read these properties and act upon these values.  So let's add the applications and functionalities you are authorized for in the mail template.

1 WriteApplicationInformation(person) ::= << 2 You have access to the following applications: 3 \<ul\> 4 <person.AuthorizationSet.Applications:{application|<WriteApplicationInformationLine(application)>}; separator="\n"> 5 \</ul\> 6 >> 7 8 WriteApplicationInformationLine(application) ::= << 9 \<li\> <application.Name> of type <application.Type> valid from <application.StartDate> till <application.EndDate> \</li\> 10 >> 11 12 WriteFunctionalityInformation(person) ::= << 13 You have access to the following functionalities: 14 \<ul\> 15 <person.AuthorizationSet.Functionalities:{functionality|<WriteFunctionalityInformationLine(functionality)>}; separator="\n"> 16 \</ul\> 17 >> 18 19 WriteFunctionalityInformationLine(functionality) ::= << 20 \<li\> <functionality.Name> with code <functionality.Code> valid from <functionality.StartDate> till <functionality.EndDate> \</li\> 21 >> 22 23

And you simply call these templates with the following 2 lines in your email template:

<WriteApplicationInformation(person)> <WriteFunctionalityInformation(person)>

Let's go a little bit deeper in the previous templates we've seen, shall we!  We have created 4 sub templates, two for application permissions (WriteApplicationInformation and WriteApplicationInformationLine) and two for functionality permissions (WriteFunctionalityInformation and WriteFunctionalityInformationLine).  The main template calls the line template for each item.  This is achieved by the following syntax: < property : { subtemplate }; separator = "\n">,.  This means that for each property (if it is an array, otherwise it will be called only once) the subtemplate is called, the "\n" character will be used in the template between every iterated call.  The subtemplate has the following pattern { parameter | <template(parameter)>}.  First you name the value for each iterated object, then you specify what other named template to call (or use an inline template).

Finally I would like to add extra information on the items depending on the value we have in the permission sets.  Every permission has a start date and an end date.  These are shown as well, but now when a permission has an end date set to sometime far in the future, it doesn't really add any extra value.  On top of that it looks unprofessional too, so let's us vary the template based on wether we have a permission that is open ended.  First add an extra property in your permission class IsOpenEnded that returns true/false based on the EndDate == DateTime.MaxValue.  Then make an if structure in your template depending on this property.  If we have an open end, we simply make do not display the end date, but show a slightly different text.

1 WriteApplicationInformationLine(application) ::= << 2 \<li\> 3 <application.Name> of type <application.Type> 4 <if(application.IsOpenEnded)> 5 valid from <application.StartDate> till piggs can fly 6 <else> 7 valid from <application.StartDate> till <application.EndDate> 8 <endif> 9 \</li\> 10 >>

So now we have a nice looking email that communicates everything we want with just providing an object tree to our template.  But of course that doesn't suffice.  We want to be able to differentiate templates between the action we have performed, that was one of the reasons why we created the small templates remember.  So if we modify the code where we load our template, we can choose a different template based on the action we had.

1 var group = new StringTemplateGroup(new StreamReader("templates\\TemplateEmail.st")); 2 var template = group.GetInstanceOf("EmaiForl"+action.Type); 3 4 template .SetAttribute("person", person); 5 template .SetAttribute("action", action); 6 7 var emailBody = query.ToString();

This means we need to have templates for the different actionTypes our application has, in our case these two templates would be required:

1 EmailForChangeAuthorization(person, action) ::= << 2 <WriteEmailHeader(person)> 3 <WriteEmailAction(action)> 4 \<br\> 5 This leads to changes in the permissions you have on our applications. 6 \<br\> 7 <WriteApplicationInformation(person)> 8 <WriteFunctionalityInformation(person)> 9 10 <WriteEmailEnding()> 11 >> 12 13 EmailForChangePassword(person, action) ::= << 14 <WriteEmailHeader(person)> 15 <WriteEmailAction(action)> 16 17 We are glad to inform you that your new password is <MakeBold(person.password)>, please 18 logon and change your password to something more personal. 19 20 <WriteEmailEnding()> 21 >>

 

That pretty much it.  If you want to have a look at it yourself, you can download the code or go have a look at the he Stringtemplate website.

zaterdag 2 augustus 2008

Simplify your life... decorate with aspects !

In the company that currently hired me tracing for instance (which is one of the areas you could benefit a lot from using aspects), is done my hand.  Every method (at least most of them)  follows the next format

public bool Method(params string[] inputValues) { Trace("Enter", "MethodName", inputValues); // trace all input parameters ..... bool someValue; ...... Trace("Exit", "MethodName", someValue); // trace parameters leaving the method return someValue }

If you only have to write code once and then never touch it again, maybe this way of developing would be acceptable.  But I rarely (read never) have been on a project where this was true.  Code will be refactorred and not only once.  Keeping the tracing parameters in sync with the constant refactorings is something that is often forgotten.  Compare it with the method documentation you write, if you would generate your ndoc now does it truly reflect your code??  My thoughts exactly, so help is needed, aspect orientation to the rescue.  If you Google aspect orientation (that's right I even saved you the time to do that) you will find many useful resources and implementations, today I will be taking a closer look into PostSharp

PostSharp performs a post compilation step to inject IL code, which means it can 'adapt' your entire code base even private methods,fields...  You can use PostSharp in two ways, the easiest is to download the msi file and install it on your machine.  If you are anything like me you hate installing software on your machine, you might have a look at this blog post from Gael Fraiteur the lead developer for the project.  He explains what happens under the hood and how the post compile step is called in msbuild.   

If now you add the required assemblies (PostSharp.public and optionally PostSharp.Laos) to your project, the post compilation step will automatically gets called from msbuild.  It will search your assembly for all required tasks to process and then updates the IL code.

First on my list is to improve my above tracing problem.  This is easily solved by overriding the OnMethodBoundaryAspect (provided as one of the higher level aspects of the PostSharp.Laos library) , this provides the following methods:

  • OnEntry : called when entering the method
  • OnExit : always called when exiting a method
  • OnException: called when the method resulted in an exception
  • OnSuccess: called when the method executed successfully

and leads to the following code:

public override void OnEntry(MethodExecutionEventArgs eventArgs) { Trace.WriteLine( string.Format("Enter {0}.{1}.", typename, methodname), this.category); } public override void OnExit(MethodExecutionEventArgs eventArgs) { Trace.WriteLine( string.Format("Leaving {0}.{1} with {2}", typename, methodname, eventArgs.ReturnValue), this.category); } public override void OnException(MethodExecutionEventArgs eventArgs) { Trace.WriteLine( string.Format("Exception {0}.{1}.", eventArgs.Exception.Message, eventArgs.Exception.StackTrace), this.category); } public override void OnSuccess(MethodExecutionEventArgs eventArgs) { // Usually you don't need this }

Another way to achieve this is to override the OnMethodInvocation.  This provides you with different methods to work with but you have the same functionality at your disposal.  The major difference is that this method does not modify your original method (as would happen with the above sample), but intercepts the call en invokes your OnInvocation method).  Check reflector to see the differences here!!

public override void OnInvocation(MethodInvocationEventArgs eventArgs) { // Perform tracing here Trace.WriteLine( string.Format("Enter {0}.{1}.", typename, methodname), this.category); try { base.OnInvocation(eventArgs); // Invoke your method here! } catch(Exception ex) { Trace.WriteLine( string.Format("Exception {0}.{1}.", ex.Message, ex.StackTrace), this.category); } finally { Trace.WriteLine( string.Format("Leaving {0}.{1} with {2}", typename, methodname, eventArgs.ReturnValue), this.category); } }

So far so good.  Applying these attributes is as simple as using other attributes in .NET, just decorate your method/class with them.  If off course you wish to perform tracing on an entire assembly or part of it, You will be adding a lot of these attributes, so a better way has been provided:  The following configuration intercepts all method calls from the Tracing.Model, Tracing.Repository and Tracing.Service namespace.    You could tweak this further.

[assembly: Trace(AttributeTargetTypes = "Tracing.Model.*")] [assembly: Trace(AttributeTargetTypes = "Tracing.Repository.*")] [assembly: Trace(AttributeTargetTypes = "Tracing.Service.*")]

You could specify on which the aspects (or attributes) can be applied by specifying the AttributeUsage and MulticastAttributeUsage, see the official documentation about that here (UserGuide -> Using PostSharp LAOS -> Wildcards and multicasting).

Secondly my I wanted to simplify my validation code.  One solution is to decorate my fields with the specification they have to obey.  For instance

  • A String field should contains maximally 16 characters
  • A Number must be between 1-100 (see the following code sample)
  • A Date must be in the future
[Serializable] public class RangeSpecification : OnFieldAccessAspect { public Int32 _minimum = 0; public Int32 _maximum = 100; public RangeSpecification(Int32 minimum, Int32 maximum) { _minimum = minimum; _maximum = maximum; } public override bool CompileTimeValidate(System.Reflection.FieldInfo field) { Console.WriteLine("RangeSpecification"); // this comes in the output window when compiling if (field.FieldType.Name != typeof(Int32).Name) { // "Why would you want to use this specification on a non number field?" return false; } return true; } public override void OnSetValue(FieldAccessEventArgs eventArgs) { Int32 exposedValue = Int32.Parse(eventArgs.ExposedFieldValue.ToString()); if (exposedValue < _minimum || exposedValue > _maximum) { // keep the old value when an invalid value was passed in eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue; } base.OnSetValue(eventArgs); } }

So far the first exploration of PostSharp, I  realize this was only the top of the possibilities but I hope everybody can see how much code can be saved and might not clutter your production code by applying these aspects correctly in your code.

See you next time.

dinsdag 29 juli 2008

Ignore files in your subversion repository

After reading the pragmatic programmer in my holiday I decided it was time to put theory into practice.  Whenever I perform an check-in in my subversion repository I usually deleted my bin and obj folders manually to make sure they didn't got checked-in.  Of course tortoiseSVN and subversion provides ways to automatically exclude them when you check-in.

So in order to 'avoid my repetitive tasks' and win those crucial couple of seconds on every commit (have you ever count how much this could add-up to on a year basis?) I browsed the tortoise site and found the following documentation:

http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/ch05s11.html#tsvn-DUG-ignore-glob

Here are the settings that I've applied on my projects : */bin */obj */_ReSharper* *.suo *.user *.resharper

image

Right where can I win some more time, maybe I can achieve my 4 hour work week!

maandag 7 juli 2008

Book Reviews: the holiday books

Just returned from my holiday where I had the time to catch up on my reading. I choose a couple of books from my shelf and went on my way to France.

The pragmatic programmer

This book is all about becoming a better and more productive developer.  The book contains tips and tricks to let you focus on the job at hand instead of distracting you from it.  It reads like a novel so it is perfect as holiday lecture (buy this book if you are leaving in the next couple of weeks).

I simply cannot believe that this book is written 10 years ago.  It still is burning accurate and besides the referral to the "upcoming language of java" and "in the future there will be refactorings tools available" you simply cannot tell it is this 'old'. 

I really liked the way the book compared the continuously studying everyone has to do with investing in your stock portfolio, it's all about diversification! 

As a nice extra for one of my colleagues  the books describes nicely the pussy way of development.  :-)

Agile principles, patterns and practices in C#

A must read book for everyone doing agile development in C#.  It starts of with a section explaining what agile development is all about and what are its cornerstones.  The section ends with an hilarious 'role play story on pair programming'. 

The second section is more interesting where all the basic principles of software development pas the revue.  If you don't know what the Single Responsibility  principle, what the open/closed principle has to do when there are no doors involved, when LSP, DIP and ISP are just meaningless acronyms then this book is for you.  The section finishes of with an overview of UML and how to express design in various diagrams.

Section three and four covers the patterns part of the book and it does this by following a case study about a payroll system.  If you have heard of NDepend you will probably be familiar with the principles (REP, CRP, ....) Robert explains when packaging our case study.

I would advice this book to everyone who wants to start with agile development!

I then started to read Implementation patterns from Kent Beck, but the didn't finish it yet.  The swimming pool looked more appealing...

donderdag 12 juni 2008

The pain of development in Vista

I recently bought a new laptop with Windows Vista already pre-installed.  Until that time my development machine was running on XP, but now I had the joy of meeting the latest invention (??) of Microsoft called User Access Control (UAC)!  I am still figuring out if this is supposed to be feature or a bug that the programmers could not fix. 

My problem is the following: Whenever I open a perfectly working solution on my new machine I got an annoying "System.Runtime.InteropServices.COMException" exception hitting me.  I quickly realized it happened only when accessing a Web or Service through IIS.  Whenever you want to access local IIS Website your Visual Studio needs to fired up in the context of an administrator, by default Vista starts applications in a limited-privilege user account.  The solution to this problems is relatively easy, always start your studio in administrator mode.  I created a new shortcut that runs in administrator mode and associated my sln-files to use this shortcut by default.  If you right-click on a shortcut, in the advanced tab you can select the 'run in administrator' option.

Problem solved if you can live with a UAC popup every time you open Visual Studio.  If you anything like me you want to avoid this popup as well :-), my first thought was simply disable the UAC Altogether, but then other features might stop working because windows believes your system is not trustworthy.  Since I usually select proceed in those useless popups I decided to accept this silently without prompting, you can read here how this can be achieved.  I took the liberty of giving you summary here:

Click Start and Control Panel. Switch to Classic View (if you haven't already) and click on the Administration Tools icon. In the list that opens click on Local Security Policy, and in the next window, Local Policies (a tiny bit redundant, but all UIs can't be perfect -- If UAC is running you'll get a UAC pop-up somewhere in here). In the Local Policies list click Security Options, and scroll down to "User Account Control: Behavior" (the full title of the policy is "User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode" but the window barely opens that far). Double-click the title and in the dialog box change its setting from "Prompt for Consent" to "Elevate without prompting." Click OK and the urge to tear your hair and scream at your PC will be greatly diminished in the future.

I hope this post will save you time and headache, till next time.

donderdag 5 juni 2008

NHibernate in Action: Book Review

I finished this 'beta' book today, it took me a while because I have the bad habit of reading multiple books at the same time.  For an NHibernate virgin like myself the book was a very good introduction. It covers everything you need to know to get started with release 1.2.1 version, although nothing is inserted (yet ?? ) for the upcoming 2.0 release.  I hope the final version will include some chapters covering the new features, especially the event/listener model seems to be interesting.  If it doesn't the book might already be outdated upon its release in August.

The thing I was missing was more in depth information about extending the functionality of NHibernate.  We had an issue for instance with the interceptors which you can read all about here, but the book did not provide a lot of information about. 

My overall conclusion is positive because it was a nice intro, but if you already have some experience with NHibernate the book  might be too 'easy' for you.

woensdag 4 juni 2008

Big twitter is watching you.... or me

I finally got the 'stalking decease' as well and subscribed to twitter.  You can follow me here.

zaterdag 31 mei 2008

DDAD: Domain Driven "Allors" Design

As explained in my previous post I am going to build an application to demonstrate what Allors is and how to use it.  I will hopefully have to time to build the same application later on using NHibernate to show both frameworks differences. 

The application I'll be building will take care of the invoicing for a contractor.  It is built using the YAGNI principle (this basically states if you think you need to add complexity to your domain model, you should defer it until the moment you actually need it.  Probably you ain't gonna).  Lets discuss the domain shall we.  The most important class obviously is the Contract signed between a Customer and a contractors's Company.  Both the customer and the company are subclasses of the corporation class, which gives them some common attributes (like Name, Address, Account, .... ).  On the Contract you can then register the hours you worked for them and eventually generate an Invoice for a specific period. 

All relations and classes are shown in the following model:

Version1 
I deliberately kept everything as simple as possible so I can make future improvements to demonstrate what this means in terms of database upgrades, refactorings possibilities, etc....  If you want to follow everything that is explained here below, you can download the complete solution here or built everything yourself of course.

Building the domain (Allors)

To start building an Allors domain you first need to download the binaries and the Allors Repository.  You can either checkout the sources from the subversion (https://www.allors.com/svn/platform) or you can download the Quick Start file I've put together. The zip contains two directories & a command file

  • lib: Directory containing the Allors binaries and the Allors Repository, you should extract these in your solution folder.
  • Allors: Directory for the Allors Domain Files, you should extract these in your domain project folder.
  • AllorsRepository.cmd: file that will startup the AllorsRepository Tool for you domain, this should be extracted in your solution folder.

Step 1: Setting up the solution hierarchy

The solution structure I have applied consists of 4 projects.

  • Diagrams: containing the diagrams of my domain.  This project will contain only generated code with getters/setter that reflect your domain.  You can then use these to generate your class diagrams.
  • Domain: the heart and soul of our accounting application, you should refer to the Allors.Framework.dll here.
  • Population: Helper classes to build your domain objects and setup an initial population for unit/integration testing.
  • Unittests: proving our design and domain is correct and well thought.

image 

Step 2: Creating the Allorized domain

The Allors folder from the zip file needs to be copied into your domain folder.  This folder will contain the meta information (allors.repository) about your domain classes, which is built up using the AllorsRepository-Application (included in the zip file).  if you modify the command file that was included in the zip file so that the parameter passed in to start up the "Allors.Repository.Application.exe" refers to the allors.repository in your domain folder, this file will now fire up the AllorsRepository-Application for your domain.  You should see the following (if you are building from scratch, otherwise your domain will be completely filled in).

image

This screen has three main parts. 

  • The top left has a tree containing all your types and relations in your domain
  • The top right is the property window of the selected treeNode
  • The bottom gives information about errors in your domain

All actions are available by rightclicking the treeNode and then select the action in the context menu or change the node's corresponding properties.  If you need to know how things are getting done, you can checkout the getting started page of the Allors website.  On the bottom you can see that the repository already has one error.  It has no name, so you need to select the domain node and fill in the name in the properties window.

Step 3: Namespaces & Types

Our solution will have two namespaces to start with.  You can see here how you can add namespaces in the repository.  The types we are building are shown in the diagram above, you can easily add them yourself in the allors repository.  It is written out here how you can achieve that.  All objects belong to the Accounting namespace, only the DatePeriod type is more generic and is placed into its own General namespaces

Step 4: Attributes & Relations

We now have domain containing single classes without any attributes or relationships between them.  You cannot call this a domain of course so the logical next step to give our objects data and connect them through the use of relations.  As always you can checkout here how everything can be done.  The above diagram gives you all the information you need to create all the relations.

Step 5: Adding Domain Logic

The Allors domain has been built (you can download the zip file here).  The next step is to generate (right click the domain and select generate) our allors classes, these will be our base classes for our domain objects.  You don't have to remember to inherit any classes or interfaces because we generate a partial class for you as well.  Include these files (located inside the Allors/output/folder by default, but this can be tweaked of course) in your domain project and you can start using them.  Every object you instantiate now is inside a Session, the creation is performed through the Session as you can see in the next code block:

1 public static Account Create(AllorsSession session, 2 string bank, 3 string number) 4 { 5 Check.Argument(number, "number").IsNotNullAndNotEmptyAndNotWhiteSpace(); 6 Check.Argument(bank, "bank").IsNotNullAndNotEmptyAndNotWhiteSpace(); 7 8 var account = session.Create<Account>(); 9 account.Bank = bank; 10 account.Number = number; 11 12 return account; 13 }

Adding the actual business logic is done simply by adding the methods into your class (as you normally would)

1 public TimeRegistration RegisterWorkingTime(DateTime date, Double hours) 2 { 3 return TimeRegistration.Create(AllorsSession, date, this, hours); 4 } 5 6 public Invoice BuildInvoice(DatePeriod period, 7 String reference, 8 DateTime invoiceDate, 9 IInvoiceCalculator invoiceCalculator) 10 { 11 VerifyThatInvoiceReferenceIsUnique(reference); 12 13 var timeRegistrations = new TimeRegistrationFinder(AllorsSession) 14 .GetNotInvoicedTimeRegistrationsFor(this,period); 15 if (timeRegistrations.Length == 0) 16 { 17 throw new ArgumentException("Invoice must contain TimeRegistrations"); 18 } 19 20 var invoice = Invoice.Create(AllorsSession, reference, invoiceDate); 21 AddInvoice(invoice); 22 23 foreach (var timeRegistration in timeRegistrations) 24 { 25 invoice.InvoiceTimeRegistration(timeRegistration, invoiceCalculator); 26 } 27 28 return invoice; 29 }

Step 6: Unit Testing

Since all objects are Session aware we need to have a Session in our UnitTests.  For performance reasons we will not use a real database, but rather work completely in memory.  The following code creates an in-memory session for our domain. 

var population = new Allors.Adapters.Memory.AllorsConnectedMemoryPopulation(new AccountingDomainConfiguration()); population.Init(); _session = population.CreateSession();

You can then create your objects with this sessions and perform the regular tests you would normally write.

1 [TestFixture] 2 public class When_creating_an_account : AllorsBaseTest 3 { 4 private AccountBuilder _builder; 5 6 [Test] 7 [ExpectedException(typeof(ArgumentNullException))] 8 public void Then_expect_an_error_when_the_number_is_null() 9 { 10 _builder = new AccountBuilder(Session); 11 _builder.WithBank(null).Build(); 12 } 13 }

The final step is to make our domain persistent.

For this I created a new project (IntegrationTests).  You do not need to supply mapping files because Allors will make and initialize the database scheme for you based on the meta information you supplied.  This is achieved by simply instantiating the correct population and Session, here we will use the SQL Server Express Edition.  For unittesting we created the population in code (and for memory), you could as well set everything in the config file:

  • First of all you need to declare the allors section in the config
  • You need to configure your populations(or multiple of them) + connectionstrings
  • Finally you need to create the population from based on the name in the config
1 <configSections> 2 <section name="allors" type="Allors.AllorsConfigurationSection, Allors.Framework"/> 3 </configSections> 4 5 <allors> 6 <populations> 7 <add name="AccountingPopulation" 8 type="Allors.Adapters.SqlClient.AllorsSqlClientPopulation, Allors.Adapters.SqlClient" 9 domainConfiguration="AllorsDomains.AccountingDomainConfiguration, Pdbc.Accounting.Domain" 10 connectionStringName="accounting"> 11 </add> 12 </populations> 13 </allors> 14 15 <connectionStrings> 16 <add name="accounting" connectionString="Data Source=Pdbc-Laptop\SqlExpress;Initial Catalog=accounting;Integrated Security=True"/> 17 </connectionStrings>

Then in code we can retrieve the population and instantiate the session.  The Init method by the way drops the database and recreates it which makes sure that our integration tests always have the latest version of the database scheme available.

1 var population = AllorsConfiguration.GetPopulation("AccountingPopulation"); 2 population.Init(); 3 _session = population.CreateSession();

Check the complete sample along with the unittests for a complete overview.  As you notice, the major difference with traditional POCO domain objects is that we need to inherit from an Allors Class.  This Class encapsulates the access to a strategy object which contains all your class attributes and object relations.  This way we can keep all objects managed by Allors which has a lot of benefits (lazy loading, managed relations, ...) , but that is for a next post. 

Let me know what you think about it and have a spin with the sample.