Friday, January 8, 2010

“Hello World” with FubuMVC (Super Quick Start)

I started at Dovetail Software near the end of last year and the guys were gearing up to strip out the “proto-fubu” framework from their current project and rewrite the existing FubuMVC code; which is now complete. This week Brandon and I messed around and created a sample application to get more familiar with the framework. These are the steps that we used to get a quick sample up and running (made *much* easier by Chad and Josh last night).

  1. Get FubuMVC source from the “reboot” branch using something like TortoiseSVN at http://fubumvc.googlecode.com/svn/branches/reboot/ (soon to be Git). A sample application very similar to what is listed below is in the src/FubuMVC.HelloWorld folder
  2. Get Ruby to build it by navigating to the base FubuMVC folder and run a “rake” command (I am using “Ruby-186-27”, but any should work) or just open the solution and compile it.
  3. Create an ASP.NET Web Application project. Create a “lib” folder on the file system next to the newly created project
  4. Grab all the files (not just the three DLL's below) from the %yourFubufolder%\build folder if you raked, or %yourFubufolder%\src\FubuMVC.Container.StructureMap\bin\Debug folder if you built it through Visual Studio, copy them to a “lib” folder mentioned above, and then add three references to your project
    1. StructureMap.dll
    2. FubuMVC.Core.dll
    3. FubuMVC.StructureMap.dll
  5. Also add a reference to “System.Web.Routing” if you want to make the squiggle’s in your web.config go away
  6. Delete the “Default.aspx” file and the App_Data folder
  7. Create a Controllers Folder and then add a Home folder underneath it
  8. Add a Home.aspx Web Form page into the Home folder, have it inherit from the FubuPage<TViewModel> class instead of the Page class (FubuPage inherits from Page) and create an output view model to plug into that spot
       1: using FubuMVC.Core.View;
       2:  
       3: namespace FubuMVC.HelloWorld.Controllers.Home
       4: {
       5:     public class Home : FubuPage<HomeViewModel>
       6:     {
       7:     }
       8: }

  9. Add a HomeContoller.cs class to the Home folder and add a method that returns the previously created output view model, HomeViewModel and accepts a new input model
       1: namespace FubuMVC.HelloWorld.Controllers.Home
       2: {
       3:     public class HomeController
       4:     {
       5:         public HomeViewModel Home(HomeInputModel model)
       6:         {
       7:             return new HomeViewModel {Text = "Hello, world."};
       8:         }
       9:     }
      10:  
      11:     public class HomeViewModel
      12:     {
      13:         public string Text { get; set; }
      14:     }
      15:  
      16:     public class HomeInputModel
      17:     {
      18:     }
      19: }

  10. Get the text out of the returned Model and display it on the view (I yanked out the server tags, although that is not necessary)

  11.    1: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Home.aspx.cs" Inherits="FubuMVC.HelloWorld.Controllers.Home.Home" %>
       2:  
       3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
       4:  
       5: <html xmlns="http://www.w3.org/1999/xhtml" >
       6: <head>
       7:     <title></title>
       8: </head>
       9: <body>
      10:     <div>
      11:         <%= Model.Text %>
      12:     </div>
      13: </body>
      14: </html>



  12. Add a Global.asax file to the project, but instead of inheriting from HttpApplication, inherit from FubuStructureMapApplication:

       1: using FubuMVC.StructureMap.Bootstrap;
       2:  
       3: namespace FubuMVC.HelloWorld
       4: {
       5:     public class Global : FubuStructureMapApplication
       6:     {
       7:     }
       8: }

  13. If you want to turn on the diagnostics from Jeremy’s article, switch the web.config debug="true"and the diagnostics will be enabled. Otherwise you can set it yourself below.

  14.    1: using FubuMVC.StructureMap.Bootstrap;
       2:  
       3: namespace FubuMVC.HelloWorld
       4: {
       5:     public class Global : FubuStructureMapApplication
       6:     {
       7:         public Global()
       8:         {
       9:             EnableDiagnostics = true;
      10:         }
      11:     }
      12: }

  15. Lastly, we took out the machete on the web.config file. Although, we did add some references to System.Web.Routing inside of it.
       1: <?xml version="1.0"?>
       2: <configuration>
       3:   <configSections/>
       4:   <appSettings/>
       5:   <connectionStrings/>
       6:   <system.web>
       7:     <compilation debug="false">
       8:       <assemblies>
       9:         <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
      10:         <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      11:       </assemblies>
      12:     </compilation>
      13:     <authentication mode="None" />
      14:     <pages>
      15:       <controls/>
      16:     </pages>
      17:     <httpHandlers/>
      18:     <httpModules>
      19:       <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      20:     </httpModules>
      21:   </system.web>
      22:   <system.codedom>
      23:     <compilers>
      24:       <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4"
      25:                 type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      26:         <providerOption name="CompilerVersion" value="v3.5"/>
      27:         <providerOption name="WarnAsError" value="false"/>
      28:       </compiler>
      29:     </compilers>
      30:   </system.codedom>
      31:   <system.webServer>
      32:     <validation validateIntegratedModeConfiguration="false"/>
      33:     <modules>
      34:       <remove name="UrlRoutingModule" />
      35:       <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      36:     </modules>
      37:     <handlers>
      38:       <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      39:     </handlers>
      40:   </system.webServer>
      41: </configuration>

  16. Add the project path to new application in IIS (or Cassini) and hit the URL: http://localhost/%yourapp%/home/home

image


Screenshot of final folder structure and references:

image

Code location: An application very similar to this is located in the reboot branch of FubuMVC, called FubuMVC.HelloWorld in the src folder here

Let me know if I missed anything or if this does not work. A lot will be done in the next couple of weeks to get Fubu rocking, and I plan on blogging as much as possible along the way. As you probably heard, we are starting up a posse: http://wiki.fubumvc.com/TODO

-Tim Tyrrell

12 comments:

Travis January 8, 2010 at 10:31 AM  

So CodeBehind is required for the Views? Using this directive "<%@ Page Language="C#" Inherits="FubuMVC.Core.View.FubuPage" %>" I get nothing. I am total fubu newb, so I am probably missing something.

Troy Goode January 8, 2010 at 11:43 AM  

Out of curiosity, why doesn't this work in Cassini?

Travis January 8, 2010 at 12:16 PM  

Troy it does, but you have use /Home/Home for the url.

Anonymous January 8, 2010 at 12:49 PM  

Could you explain what is the difference with ASP.NET MVC?

Unknown January 9, 2010 at 2:54 AM  

Would it be possible to have two urls ( / and /home/home ) for the same route ?

Tom Janssens January 9, 2010 at 4:48 AM  

Thank you for this great post. I wanted to get in to fubumvc but did not have enough time yet to get started...
I am very eager to see your next post about this..
BTW, could you give a short explanation of the (default) routing & controller conventions please ?

Thank you !

Ben Keeping January 9, 2010 at 4:57 AM  

For those new to Ruby/Rake, the rake file requires you to install rubyzip.
Eg, from the cmd prompt :

gem install rubyzip

Tim Tyrrell January 9, 2010 at 8:42 AM  

@Some - There are two issues with removing the code-behind file:
1. Without it, the route does not get registered correctly because the aspx file gets compiled into another assembly, so Fubu cannot associate the view with the matching view model type (because they currently must be in the same assembly).
2. ReSharper goes ape-shit (maybe fixed in R#5?)

The original reason to remove code-behind is so that people will not be tempted to put stuff in the pageload. Well, we feel that anyone using Fubu will not be prone to that behavior. I understand that it is nice to get rid of them (it was the first question that I asked, as well), and one quick way is to placing the strongly-typed view declaration inside your controller(or another file in the assembly), you could place it next to the view model classes:

//This one line allows for the association of the Home.aspx view with the HomeViewModel strongly-typed model and keeps ReSharper support in the view
public class Home : FubuPage<HomeViewModel> { }

Tim Tyrrell January 9, 2010 at 8:51 AM  

@Mike - Check out the wiki http://fubumvc.pbworks.com/ for a little more info...

Tim Tyrrell January 9, 2010 at 8:56 AM  

@exeter - Thanks, I will update the ruby info on the post

@Tom - I hope to post this weekend with more details on the default configuration/conventions

@Mihai - I will take a deeper look on the routing and let you know

Ben Keeping January 9, 2010 at 1:03 PM  

If anyone has problems getting 404 errors running in VS's dev server, I found that by also adding references to HtmlTags.dll and Microsoft.Practices.ServiceLocation.dll fixed it. Note, noit just copying the files, but adding references.

I'm using the example source code from SVN with VS 2008 SP1

Tim Tyrrell March 25, 2010 at 10:55 AM  

@Mihai Adding something similar to the config will set the default route - HomeIs();