An Update on the FubuMVC Reboot

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):

image

 

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:

 

image

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:

  1. Executing Controller Actions
  2. Fubu’s “ModelBinder” approach
  3. Url Resolution – I think this is important and the MVC framework has totally missed this
  4. Configuration Model – Conventions First, Explicit DSL when you must, Attributes when there’s no other way…

 

 

Laters…..

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Liang

    Thanks, Jeremy! FubuMVC seems very interesting to me. could you shed the light about how easy FubuMVC can be integrated with existing ASP.NET application?

  • Andrew

    @Jeremy

    Please blog about that when you guys get that feature implemented. I definitely want to check that out.

    As a suggestion, it would be nice to integrate Automapper for the model binder if it can be done.

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @Andrew,

    Invoking a controller action, or any service, is just a behavior in the Fubu behavior chain.

    As for Url’s, we’re going to be able to do it both ways. For my team, it’s more than good enough to derive the Url from the controller actions via conventions. For someone else we’re talking to we’ll have a model where you can start from the route/url pattern you want and hang a behavior chain off of that.

  • Andrew

    @Jeremy

    The controller deciding which view to use was more of an ASP.NET MVC gripe and not related to FubuMVC. Commands are a lot like Behaviors (in fact that’s a lot how they are built), but I don’t register routes based on controllers. Instead I have an IActionUrl interface that is used to register the chain of commands with a url that is convention based from the type. The IActionUrl adds the command that processes the main request. This allows me to create strongly typed urls not tied to controllers and actions. I do like the behavior thing you implemented, but I don’t like individual controllers and how they are used to build a url for the route.

    The IActionUrl allowed me to have different areas based off namespace and allowed me to reuse commands. ex: Website.Urls.IndexUrl would be /index and Website.Urls.Products.ProductAUrl would be /products/producta.

    I’ve also added modules. On app startup, it will go through the bin directory and find IModule, instantiate it and call Configure. The module can then add all of the routes it needs. It helps me split up my intranet as it has grown quite large.

    Don’t get me wrong, FubuMVC is great and had most of what I wanted. But in the end, I like the chain of commands without having an action controller involved and instead using a front controller that executes the commands. I guess I just dislike action controllers.

  • http://webgambit.com Karthik Hariharan

    Glad to see this project is still alive and kicking, how many production apps do you have running on it at Dovetail?

    Also, what’s the story regarding ViewEngines? Default to WebformsVE with an option to plug in your own? I think a more opinionated, default VE would be very nice for this project.

  • Suedeuno

    Jeremy, what’s the status of fubu? Last time I checked it was not a RC yet.

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @Andrew,

    Um, dude, Fubu works basically the way that you described. The Controller’s in Fubu do NOT decide which view to use and your Commands sound a lot like Fubu Behaviors.

  • Andrew

    I really like what you all have done with the FubuMVC project. I have learned a lot digging through the code and it has helped me build my own MVC framework.

    I really like how pluggable and configurable it really is. The only thing I don’t really like is the controllers. This lead me to build my own framework taking a lot of the things I like about FubuMVC and discarding the things I don’t like. What I ended up with instead of individual controllers, I used a chain of commands to process a web request using a front controller. This allowed me to get rid of the behaviors and controllers and just have the chain of commands process the entire request. Instead of having the controller control what view gets rendered, I have one of the commands in the chain construct a view model and the view renderer finds what view to render based on the type of the view model. It has been working out great and I am running my company’s website off it.

    Anyway, I just wanted to say thanks. Without FubuMVC it never would have sparked me to write my own MVC framework that is a whole lot easier to manage than ASP.NET MVC. For anyone out there who doesn’t like the way ASP.NET does certain things, check out FubuMVC. It is great.

  • http://chadmyers.lostechies.com Chad Myers

    I can personally vouch for Jeremy that Fubu is not a NIH effort. We sincerely gave ASP.NET MVC a try for over a year. We tried to make it work, but ultimately MVC was simply too inheritance based and trying to do anything beyond basic usage required overriding and replacing large swaths of the framework. The extension points were simply not coarse- or fine-grained enough for us to do what we needed to do.

    The details are long and probably boring and we can go into them, but the point here is not to bash on ASP.NET MVC, it’s to show that ASP.NET MVC proved that there is life beyond WebForms/Page Lifecycle and it’s very good. So whether you like ASP.NET MVC or OpenRasta or Fubu or MonoRail or any of the other frameworks, there are OPTIONS and that’s GOOD.