How I link to my fubuMVC actions

I’m in the process of migrating an existing production web project to use fubuMVC and all the power that it provides and I’m currently writing a series on my experiences with it – this is the third in that series.

I’ve already begun to migrate my static content pages and now need to link to them in my spark views.
Obviously hard coding the urls defeats the whole point of routes and actions being malleable so I want a way to look back at  my actions and have fubuMVC find the appropriate url.

This is provided by fubuMVC in the form of Url Resolution and my spark views are already integrated with an overloaded LinkTo() method that allows me to refer back to my actions or input models.

So here’s the first stab at the navigation in my site using this method:

    <div id="menu">
      <ul id="headerLinks">
        <li>${this.LinkTo<HomeController>(c => c.FrontPage()).Text("home")}</li>
        <li>${this.LinkTo<NewsController>(c => c.Root()).Text("news")}</li>
        <li>${this.LinkTo<AboutController>(c => c.Root()).Text("about")}</li>
        <li>${this.LinkTo<LoginController>(c => c.Root()).Text("login")}</li>
      </ul>
    </div>

This works a treat, but I'm not so sure about breaking out into code all the time. Is there anyway I can embrace the tag nature of the spark view engine and have an element that would do this for me?

Spark bindings allow you to do just that - you can add custom elements that wrap your code by simply providing a bindings.xml file in your shared folder allowing you to hook them into the spark view engine.
Here's my bindings.xml file:

<?xml version="1.0"?>
<bindings>
  <element name="linkTo">this.LinkTo&lt;@action&gt;(c => c.@method).Text("child::*")</element>
</bindings>

I’m declaring a new “linkTo” element and chopping up the previous code with parameters I expect on that element.
This allows me to now have a better flowing syntax for my links:

    <div id="menu">
      <ul id="headerLinks">
        <li><linkTo action="HomeController" method="FrontPage()">home</linkTo></li>
        <li><linkTo action="NewsController" method="Root()">news</linkTo></li>
        <li><linkTo action="AboutController" method="Root()">about</linkTo></li>
        <li><linkTo action="LoginController" method="Root()">login</linkTo></li>
      </ul>
    </div>

Posted at at 6:42 AM on Tuesday, August 30, 2011 by Posted by Justin Davies | 0 comments Links to this post   | Filed under: ,

How I customised my fubuMVC routes with a url policy

I’m currently re-writing my existing application so that it uses fubuMVC and I shared my experiences in how easy it was to get started with fubuMVC – this is the second post in a series on fubuMVC in action.

I’m migrating the static pages for my website – the home, news, about pages – and I now have an opportunity to change a few things around.
One of the things I was doing when using ASP.NET MVC was to have a HomeController that had actions for these pages:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            return View();
        }

        public ActionResult News()
        {
            return View();
        }
    }

This resulted in urls of “home/index”, “home/about”, “home/news”.

So the first thing I want to change is to ditch the “home” part of the url – for the first one, I’ve already declared my HomeController.FrontPage() method as the root url for my website in my FubuRegistry, so that is taken care of.
I now have the other two to tackle so I want these to be simply “/news” and “/about”.

Here comes the fubu power because I am now free to think of any convention I like to make this happen – once I’ve come up with one, I can declare that convention in my own FubuRegistry.

I decide that for my project, any action that has a method called “Root” will have a custom url that ignores the method and just uses the prefix name of the controller.

To enable this, I’m going to define a custom IUrlPolicy (to read more about policies, see Josh Arnold’s post on compositional patterns - policies).

The IUrlPolicy interface contract is:

  public interface IUrlPolicy
  {
    bool Matches(ActionCall call, IConfigurationObserver log);

    IRouteDefinition Build(ActionCall call);
  }

Being always test driven, I define my tests for the matching process first using Machine.Specifications :

    [Subject(typeof(EnsureControllersCanHaveARootUrlPolicy))]
    public class when_matching_against_a_non_root_action_call
    {
        Establish context = () =>
        {
            _actionCall = ActionCall.For<HomeController>(h => h.FrontPage());
            _log = new Mock<IConfigurationObserver>();
            _matches = true;

            _urlPolicy = new EnsureControllersCanHaveARootUrlPolicy();
        };

        Because of = () => _matches = _urlPolicy.Matches(_actionCall, _log.Object);

        It should_not_match = () => _matches.ShouldBeFalse();

        private static EnsureControllersCanHaveARootUrlPolicy _urlPolicy;
        private static bool _matches;
        private static ActionCall _actionCall;
        private static Mock<IConfigurationObserver> _log;
    }

    [Subject(typeof(EnsureControllersCanHaveARootUrlPolicy))]
    public class when_matching_against_a_root_action_call
    {
        Establish context = () =>
        {
            _actionCall = ActionCall.For<NewsController>(h => h.Root());
            _log = new Mock<IConfigurationObserver>();

            _urlPolicy = new EnsureControllersCanHaveARootUrlPolicy();
        };

        Because of = () => _matches = _urlPolicy.Matches(_actionCall, _log.Object);

        It should_match = () => _matches.ShouldBeTrue();

        private static EnsureControllersCanHaveARootUrlPolicy _urlPolicy;
        private static bool _matches;
        private static ActionCall _actionCall;
        private static Mock<IConfigurationObserver> _log;
    }

So here I’m writing specifications for my new class “EnsureControllersCanHaveARootUrlPolicy” and the first should not match on an action call to the HomeController’s FrontPage method.
The second should match on an action call to a new class, NewsController, and its new Root method that meets my convention.
Here’s the implementation for this:

    public class EnsureControllersCanHaveARootUrlPolicy : IUrlPolicy
    {
        public bool Matches(ActionCall call, IConfigurationObserver log)
        {
            return call.Method.Name.EndsWith("Root");
        }
    }

My next specification is for the building of the route definition when the policy executes:

    [Subject(typeof(EnsureControllersCanHaveARootUrlPolicy))]
    public class when_building_a_route_definition
    {
        Establish context = () =>
        {
            _actionCall = ActionCall.For<NewsController>(h => h.Root());

            _urlPolicy = new EnsureControllersCanHaveARootUrlPolicy();
        };

        Because of = () => 
            _routeDefinition = _urlPolicy.Build(_actionCall);

        It should build_the_route_from_the_prefix_of_the_controller = () =>
            _routeDefinition.Pattern.ShouldEqual("news");

        private static EnsureControllersCanHaveARootUrlPolicy _urlPolicy;
        private static bool _matches;
        private static ActionCall _actionCall;
        private static Mock<IConfigurationObserver> _log;
        private static IRouteDefinition _routeDefinition;
    }

When the route definition is required, I want this policy to make sure that “controller” is stripped from the name of the handling type (in this case NewsController) and that the name is in lower case.

Here’s the full implementation of the policy:

    public class EnsureControllersCanHaveARootUrlPolicy : IUrlPolicy
    {
        public bool Matches(ActionCall call, IConfigurationObserver log)
        {
            return call.Method.Name.EndsWith("Root");
        }

        public IRouteDefinition Build(ActionCall call)
        {            
            var newRoute = call.HandlerType.Name.Replace("Controller", string.Empty).ToLower();

            var routeDefinition = call.ToRouteDefinition();
            routeDefinition.Append(newRoute);
            return routeDefinition;
        }
    }

The next thing to do is to create a new view model in the NewsController and hook it up to my old news spark view that I’m migrating across. Here’s the news controller:

    public class NewsController
    {
        public NewsViewModel Root()
        {
            return new NewsViewModel();
        }
    }

    public class NewsViewModel
    {
    }

In my spark view, I ensure that the page is using this new output view model:

<viewdata model="Xerces.Web.Core.Home.NewsViewModel" />

Last thing to do is declare this policy in my own fubu registry :

    public class XercesFubuRegistry : FubuRegistry
    {
        public XercesFubuRegistry()
        {
            IncludeDiagnostics(true);

            Applies.ToThisAssembly();

            Actions.IncludeClassesSuffixedWithController();

            Routes.HomeIs<HomeController>(c => c.FrontPage())
                .IgnoreControllerNamespaceEntirely()
                .UrlPolicy<EnsureControllersCanHaveARootUrlPolicy>();  <-- new line

            this.UseSpark();

            Views.TryToAttachWithDefaultConventions();

            Output.ToJson.WhenCallMatches(action => action.Returns<AjaxResponse>());
        }
    }

I already have the start url of my web application pointed to the “_fubu/actions” url so that it goes straight to diagnostics, so I now debug the application to examine my new action set up:

urlpolicy

I now have a new action registered for NewsController.Root() that points to my news.spark view and has a route of “news”. In the bottom left corner is the hover on the news link, showing that it points to “/news”.

As you can see it is very easy to customise your MVC application and have it work exactly how you want with the powerful hooks that fubuMVC has provided.
In this convention I had decided to have a HomeController.FrontPage(), NewsController.Root(), AboutController.Root() – this is my personal preference so they are isolated and quite easy to remember that they will generate a root url.

However, let us look at an alternative just to show how customisable these rules are.. what if I had wanted to stick to my original ASP.NET MVC layout where the HomeController had methods called News() and About()?

If I say that my new convention is any method on the HomeController that is not FrontPage() has the method name used as the root url, this should give me the same output.
I would end up with something like:

    public class EnsureHomeControllerCanGenerateRootUrlsPolicy : IUrlPolicy
    {
        public bool Matches(ActionCall call, IConfigurationObserver log)
        {
            return call.HandlerType == typeof(HomeController)
                && call.Method.Name.ToLower() != "frontpage";
        }

        public IRouteDefinition Build(ActionCall call)
        {
            var newRoute = call.Method.Name.ToLower();
            var routeDefinition = call.ToRouteDefinition();
            routeDefinition.Append(newRoute);
            return routeDefinition;
        }
    }

This time I would be using the HandlerType of the action call and if it is the HomeController and the action call method is not the FrontPage method, then it would be eligible to build a route definition and it would use the lowercase name for that.

So that’s how I customised my routes with a url policy – oh and did I say that fubuMVC is great?!

Posted at at 7:29 AM on Thursday, August 25, 2011 by Posted by Justin Davies | 1 comments Links to this post   | Filed under:

My experiences with fubuMVC

I’m currently writing a series on my experiences using the excellent fubuMVC open source framework and thought I’d list the topics I’m writing about here.

It's a "How I..." series because fubuMVC allows you to customise and take control anyway you want.
It's amazing.

Here are all the posts in this series:

Posted at at 7:24 AM on Tuesday, August 23, 2011 by Posted by Justin Davies | 1 comments Links to this post   | Filed under:

How I got started with fubuMVC

I’m in the process of re-writing my own production project to use fubuMVC and I wanted to share how easy it was to get started with the framework and use the fubu power to get up and running with very little ceremony.

Step one:

Create a new 4.0 ASP.NET web application and reference the libraries I need to use fubuMVC:

xercesweb

Step two:

In the Global.asax.cs start wiring up the FubuApplication.

To do this, in my application start method I hook up my own (currently empty) implementation of FubuRegistry, with a new structure map container and Bootstrap using the routes from the route table.

        protected void Application_Start(object sender, EventArgs e)
        {
            FubuApplication
                .For<XercesFubuRegistry>()
                .StructureMap(() => new Container())
                .Bootstrap(RouteTable.Routes); 
        }

        public class XercesFubuRegistry : FubuRegistry
        {
        }

Step three:

Declare the setup of my FubuRegistry

    public class XercesFubuRegistry : FubuRegistry
    {
        public XercesFubuRegistry()
        {
            IncludeDiagnostics(true);

            Applies.ToThisAssembly();

            Actions.IncludeClassesSuffixedWithController();

            Routes.HomeIs<HomeController>(c => c.FrontPage())
                  .IgnoreControllerNamespaceEntirely();

            this.UseSpark();

            Views.TryToAttachWithDefaultConventions();
        }
    }

I’m including diagnostics so that I can use fubuMVC’s excellent diagnostic features to help me visualise how the code in the site works for each url as I build it (more on this below).

I’ve decided to stick with a “controller actions” concept so I tell fubuMVC that actions are those classes that end with “Controller”.

I declare my home route as the HomeController (which I’ve yet to create) and declared a method on there called FrontPage.
I also tell fubuMVC to ignore the namespaces of my controller class when building the routes.

I’m using the spark view engine and I tell fubuMVC to wire up the views with default conventions – here it will use a number of ways to match the view based on the model returned by the FrontPage method – I’m essentially wanting it to look for the only concrete implementation of that type.

Step four:

Create the controller – it does not take any parameters in the front page method and it returns a HomeViewModel.
This is a zero model in, one model out concept that fubuMVC is very opinionated on (along with the one model in, one model out concept).

    public class HomeController
    {
        public HomeViewModel FrontPage()
        {
            return new HomeViewModel();
        }
    }

    public class HomeViewModel
    {
    }

Step five:

Create my view.

I’m actually importing the code from my existing home page but now I can call this view whatever I want rather than relying on naming conventions and location matching – one of the beautiful things about fubuMVC is that I am free to put my actions and views anywhere I like and it will hook them up based on the types concerned – a HomeController type for the action and a view that uses the HomeViewModel for my output.

My spark view, frontpage.spark, now uses the HomeViewModel:

<viewdata model="Xerces.Web.Core.Home.HomeViewModel" />

<div id="imageContainer">
...etc

Here’s a picture of my web application illustrating that I can have the action and views where I want:

xercesweb2

Step six:

Confirm that it all works!

I set the start page of my web application to “_fubu/actions” – this points to one of the diagnostics pages for my fubuMVC application – and I debug the website:

xercesweb3

The fubuMVC diagnostics shows me that I have one registered action that is the HomeController I set up. The action returns a HomeViewModel and the view it has found that ties up with this output model is my frontpage.spark view.

I can click on the “(default)” route to take me to the website and my home page loads!
(note that using the diagnostics as my start page is a personal preference and isn’t required)

This was very easy and fubuMVC is doing a lot of the work for me so that out of the box it just makes my life simple.
I’m going to love working with this framework.

Posted at at 5:47 PM on Saturday, August 20, 2011 by Posted by Justin Davies | 4 comments Links to this post   | Filed under: