Monday, January 11, 2010

“Hello World” with FubuMVC (without the training wheels)

My previous post was a FubuMVC super quick-start which explained how to utilize some very helpful code that has been added into the Fubu source to allow you to get up and running fast. While this should suit most initial situations, there probably will be a point where you need to add your own conventions. I will walk you through creating your own bootstrapping code which will also explain how the “training wheels” from the previous post work. I am going to borrow heavily from Chad Myers’ explanation’s which he posted on the FubuMVC Google Group, because I could not have said it better.

  1. (Starting from the previous posts step #11) Add a “Global.asax” file and delete all the generated methods except “Application_Start”. In “Application_Start” add the following:

       1: public class Global : System.Web.HttpApplication {
       2:     protected void Application_Start(object sender, EventArgs e) {
       3:         var routeCollection = RouteTable.Routes;
       4:         FubuStructureMapBootstrapper.Bootstrap(routeCollection);
       5:     }
       6: }

  2. Create a FubuStructureMapBootstrapper.cs class that implements the IBootstrapper interface from StructureMap and then implement it’s members. This class manages the starting of Fubu and StructureMap together.

       1: public class FubuStructureMapBootstrapper : IBootstrapper {
       2:     private readonly RouteCollection _routes;
       3:  
       4:     private FubuStructureMapBootstrapper(RouteCollection routes) {
       5:         _routes = routes;
       6:     }
       7:  
       8:     public void BootstrapStructureMap() {
       9:         UrlContext.Reset();
      10:  
      11:         ObjectFactory.Initialize(x => { });
      12:  
      13:         BootstrapFubu(ObjectFactory.Container, _routes);
      14:     }
      15:  
      16:     public static void BootstrapFubu(IContainer container, RouteCollection routes) {
      17:         var bootstrapper = new StructureMapBootstrapper(container, new HelloWorldFubuRegistry());
      18:         bootstrapper.Bootstrap(routes);
      19:     }
      20:  
      21:     public static void Bootstrap(RouteCollection routes) {
      22:         new FubuStructureMapBootstrapper(routes).BootstrapStructureMap();
      23:     }
      24: }
    
    

  3. Create the HelloWorldFubuRegistry class that is passed into the StructureMapBootstrapper constructor along with the container. This is where all the actual Fubu conventions are located.

       1: public class HelloWorldFubuRegistry : FubuRegistry {
       2:     public HelloWorldFubuRegistry() {
       3:         IncludeDiagnostics(true);
       4:  
       5:         Applies.ToThisAssembly();
       6:  
       7:         Actions
       8:             .IncludeTypesNamed(x => x.EndsWith("Controller"));
       9:  
      10:         Routes
      11:             .IgnoreControllerNamespaceEntirely();
      12:  
      13:         Views.TryToAttach(x => {
      14:                               x.by_ViewModel_and_Namespace_and_MethodName();
      15:                               x.by_ViewModel_and_Namespace();
      16:                               x.by_ViewModel();
      17:                           });
      18:     }
      19: }
    

  4. IncludeDiagnostics(true) – Enable the diagnostics to be accessible through the /_fubu and /?fubudebug=true querystring options
  5. Applies.ToThisAssembly() – Tells Fubu to perform the following registration steps by scanning this assembly
  6. Actions.IncludeTypesNamex(x => x.EndsWith(“Controller”)) – Tells Fubu how to identify which classes containing action methods (i.e. HomeController)
  7. Routes.IgnoreControllerNamespareEntirely()  -- By default, Fubu will create a route for each action like /namespace/controllerbasename/action. Normally you wouldn't want /fubumvc/helloworld/controllers/home/home/home, you'd just want /home/home or /home/index or whatever. "IgnoreControllerNamespaceEntirely" does that. There are numerous variations of how to arrive at the route name here. Otherwise, you can specify your own conventions and manage the process.
  8. Views.TryToAttach --  This is a fall-through for matching actions-that-should-render-views (as opposed to actions that should render JSON) to their corresponding views.  It goes as follows:

      1. Try to match a view that is strongly typed (i.e. IFubuView where TModel is the return/output type of the Action), *AND* is in the same Namespace as the Controller/Action class *AND* is named the same as the Action/Method name (i.e. Home() -> Home.aspx)

      2. Try to match on the model *AND* the Namespace

      3. If all else fails, try to find a view anywhere in this assembly that matches the model type (Meaning that you don’t need to have the controllers and views in the same folder)

  9. Just in case you missed it, perform the same web.config tweaking like in the previous post.
I added this to my personal Google Code repo folder here. I anticipate that this, or something like it, will probably be moved to the Fubu code or wiki in the near future.

-Tim Tyrrell

0 comments: