Gustav Nilsson-Kotte of Dotway Malmö, formerly manning the Göteborg outpost, has now re-emerged onto the scene with a very interesting blog.
Category Archives: .NET
The Dark Side
Back in the nineties when I trained as an apprentice coder at the University of Umeå, I was first exposed to the Dark Side. It was very seductive with an intuitive TCP/IP stack, simple signal management conventions, concise UI:s, lean config files, powerful scripts, nifty daemons and of course the Bible: Advanced Programming in the UNIX Environment by W. Richard Stevens. I marveled at the distributed GUI, broken and deeply insecure though as it was, I admired that multi-user security concerns had been addressed back in the ‘70s already, not as an afterthought in 1989. Then I was brought out in the real world and began appreciating GUI conventions, speed of implementation, solving customer problems and so on and came and joined the Just and Fair in the Microsoft camp and haven’t strayed since. Much.
But
But now and then the urge to complicate things gets stronger and stronger and with members of my immediate family having been lost to the Others for years now, the lure became overwhelming. After years of propaganda from my father I finally decided to install OpenSolaris on a virtual machine. Of course Solaris will not install on Windows Virtual PC Beta. It does not recognize any of the virtual SATA devices and thus cannot install. What to do? Well I gave up of course.
For a week or two until I thought I should make a serious attempt and actually dowloaded Sun’s VirtualBox.
VirtualBox vs Windows Virtual PC Beta
I really wanted to hate it, it not being made by the Just and Fair folks at Redmond. However, it is difficult to argue with 64 bit CPU high performance virtualization with USB, disk and network integration. It sucks the life out of the host machine, but in return both guest and host perform acceptably, lest you allocate too much memory to the guest “computer”, unlike with Windows Virtual PC where you get low performance (but better than Virtual PC 2007) on the handful of platforms it does handle.
Of course, I popped in the ISO in an empty Virtual machine (ironically using the same empty VHD Windows Virtual PC Beta created but couldn’t make available to Solaris) and of course the setup just chugged along event free. A vast improvement over previous UNIXes I installed back in the day. It refused to give me any options but to fill my VHD with the One Solaris partition to bind them all. None of that allocating partitions to /root, /home, /usr/local et c-business that used to be 90% of the fun of trying to set up a Unix style system.
Stereo? Not for me
Of course, once everything is set up you want to do stuff. Back in the day I would have set up FTP and the Apache httpd and created logins for friends and acquaintances and set up the firewall to allow for SSH:ing in to my computer. My computer in this case just being nothing but a figment of my laptop’s imagination, that would be even more pointless than it was back in the day. So: What to do? Weill, of course: Develop in .NET! After all, if I am to achieve global supremacy, I need to be able to code on Solaris as well, at some point.
This is where it all came back to me. Because it is a proper UNIX and not some humble Linux, allegedly, they haven’t gotten mono to run consistently on Solaris. The hours of gunzipping and ./configuring and make believing. compile errors upon compile errors. Downloaded various other package managers to appease the evildoers. Nothing I did could make mono build, despite gigabytes of source code. Ah well… Now I gave up properly.
OpenSUSE
Until I tried OpenSUSE, that is. Similar scenario, clean VM in VirtualBox, popped a physical DVD in my drive and shared it to VirtualBox, the empty VM booted and started the Open SUSE setup. I got to fiddle with my partitions (yay!) but I chose not to. Again, nothing fun happened during install, it just worked. A couple of reboots later I was able to login on my new machine, open the package installer, select everything mono-related and click install. After 20 minutes or se everything was downloaded and installed, and I just went to the Start menu(or what do you guys call it? The non-Start menu?) –> Applications-Development-Integrated Development Environment (monodevelop) and start to code. Very painless. Press play, off you go and you have ASP.NET being hosted on a Linux machine.
Then I noticed that my window was a bit on the smallish side, I would have preferred a higher resolution, like the one I had on the Solaris VM or so, so I go into the yast2 thingy and change display settings to something I consider appropriate and save the settings. I am instructed to restart the window manager, so I reboot the computer (yes I know. but it involved less interaction) and login again. Everything looks fine until after 5 seconds when the display gets garbled and I’m thrown out back to the login screen. I try all kinds of failsafe settings but to no avail. Of course I could manually edit a conf file somewhere to solve the issue, but Google has yet to reaffirm its friendship with me by coming up with a link to a Q&A forum where the question has been answered,
So?
Back to the good side it is, where stuff just works. Of course you can also end up in situations where stuff just doesn’t work as well (oi! CRM4! There’s this new thing, Windows Server 2008. It’s been out for a good two years now!), but resources are more plentiful and as an added bonus: you feel better cursing big successful company than makers of free software.
Cool link
On the topic of Silverlight and Prism2, this link is worth reading.
I can’t be bothered writing a sample on this right now, but I sure wish I could expand the basic 24 hour clock for this one.
Composite Application Guidance for WPF
Because my esteemed colleague Carl Kenne outed his excellent blog on TDD and WPF I felt I should probably put together a little something re: the CAG for WPF and Silverlight. The idea behind the Composite Application Guidance is to enable decoupled applications in WPF and Silverlight, utilizing a shell window, a dependency injection container, separate modules providing views that are displayed in regions either directly in the shell window or nested in regions provided inside the modules. For the conceptually isolated modules to communicate between each other a dedicated messaging system is created. Composite Events, to which separate modules subscribe to and others publish.
So what’s the point?
The point behind the guidance package is that it helps you structure your WPF application in such a way that you design a very loosely coupled system from the beginning. If you don’t have any use for module separation from the beginning, fine, make all your functionality reside in one module, that’s fine. You may want a few services, you may just want one, that’s fine too. The point is: Even with your one module consisting of a single Service managing one Model class and with your single Controller using one PresentationModel class to feed a single View xaml-file, you still have separated all your concerns, making testing a doddle with you being able to pass any mock object in just implementing the appropriate interfaces. You easily just make two different configurations for the DI-container of your choice for test and production environments.
So how do I get started?
Download the Composite Application Guidance package using the link above and pay attention to the requirements they specify right there on the download page. As you can see from the first page, one of the key new features introduced with this version of the CAG for WPF and Silverlight is that you can make Silverlight applications and WPF applications on a shared codebase using a nifty Project Linker. Less code is good. OK, so download the source code, open the shipped solutions and build them.
After that you are ready to create a solution and to get a feel for what this is and how it works.
Open up Visual Studio and get on with it
Create a WPF project called CompanyDashboard.Desktop (if you want to follow this story in detail, otherwise call it whatever you like). Use the Open in Windows Explorer menu option in Visual Studio and create a folder called Library.Desktop. In a new Windows Explorer window, open up your CAG source folder and browse down the Composite.UnityExtensions\Bin\Debug folder and copy everything pdbs, xmls and all into your new Library.Desktop folder. From Visual Studio, Add Reference and Browse to the folder and add everything. Rename (using the Refactor menu option, obviously) the Window1.xaml to Shell.xaml.
Add a class library project called CompanyDashboard.Common to your solution. Rename the Class1.cs to Constants.cs and add a public const string MainRegion containing the string value “MainRegion”.
Make it so that your shell.xaml looks like below:
<Window x:Class="CompanyDashboard.Desktop.Shell"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:cal="http://www.codeplex.com/CompositeWPF"xmlns:common="clr-namespace:CompanyDashboard.Common;assembly=CompanyDashboard.Common"Title="Company Dashboard" Height="600" Width="800"><StackPanel><ItemsControl Name="HeaderRegion"cal:RegionManager.RegionName="{x:Static common:Constants.HeaderRegion}"Height="200" Width="800" /><TabControl Name="MainRegion"cal:RegionManager.RegionName="{x:Static common:Constants.MainRegion}"HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></TabControl></StackPanel></Window>The XAML above defines two regions, a header region that is an items control and a main region which is a tab control. Now the point of these regions will be explained further below, but for now just accept that this is what we are going to do.
Create your Unity bootstrapper
Add a class to your CompanyDashboard.Desktop solution. Call it CompanyDesktopBootstrapper and let it inherit UnityBootstrapper like so:
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Composite.UnityExtensions;
using System.Windows;
namespace CompanyDashboard.Desktop
{class CompanyDashboardBootstrapper :
UnityBootstrapper{protected override DependencyObjectCreateShell(){Shell shell = new Shell();
shell.Show();return shell;
}protected override IModuleCatalogGetModuleCatalog(){ModuleCatalog catalog =new ModuleCatalog();
return catalog;
}}}The UnityBootstrapper class is abstract and needs help creating a Module Catalog and creating the Shell window, this is what we do above. Since the bootstrapper wants to set up all the instances we need to rock’n’roll we shall disable the built-in WPF startup-object management and start the UnityBootstrapper instead. To accomplish this we shall attack the App.xaml and App.xaml.cs files. In the app.xaml-file, remove the StartupUri attribute from the Application element. In the app.xaml.cs, add the following function:
protected overridevoid OnStartup(StartupEventArgs e)
{base.OnStartup(e);
CompanyDashboardBootstrapper bootstrapper= new CompanyDashboardBootstrapper();
bootstrapper.Run();}This way, the bootstrapper is called and on its own creates the Shell window and any dependencies that are necessary or that become necessary with future versions of the software.
At this point you can press play on tape and view your empty CAG application.
Wait a minute… What are we doing here?
The sample will create a composite application bringing together information from a two sources, a “CRM system”, which will be the main source of customer information, and an “Order system” plus an extra module looking up address info on google maps and stuff like that. Whenever a customer is selected, the word gets out (Composite Events) and the other modules scramble to present their own information in context.
Adding some modules
Add a Class Library project to the solution and call it CompanyDashboard.CRMModule. Feel free to use Solution Folders to create some order in your solution explorer. Add another module called CompanyDashboard.SalesModule. What’s going to happen is that the bootstrapper will load the modules from a folder located under the application base folder. To enable this, a few things need to happen, such as post-build events that copy the DLL:s from the module output folders into the Modules folder under CompanyDashboard.Desktop/bin/Debug. Before we get to that though, we need to set up some references.
You will need the following references in a typical Module:
- PresentationCode.dll
- PresentationFramework.dll
- WindowsBase.dll
- Microsoft.Practices.Composite.dll
- Microsoft.Practices.Composite.Presentation.dll
In CompanyDashboard.CRMModule, rename Class1.cs to CRMModule.cs and add a using statement for Microsoft.Practices.Composite.Modularity and let your CRMModule class implement the IModule interface. In order for your module to be dynamically loaded, you need to also add the attribute [Module(ModuleName=”CRMModule”)]. For the Sales Module, which will depend on the CRMModule, an additional attribute will need to be specified. The SalesModule.cs will look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Composite.Modularity;
namespace CompanyDashboard.SalesModule
{[Module(ModuleName = "SalesModule")]
[ModuleDependency("CRMModule")]
public class SalesModule : IModule{public void Initialize(){}}}This will now mean that the CRMModule will be initialized first, and then the SalesModule. In order to add a module to this application, all you need to do is to create a DLL, give it the right attributes and deploy it in the Modules folder and you have your new features accessible. We will demonstrate this with Module no. 3 eventually.
Come back in the next post to see how views are created and filled with data from separate data stores.
More Castle Windsor
In an unexpected move, I decided to go back and demonstrate the automatic injection of dependencies in the old Castle sample app from before. I did so because, well, not doing so I felt kind of missed the entire point of dependency injection.
Code Changes
There are a few initial changes to the source worth mentioning: I renamed the DataSourceFacility assembly to simply DataSource as I wished to avoid the ‘Facility’ word which has a different meaning altogether in the context of Castle Windsor.
As I hinted in the previous blog post I lifted the data access method from the HomeController class to a dedicated data factory consumer class (cunningly name FactoryConsumer) in the DataSource assembly. To maintain an air of civility I also defined a new interface IFactoryConsumer which the FactoryConsumer class would then implement.
using System;
using System.Collections.Generic;
namespace DataSource
{public interface IFactoryConsumer{void LoadData(ref List<DataModel.Entity> lst,NHibernate.ISession session);}}using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataModel;
namespace DataSource
{public class FactoryConsumer : DataSource.IFactoryConsumer{IDataFactory m_fac;public FactoryConsumer(IDataFactory fac) {
m_fac = fac;}#region IFactoryConsumer Membersvoid IFactoryConsumer.LoadData(ref List<Entity> lst, NHibernate.ISession session){lst.AddRange(m_fac.GetData(session));}#endregion}}In the home controller I, perhaps not so wisely, renamed the existing data access function LoadDataFromFactory to demonstrate that it loads data directly from the IDataFactory, and created a new function LoadData that gets its data from a IFactoryConsumer. Then I changed the caller to access both function, getting product data from the Factory Consumer, where Castle secretly and automatically figures out which factory to use, while still loading service data from the factory directly as before.
Config changes
To accomplish the above there had to be some changes to the configuration file. I specified that the Product Data factory has a ‘service’, which is, incidentally IDataFactory. Ahead of both factories I declared my factory consumer. As you can see, Castle cleverly figures out quite a few things on its own, like how to create my Factory Consumer with no more than two empty hands and, incidentally, a component just a line or two below in the web.config file that actually implements IDataFactory which is what it needs to call the constructor of the FactoryConsumer.
<castle><facilities><facility id="loggingfacility"type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging"loggingApi="log4net"configFile="logging.config" /></facilities><components><component id="ProductLoader"type="DataSource.FactoryConsumer, DataSource" /><component id="ProductData"type="DataSource.ProductInfoFactory, DataSource"service="DataSource.IDataFactory, DataSource"/><component id="ServiceData"type="DataSource.ServiceInfoFactory, DataSource" /></components></castle>
Output changes
When you make the above changes to the source, rebuild and ‘play’, you will notice the following changes compared to the other source:
That’s right. Nothing. Exactly the same output is produced.
So, what was the point of all this you ask? Well, as you can see, I could easily move the ‘service’ tag in the config file and have the web page display service info only. We have lifted the dependency control right out of our lap and left it in the hands of the guy/gal who owns the config file. There are so many implications of this; everything from enabling completely changing to different data sources or services on the fly, making partial upgrades, moving from staging to production environments dynamically and so on.
The ASP.NET project
As the returning reader may have noticed I have used the Model-View-Controller framework for ASP.NET again and again in the few posts I have produced so far. This is because unlike the ASP.NET standard framework, the MVC framework allows and simplifies actual programming in lieu of VB3 style component hell. To show proof of my benevolent and magnanimous generosity, I have however decided to let go of my loathing for the standard ASP.NET setup and actually try to make something out of it, utilizing every bit of it just to see if it can be used for anything real.
Orientation
There is a plethora of Server Controls, at least one for every imaginable application known to man. The idea is that when you have a business problem you want to solve, you simply write <asp: in front of a general description of your problem. switch to Design view and edit the properties of your server control.
Example:
I would like to create a wizard that allows me to create a ASP.NET Forms user account… Let’s try it:
Hmm… that would mean… ‘<asp:’ and then, let’s try .. ‘ CreateUserWizard />’ … Switch to design view… Woah!!!
This is just one example, but the amount of server controls out there is limitless and you can watch your ViewState go from 0 – 60MB in seconds with ease, building your website with themeable data bound server controls fully integrated with your web.config.
I have seen people dismiss the MVC framework as it means ‘a move away from Server Controls back to spaghetti code’. I find this unfathomable. Server controls try to abstract away the fact that this the application runs on a web server which is inherently stateless. Through the use of ViewState and other constructs the server controls use a variety of dirty tricks behind the scenes to hide this basic fact from the confused developer. In practice however I have never seen a case where this abstraction has been successful and there have always been places in a web application that have deteriorated into near-ASP Classic monstrosities.
I have always put the blame for this squarely on the shoulders of the ASP.NET Server Control concept. However, I have decided to actually put my money where my mouth is on this one and actually make a serious effort to build something usable out of a bucket of server controls and see if it can actually be done. For real. All the way.
Example
I am going to build an application that uses the following aspects of the ASP.NET basic features:
- ASP.NET Forms Authentication
- Themes
- Profiles
- Wizard
- DataGrid
- GridView
- DetailsView
- DataGrid
- MultiView
- … any other controls that I find irresistibly disturbing
I have a useful scenario which I have been working with, however I will not release the details of this yet, and I will only briefly discuss the actual application. The point of this exercise is whether or not the controls are useful, how difficult they are to manage in a professional way and the amount of ugly code that is necessary to patch things up. I will go through this anxiety ridden journey on my own and spare you most of the details and only report back when I need to vent or when I, maybe, reach points of success. I do this so that I will reach a point where I can disrespect the ASP.NET framework with greater authority. I admit there is a risk I may come out on the other side a changed man, a born-again VB3 fanatic, touting opaque server logic, horribly leaky abstractions and other features as reigning supreme over so-called real programming, we never know.
Castle Windsor and nHibernate in ASP.NET MVC
Years later after this post was originally written, things have improved – see updates.
I will in this post attempt to show how to make a simple DI scheme, access data through the nHibernate O/R-mapper, and present it in an ASP.NET MVC web site. I will present sample code and sample XML along the way and I have also bundled the Visual Studio solution and sample database in an easy-to-download Zip file. Work was greatly simplified by excellent sources, that are listed below
The Premise
The web site in this case is rudimentary to the power of three. It will display one list. On the start page. No clicking involved, just straight to the point.
The list will contain services and items. The point is to illustrate a need to uniformly treat information from two sources. In this case there are two tables in the same database, but conceptually you could have one piece of information in the ERP system and the other one in the CRM system, for instance.
The Domain Classes
The two types of data, Items and Services, are implemented in the POCO classes Item and Service. Both inheriting common properties from the POCO class Entity for the sake of me not having to write as much code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataModel
{public class Entity{public virtual int Id { get; set; }public virtual string Description { get; set; }public virtual string Identifier { get; set; }public virtual double UnitPrice { get; set; }}}using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataModel
{public class Item : Entity{public virtual double Inventory { get; set; }public Item() {
}}}using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataModel
{public class Service : Entity{public virtual double ExpectedDuration { get; set; }public Service() {
}}}As you can tell, the classes exposed to nHibernate require a public default constructor. Properties must be public and virtual.
In SQL Server two tables are created, Item, Service and the common fields are inherited through Copy/Paste.
The Mapping
For this exercise I went with nHibernate 2.0.1. To use that at the same time with Castle Windsor you need to directly specify the NHibernate assembly of the correct version and avoid the 1.2 version shipped with Castle Project. To do this I simply chose the Browse tab under Add Reference… and pointed to the correct assembly. Be careful here to double check your assembly versions, because if there was a blooper reel to this blog you would have seen a clip of me trying to configure a 1.2 nHibernate assembly with 2.0 XML because I had taken the NHibernate reference at face value. <Canned laughter>
For each domain table I made a mapping file to map the assembly, namespace and class with the physical table and the individual fields with their corresponding properties. Very straightforward indeed. The files are named in the following manner: namespace.class.hbm.xml As you can plainly see, the properties inherited from the Entity class are mapped as if they belonged to the Item or Service classes directly. Below: DataModel.Item.hbm.xml
<?xml version="1.0" encoding="utf-8" ?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"namespace="DataModel"assembly="DataModel"><class name="Item" table="Item"><id name="Id" column="Id" type="Int32"><generator class="identity"/></id><property name="Description" column="Description" type="String"/><property name="Identifier" column="Identifier" type="String"/><property name="UnitPrice" column="UnitPrice" type="Double"/><property name="Inventory" column="Inventory" type="Double"/></class><query name="DataModel.Item.GetAll"><![CDATA[
from DataModel.Item]]>
</query></hibernate-mapping>
In order to fetch a list of Items, the XML file contains a very simple query definition that simply requests every record from the table sans filter. As we take a look at the file containing the mapping against the Service table, we see very similar content:
<?xml version="1.0" encoding="utf-8" ?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"namespace="DataModel"assembly="DataModel"><class name="Service" table="Service"><id name="Id" column="Id" type="Int32"><generator class="identity"/></id><property name="Description" column="Description" type="String"/><property name="Identifier" column="Identifier" type="String"/><property name="UnitPrice" column="UnitPrice" type="Double"/><property name="ExpectedDuration" column="ExpectedDuration" type="Double"/></class><query name="DataModel.Service.GetAll"><![CDATA[
from DataModel.Service]]>
</query></hibernate-mapping>
NHibernate requires Session state to be maintained. This is performed through the use of an Titmouse that maintains the connection across an entire IIS request. You could figure this code out on your own or follow my lead and find it online. The HttpModule is registered with the IIS web.config and is thereafter managed automagically by the web server. A caveat I ran into was that you cannot just register modules willy nilly on a Vista machine, You have to command some authority over the applicationHost.config file and specifically allow the server or, rather, individual web sites to add modules on their own.
I have included an NHibernateHelper class with static methods to execute the queries that we defined in the XML files above. The helper class is quite accomplished in that it has built in paging and is very clean and easy to understand. It was written and conceived by a colleague of mine.
At this point we have:
- Created POCO classes that represent our domain information
- Created SQL Server tables that contain the information we wish to display
- Created mapping files to correlate between 1 and 2 and define queries for future use
- Set up Session state in NHibernate through the use of the IHttpModule interface
- Defeated the applicationHost.config issue
- Included helper functions to help us execute the queries defined in 3.
The IoC scenario
To illustrate Inversion of Control I chose a very simple example. The web site wants to display a list of stuff that you can buy, regardless of whether it’s goods or services, whether it’s stored in the database directly or catalogued in an ERP system somewhere. In this extremely simple example, the Controller will itself call the data retrieval function and collect all data in a List<Entity>.
A more feature rich option would have been to create a class for the data retrieval function below and register it as a Castle component and then let Castle create the data retrieval function with the implementations for Services or Items already loaded. I may just do that in the future.
How is all this implemented you ask?
In the web.config file, two Castle.Windsor Components have been defined Both of them return objects of the Entity class. One retrieves Items and the other retrieves Services.
<castle><facilities><facility id="loggingfacility" type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging" loggingApi="log4net" configFile="logging.config" /></facilities><components><component id="ProductData" type="DataSourceFacility.ProductInfoFactory, DataSourceFacility" /><component id="ServiceData" type="DataSourceFacility.ServiceInfoFactory, DataSourceFacility" /></components></castle>In the Home controller in the website, both components are queried and the results go in a List<Entity> that is passed through to the HTML View and there indeed presented to the user.
As is plainly visible, the component names are daringly hard coded in the call to LoadData below.
public ActionResult Index()
{ViewData["Title"] = "Home Page";ViewData["Message"] = "Welcome to ASP.NET MVC!";List<Entity> l = new List<Entity> ();
LoadData(ref l, @"ProductData");LoadData(ref l, @"ServiceData");ViewData["Collection"] = l;
return View();
}WindsorContainer container = new WindsorContainer(new XmlInterpreter());private void LoadData(ref List<Entity> lst, string provider){DataSourceFacility.IDataFactory source = container.Resolve<DataSourceFacility.IDataFactory>(provider);lst.AddRange(source.GetData(NHibernateModule.CurrentSession));}
Where are we now?
- We have defined data access classes in a dedicated assembly.
- These data access classes are registered as components in web.config
- The Castle Windsor dependency injection container thereafter activates the classes by name
- Data is collected from the two sources into one list ready to be displayed to the user.
The GUI
In closing I just want to mention the issues that came from going from Preview 3 to Beta on the ASP.NET MVC framework while writing this post. The HtmlHelper class no longer has an ActionLink so I had to review my Master Page and change to an Ajax.ActionLink.Of course, the RenderPartial function was not available anymore either so the login box had to go.
After all this, 5 minutes after I close Visual Studio for the last time, Scott Guthrie reveals the first release candidate and you’ll be in for a new set of challenges porting this website to the RC1 ASP.NET MVC framework.
The conclusion
The Castle Windsor dependency injection container and NHibernate work just fine together as long as the version issues are kept at bay. NHibernate deals well with inheritance, but the ‘all properties must be virtual’ and ‘there must be a public default constructor’-bit destroys the purity of the O/R concept.
Work in progress
While working on a future blog entry I noticed that IIS7 does not take kindly to you just up and registering your own IHttpModules wherever you like. Do not forget about your %windir%system32inetsrvconfigapplicationHost.config file.