MonoRail+++

September 13th, 2010

It’s been more than six years since the first prototype of MonoRail appeared on Castle’s SVN repository. By then our website was hosted in a linux machine, the web server was Webrick, running a beta version of Rails, and had to be restarted once per day (at least) due to memory leaks. WebForms was the winner in the .net space, Struts the winner in the java space (unbelievable!), cocoon committers were toying with the idea of implementing continuations, probably inspired by Seaside.

Back then I was fresh back from London (now you know where Windsor’s name came from), jobless, and entertaining with the idea of setting up a small software shop with Carlos and Rodrigo. One of the first challenges was to pick the technology to invest and potentially create a small product. Rodrigo was obviously biased towards .net with boo. I was playing with Ruby/Nitro. Carlos was inclined towards webforms with c#. We decided to pick one each, build somewhat similar and compare/contrast. AFAIK Rodrigo picked up some Java tech, Carlos chose boo, and I went with Rails.

I fell in love with Rails and became a strong advocate. However, as “our product” grew in complexity, Rails – by then – didn’t catch up. Big refactorings were hard due to the dynamic nature of Ruby, lack of unicode was a red flag for i18n, leaks and bad performance (couldn’t get fastcgi to work on apache!). Also, the ecosystem, the libraries for dynamic image generation were badly maintained, if ever…

That’s when I decided to combine the philosophy of Rails with the solid foundation of .net. By then it was called Castle on Rails.

Things have changed since then. MonoRail seems to have greatly inspired Microsoft’s take on Model-View-Controller for the web. Mongrel, Merb and REST ascendance, a ton of great ideas continue to appear in the Ruby community. Same in a slower pace for other communities.

 

Web apps then and now

While there was dynamicity in web apps six years ago, my perception is that today they have an aspect of multi-faceted apps. Html is just one of the multiple supported outputs of resource-based web sites. They expose services that can be used by your mother or another service. Twitter and Facebook are the greatest examples.

Bringing that to our work and especially the MS platform is somewhat puzzling. Who wants to maintain two entry points? Why a web app and a WCF Soap/Rest interface? Why it’s so unnatural to deal with syndication on web apps?

 

The reuse dilemma

Reuse has always been an OOP challenge. Many programming practices support designs that yield subsystems (size/complexity can vary) that can be reused. Not too many programmers embrace those programming practices, though.

As the complexity of web applications grow we see subteams owing subsystem with the same web application. Their technological choices are restricted by the common denominator. There ought to be a solution for this.

 

MonoRail 3.0

This and other interesting discussions are taking place with the Castle team. I try hard to influence them over the big picture – it’s easy to get distract by what seems to be cool and interesting but deliver no value. In the last two months I drafted and propose a new enhanced design that should deal with the common challenges of web apps of today – and hopefully of tomorrow! Today I completed a working prototype.

 

Minimal core

The core is based on MicroKernel pattern. It’s a truly example of Open-Closed principle. It works by orchestrating a minimal set of extension points. Those are called primitives as they represent core abstract concepts.

The core is split into three architecture layers:

Layer 1: ASP.NET core augmentation

The layer 1 replaces the HttpHandler and HttpModule in ASP.NET with composable equivalents. You can then implement a new “handler” that has “dependencies”, and be sure that those will be satisfied.

Layer 2: Orchestrator

Layer 2 defines a minimal set of primitives and pipeline execution process. It establishes the minimal policy (behavior) but does not make assumptions over the implementation – remember the Dependency Inversion Principle?

Layer 3: Model-View-Controller

Finally, the third layer is an implementation of layer 2 that exposes the common behavior of Model-View-Controller we all know and love. It also exposes extension points, such as an execution sink for controller execution.

 

Side-by-side extensions

Windsor turned out to be successful because it delivered a rich extensibility mechanism and a minimal but useful combination of default behaviors. MonoRail 3 is built with the same principles. In fact, its Model-View-Controller capabilities are just one implementation over a set of “primitive” contracts. Behavior can be modified, added or removed by using a small set of extension points.

The design supports side-by-side extensions, which means that extensions do not replace one-another, but instead are always additive. For example, I can have a WindsorIntegration and AutofacIntegration running at the same time. I can add to the mix Razor View Engine and IronRuby support. Not a single line of configuration code or xml.

 

Composition by default, even in your code

Yes, you can turn off or replace it, but by default your app will have an IoC Container (well, MEF) composing your controllers. The composition is not limited to your types, in fact, you can express dependencies over framework components and request level objects.

Maximized simplicity

The following is a valid controller:

public class ProductsController
{
    public ActionResult Index()
    {
        var products = // fetch list
        return new ViewResult() { Model = products };
    }

    [RespondTo(ContentType.Html|ContentType.Xml|ContentType.JSon)]
    public Product View(int id)
    {
        var product = // fetch by id
        
        if (product == null)
            throw new HttpException(404, "product not found");
            
        return product;
    }
    
    public Product New()
    {
        return new Product();
    }

    public ActionResult Create(Product product)
    {
        // pretend to save
        var product = new Product();
        
        return RespondTo( format => 
            format.Model(product).
              Html().
              Xml( new ViewResult("create.xml") ).
              Json()
        );
    }
    
}

If access to some response, request (or similar) objects are necessary, no worry, you have two options: use the Controller base class or specify the dependencies in your constructor.

Powered by MEF

One of my goals is to demonstrate how MEF can be used to enhance your frameworks, instead of just your applications. By using MEF I could easily skip any “registration” step usually required by typical IoC Containers. I can also discover extensions easily in runtime without extra code.


Where/When?

I’m planning to release a first drop later this week. Note I’m kinda extra busy as I’m getting married next weekend, but watch out for a preview drop.

12 Responses to “MonoRail+++”

Ken Egozi Says:

Dropping two bombs in a single blog post …

Mazal tov for the wedding.

Looking forward for your MR3 bits

hammett Says:

Three actually: there’s a baby under way ;-)

Ayende Rahien Says:

Wow,
Seriously, congrats on all three!

Danyal Says:

Congrats x3.

I love it when a plan comes together.

Darius Damalakas Says:

Congrats!

Keep posted on MR3!

Torkel Says:

Great news! (all 3 of them).

Sergio Pereira Says:

Wow, a wedding and, really, two babies in “the oven”. Congrats+++ :)

Rodrigo B. de Oliveira Says:

Congratulations! :)

Nick Parker Says:

Hammett – congrats!

Glenn Block Says:

Congratulations on all the babies!

Dru Says:

Congrats Hammett, that is awesome!

Josh Says:

Awesome, sounds like a shotgun release…? err wedding.. congrats!

Leave a Reply