Hey, looky there, this blog thing is still turned on. Hi, my name is Jeremy and I use to blog a lot. I’m gonna try this here blogging thing out again and see what happens.
As those of you who follow me on Twitter know, I’ve been working very furiously over the last couple weeks to jumpstart FubuMVC development and convert the Dovetail codebase over from our homegrown mess. I’ve effectively done a rewrite of the core MVC bits you can look at in the “reboot” branch at: http://fubumvc.googlecode.com/svn/branches/reboot. As of yesterday we’re running our new product at Dovetail on Fubu, I’ve finally caught up on sleep, so now’s the time to finally talk about what we’ve been up to with FubuMVC. There’s self justification verbiage at top, and some technical details down below.
What is It?
FubuMVC is a an open source framework for web development using the Model View Controller pattern (like just about every other web development framework in existence minus WebForms). Fubu is built in C# and depends on the System.Web.Routing subsystem of the base CLR, but has no dependency whatsoever on the ASP.Net MVC framework. FubuMVC is largely based on work and ideas that Chad Myers and I developed when we started at Dovetail last year as described in Our “Opinions” on the ASP.Net MVC blog post and at KaizenConf. Just to boil it down, we weren’t happy with the ASP.Net MVC framework and wanted something that worked a bit differently. In a section below I’ll outline our differences with the MVC and try to explain why I think an entirely new MVC framework is fully justified.
Let me say this loudly and clearly upfront, I see FubuMVC as a “long tail” choice suitable for teams with ALT.NET/code centric aesthetic rather than a full fledged competitor to Microsoft’s MVC. Let me ask you this, what’s your favorite band and/or album? A lot of us casually like the least common denominator Top 40 stuff, but what band would you camp out to go see? I like a lot of kinds of music, but I’m only passionate about the Alt Country scene in Texas – and that’s definitely not a mainstream taste. My point is this, I want Fubu (“for us, by us”) to be a tool that *I* love using rather than a tool that’s widely used, but nobody is passionate about.
Design Philosophy & Goals
-
Composition over Inheritance. SOLID, whatever. I want it pluggable. I want to be able to swap things in and out in the small. I do NOT want Fubu to force goofy base class requirements down my throat. IMHO, frameworks that depend on inheritance are difficult to work with outside of the basic scenarios and tend to couple your code very tightly to the framework. I want Fubu MVC to largely stay out of my way.
-
Use Convention over Configuration as far as it can go. We’re heavily borrowing a page from Fluent NHibernate and StructureMap to allow you to create your own project specific conventions within FubuMVC – but also allow you to use explicit configuration to augment or override the conventions.
-
I love Ruby on Rails and all of its magic. I love how it just seems so declarative. I’m working with C#, and trying to make C# do Ruby things is a first class ticket to hell. We’re endeavoring to use the strengths of C# and wring every single bit of advantage we can out of having strong typing and work with C#’s strengths in the spirit of Rails without doing anything stupid like using C# as a bad Ruby.
-
Testability. Controller actions should be cheap and easy to setup and verify the outcomes.
-
Reduce simple mistakes by tightly tying together controller actions, routes, and url resolution to prevent errors and DRY up the code
-
Use the “One Model In, One Model Out” philosophy for controller actions.
-
Minimize repetitive noise code. Reduce code clutter. Minimize or eliminate the usage of attributes.
-
Make the code easily traceable or “ReSharperable” as I like to say.
-
Enable IoC tools to be fully utilized all the way up and down the runtime pipeline – making it relatively easy to scope services and resources throughout the request. In the Fubu model, every single piece of the runtime pipeline is retrieved with a single service locator call (except things like WebForms controls, but at least you can intercept the construction to do things like transparently calling your Container.BuildUp() against the objects without resorting to base classes). Right now, Jimmy Bogard is basically blogging one nonstop commercial for this line of thought.
-
Enabling IoC tool usage also means being IoC neutral as well as doing nothing that prevents you from utilizing the full power of your IoC’s special registration abilities. Many people out there right now are doing IoC abstractions for their frameworks – and most of them suck (After talking to Rob last night, I think the Caliburn guys got it right). The Common Service Locator is in there for one specific scenario in the Fubu core (and I’m tempted to rip it out), but other than that, it’s Dependency Injection turtles all the way down.
At some point I’m going to have to justify why Fubu is not built on top of the MVC framework. It’s a perfectly fair question. The answer is that I do not believe that the goals above are achievable with the MVC framework. I’ll get specific if anybody wants, but at the end of the day it just comes down to wanting a runtime pipeline that works a different way. I’m happy to steal anything I like from the MVC framework and much of it will be happily usable with Fubu.
Behaviors and the Lifecycle of a Request
The key element to the FubuMVC lifecyle is the IActionBehavior interface that looks like this:
public interface IActionBehavior
{
void Invoke();
}
Pretty freaking cool, huh? One method, no arguments. Remember that we’re assuming in Fubu that everything that the real ActionBehavior objects need is injected in by an IoC container – even other ActionBehavior objects and abstracted reference to the HttpContext runtime. I’m assuming that most requests will be handled by more than one behavior at a time. For convenience, we built a BasicBehavior base class you can start with:
public abstract class BasicBehavior : IActionBehavior
{
// It feels dirty, but I’m using Setter Injection here.
// I don’t remember why I did this. Maybe Chad did it.
public IActionBehavior InsideBehavior { get; set; }
public void Invoke()
{
if (performInvoke() == DoNext.Continue && InsideBehavior != null)
{
InsideBehavior.Invoke();
}
afterInsideBehavior();
}
protected virtual DoNext performInvoke()
{
return DoNext.Continue;
}
protected virtual void afterInsideBehavior()
{
}
}
Using the BasicBehavior allows you to do work before and/or after the inner behavior executes. You can even stop the invocation of the next behavior by just not calling its Invoke() method. Note that you only have to implement the interface, not this particular base class. Right now, we’ve got these Behaviors (some are Dovetail specific and some are junk stubs for testing):
Another key thing to understand about Fubu is that we put a specific RouteHandler on to each Route that knows how to locate and execute the correct ActionBehavior for that specific route. That technical detail is what makes FubuMVC’s design possible as well as making “portable areas” and “slices” and “engines” relatively easy to build.
Here’s the basic sequence of events at the beginning of every request handled through FubuMVC:
The FubuRouteHandler at this point is pretty simple, it’s just this:
public class FubuRouteHandler : IRouteHandler
{
private readonly Guid _behaviorId;
private readonly IBehaviorFactory _factory;
public FubuRouteHandler(IBehaviorFactory factory, Guid behaviorId)
{
_factory = factory;
_behaviorId = behaviorId;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var request = new RequestData(requestContext);
IActionBehavior behavior = GetBehavior(request);
return new FubuHttpHandler(behavior);
}
public void Execute(InMemoryRequestData data)
{
IActionBehavior behavior = GetBehavior(data);
behavior.Invoke();
}
public IActionBehavior GetBehavior(IRequestData request)
{
return _factory.BuildBehavior(request, _behaviorId);
}
public class FubuHttpHandler : IHttpHandler, IRequiresSessionState
{
private readonly IActionBehavior _behavior;
public FubuHttpHandler(IActionBehavior behavior)
{
_behavior = behavior;
}
public void ProcessRequest(HttpContext context)
{
_behavior.Invoke();
}
public bool IsReusable { get { return false; } }
}
}
The “_behaviorId” Guid property of the RouteHandler is assumed to be the uniquely named instance of IActionBehavior in the underlying IoC container. IBehaviorFactory is a small abstraction around an IoC container to allow for some level of bootstrapping around the construction of the behavior before it is executed. There is a simple BehaviorFactory implementation for StructureMap in the codebase, but it wasn’t sufficient for us and I’m not sure what to do about it exactly. For Dovetail, our behavior bootstrapping code looks like this (the real code is much shorter because it uses an extension method to handle the TransactionBoundary goop):
public class TransactionalContainerBehavior : IActionBehavior
{
private readonly IContainer _container;
private readonly IRequestData _request;
private readonly Guid _behaviorId;
// This IActionBehavior “wraps” the real Behavior chain.
// “container” is the root StructureMap Container for the application
// behaviorId is the key to the desired ActionBehavior for this request
// IRequestData is a Fubu specific abstraction around the RouteData and the HttpContext.Request
public TransactionalContainerBehavior(IContainer container, IRequestData request, Guid behaviorId)
{
_container = container;
_request = request;
_behaviorId = behaviorId;
}
public void Invoke()
{
// This uses the new “Nested Container” feature of StructureMap 2.5.4 (which I’ll release someday soon)
// to create a Container that tracks transient objects created by the container
// in this logical transaction and disposes them at the end
// It also helps to make sure that every object in the behavior chain gets
// the same NHibernate ISession
using (var nested = _container.GetNestedContainer())
{
// Dovetail specific stuff that starts an NHibernate session and transaction
using (var boundary = nested.GetInstance<ITransactionBoundary>())
{
// Start an NHibernate transaction
boundary.Start();
// We do some injection based on the current IPrincipal, so it’s important
// for us to attach the Principal before creating the Behavior chain
nested.GetInstance<IAuthenticationService>().SetupAuthenticationContext();
// Now, resolve the named ActionBehavior while ensuring that it has the right
// request data in the container for this request
var behavior = nested.With(_request).GetInstance<IActionBehavior>(_behaviorId.ToString());
behavior.Invoke();
// Commit the transaction
boundary.Commit();
}
}
}
}
I don’t know how you’ll want to do this behavior bootstrapping, but the point is that you *can* customize it by plugging in your own behavior around the original invocation of the IoC container to build the ActionBehavior.
Ok, I’m out of juice for the night. Next time I’ll talk about:
- Executing Controller Actions
- Fubu’s “ModelBinder” approach
- Url Resolution – I think this is important and the MVC framework has totally missed this
- Configuration Model – Conventions First, Explicit DSL when you must, Attributes when there’s no other way…
Laters…..