Web Application Extensibility with FubuMVC (Part 1)

My team is wrapping up a couple deployments to new customers.  Along the way we’ve inevitably had to make quite a few customizations to our application – some that we’ve folded into the application and others that we wanted to keep out of the core.  In the space we play in (largish enterprise system hosted on premise), customization is an absolute must for us to make sales and we’d better be good at it.  At the same time, I’ve seen what happens to a small product shop like us accommodates customizations by forking their system into a myriad of customer specific versions of their code and I’d really like to avoid that scenario.*  What we want to do is to make our application architecture follow the Open/Closed Principle (the “O” in S.O.L.I.D.), meaning that we should be able to add new features and functionality to the system without having to modify existing code. 

One of our reasons for proceeding with FubuMVC all along has been to have a better extensibility story for our web application.  Using some of the newer FubuMVC extensibility points, we’ve been able to:

  • Inject new content into an existing screen
  • Add custom Ajax/Json service endpoints
  • Add all new screens to the system
  • Add new controller actions
  • Add new policies for rendering data into the screen for customer specific types
  • Share common policies, services, and routes between our two web applications (one for users internal to an organization, and another for users external)

In this post I’m going to present the FubuMVC architecture for extensibility.  Tomorrow (or later), I’m going to write a follow up post just about how to extend existing screens with additional content with some new features in FubuMVC.

 

Extensibility with FubuMVC

One of the architectural aspects of FubuMVC that sets it apart from other .Net web development frameworks is its configuration model.  At application start time, a FubuMVC powered website starts by building a configuration model of all the possible actions, handlers, behaviors, and views in the application (which is then used to “bake” the configuration into the IoC container that will be powering your application, but that’s a story for another day).  The configuration model is built up by specifying any combination of conventions, policies, and explicit configuration by using the FubuRegistry class like this one:

    public class SelfServiceFubuRegistry : FubuRegistry
    {
        public SelfServiceFubuRegistry(bool enableDiagnostics)
        {

            Applies.ToThisAssembly()
                .ToAssemblyContainingType<WebCoreMarker>();

            Actions
                .IncludeTypesNamed(x => x.EndsWith("Controller"))
                .ExcludeMethods(x => x.Method.HasAttribute<IgnoreMethodAttribute>());

            Views.TryToAttach(x =>
            {
                x.by_ViewModel_and_Namespace_and_MethodName();
                x.by_ViewModel_and_Namespace();
                x.by_ViewModel();
            });


            this.HtmlConvention<DovetailHtmlConventions>();

            this.StringConversions<DovetailStringifierConventions>();

        }
    }

Forget the details of FubuRegistry for the moment.  All that’s important to this discussion is that altering the FubuRegistry of an application is the way to add (or remove) stuff from a FubuMVC application.  Originally I had thought that we could achieve extensibility and componentization (slices / areas / engines) through merging or importing one FubuRegistry into another, but that’s hit some snags in the internal implementation.  For the moment, I’m proposing this elegant (copout) solution for modularity, the IFubuRegistryExtension:

 

    public interface IFubuRegistryExtension

    {

        void Configure(FubuRegistry registry);

    }

 

 

The IFubuRegistryExtension interface is just hook to apply a little bit of Double Dispatch** to call back to a FubuRegistry to add more stuff into it: 

image

To make it concrete, here’s a simple one I threw together this morning at work:

      public class EmployeeReferenceConvention : IFubuRegistryExtension

    {

        public void Configure(FubuRegistry registry)

        {

            // All this does is tell Fubu’s IDisplayFormatter how

            // to render an EmployeeReference object as a

            // string within the Html conventions.

            registry.StringConversions(x =>

            {

                x.IfIsType<EmployeeReference>()

                    .ConvertBy(reference => “{0} ({1})”.ToFormat(reference.Description, reference.Id));

            });          
        }

    }

 

Granted, there’s a fair amount of C# ceremony littering that class, but it was pretty simple to do.  Now, I suppose you’re wondering how these extension thingies are discovered and when they’re applied in the Fubu bootstrapping process, so let’s just move on to…

 

Finding and Applying Extensions

First I want to back up and explain how you bootstrap a FubuMVC application to better explain how the extensions come into play.  A FubuMVC application is configured by the FubuRegistry class, but you use a Bootstrapper to “bake” the configuration model into the runtime IoC container configuration and routing registration.  Somewhere in your web application (see Getting Started from the FubuGuides for more information) you have some code like this to bootstrap Fubu:

        public static void BootstrapFubu(IContainer container, ICollection<RouteBase> routes)
        {
            // This code would be called from the Application_OnStart() method in your
            // Global.asax file to "bake" the FubuMVC configuration from the
            // FubuRegistry for your application (DovetailFubuRegistry in this case)
            // into both your IoC container for the application and also to add
            // all the routes in the application to the RoutingModule
            new StructureMapBootstrapper(container, new DovetailFubuRegistry(true))
                .Bootstrap(routes);
        }

The basic application setup cycle is:

  1. Setup your IoC container using its own configuration mechanism
  2. Pass that IoC container and the top level FubuRegistry of your application into the FubuBootstrapper object (StructureMapBootstrapper is a subclass of FubuBootstrapper)
  3. Call the Bootstrap(Routes) method to add the FubuMVC specific pieces (controllers, actions, behaviors) to the existing container

StructureMap and most of the other major IoC containers already have powerful facilities for convention based discovery of services and types, so why recreate the wheel by building that into FubuMVC?  Assuming that IFubuRegistryExtension’s are discovered as part of Step #1, in Step #3 the StructureMapBootstrapper can just ask the configured container for all the IFubuRegistryExtension’s and apply them to the top level FubuRegistry as part of the bootstrapping process.  You can see the steps in this code:

        public void Bootstrap(ICollection<RouteBase> routes)

        {

            // Find all of the IFubuRegistryExtension’s and apply

            // them to the top level FubuRegistry *BEFORE*

            // registering the Fubu application parts into

            // your IoC container

            findExtensions().Each(x => x.Configure(_topRegistry));

 

            // “Bake” the fubu configuration model into your

            // IoC container for the application

            BehaviorGraph graph = _topRegistry.BuildGraph();

            graph.EachService(_facility.Register);

            IBehaviorFactory factory = _facility.BuildFactory();

 

            // Register all the Route objects into the routes

            // collection

 

        }

“findExtensions()” is a template method.  The StructureMap flavor of this method is just:

        protected override IEnumerable<IFubuRegistryExtension> findExtensions()

        {

            // Just find all the IFubuRegistryExtension’s from

            // the StructureMap container

            return _smFacility.Container.GetAllInstances<IFubuRegistryExtension>();

        }

So if FubuMVC just applies every extension that’s registered with the IoC container, how does the IoC container itself know about the extensions?  In Dovetail’s case, we already use StructureMap’s assembly scanning to find and add other extensions to our application, so it was relatively simple to add IFubuRegistryExtension to our container.  The following code is our StructureMap Registry for finding application extensions at application startup:

    public class ExtensionRegistry : Registry
    {
        // This is a partial version of the StructureMap Registry we use in our application
        // to find and load customer specific extensions
        public ExtensionRegistry()
        {
            Scan(x =>
            {
                ExtensionProperties.ClearAll();

                // The following code directs StructureMap to search assemblies in the application's
                // binary path where the assembly name contains the word "Extensions"
                // Our naming convention is .DovetailExtensions.dll.
                x.AssembliesFromApplicationBaseDirectory(assem =>
                {
                    return assem.GetName().Name.Contains("Extensions");
                });

                // Custom StructureMap policy we use for extension properties
                x.Convention<ExtensionScanner>();

                // Add all concrete types of IFubuRegistryExtension to the
                // StructureMap container
                x.AddAllTypesOf<IFubuRegistryExtension>();

            });
        }
    }

 

Ok, I’m out of gas for the night, so tomorrow I’ll follow up with another post explaining a new FubuMVC facility for injecting content into existing pages that we’re using to allow customer specific content in some of our main screens.

 

* Several years ago I worked at a software product company that had over 70 customer specific versions of their main codebase.  It’s fair to say that their technical “solution” to customization was cutting hard into their potential profits.  That’s just one of the many times in my career when I’ve seen the bottom line of a company or an organization negatively impacted by poor technical work – and why I’m so constantly irritated by developers and managers who say that technical quality doesn’t matter.

 

 

** Please read that link before putting a pedantic comment saying that’s not what C++ calls “double dispatch.”  By “Double Dispatch,” I mean the pattern of allowing for variance by passing a service argument into a method and letting that method turn around and tell that service what to do.  In this case, IFubuRegistryExtension takes in a FubuRegistry object and “tells” the FubuRegistry what to do.

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 FubuMVC, StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.unwillingcoder.com/ Emil Cardell

    First of all this is one thing I’m started to look at for one of my project. I think you painted a good picture of how the solution might end up looking and I look forward to the second post.

    I’m normally an alt.net fanboy but in this case Microsoft provides us with an alternative solution. MEF, I haven’t personally used it but I’ve seen it being used successfully in other projects for extensibility and its is design for just that. I know it borders into IoC/DI land. If use as a extension abstraction layer on top of the chosen IoC/DI framework it would be easier to take advantage of the functionality and use the IoC/DI of you choice.

    I don’t have any good code example yet. But my five week vacations starts on Monday and hopefully there’ll be some time to look on how to integrate MEF into a MVC solution and a bunch of other stuff related to fubumvc.

  • http://www.codeofrob.com Rob Ashton

    This is very much what I’ve had to do with MS MVC in order to accommodate our different customers (We work with banks and large organisations, as well as a lot of small businesses) – and the ability to inject content, introduce new actions/replace existing actions all from standalone modules without having to modify core is very important.

    All this has had to be achieved by overriding a lot of default MS MVC functionality, it has been a trial and the end solution (controllers are the hardest, effectively looking at the requested action and choosing a controller based on context) isn’t neat and tidy.

    The route you have chosen to go down, facilitating this kind of stuff from the onset is quite sensible, and make me ponder if initially going for MS MVC because it was the “safe” option was the best plan of action.

    Oh well – I’ll try out Fubu in my next project (if I ever manage to abandon this product) – it’s looking good :)