FubuMVC From Scratch – Part 3 (Adding View to project)

Previous Posts in Series:

  • FubuMVC From Scratch Part 1 – Basic project structure setup
  • FubuMVC From Scratch Part 2 – FubuMVC configuration and Controller setup

Preparing for our View

Another founding principal of FubuMVC is to have little to no logic in the View, no logic is preferred. So when we add .aspx pages, we will delete the code behind files since we won’t be using them. We will need another file in our Views folder named “View_Page_Type_Declarations.cs” We will declare all of our View Pages in this file.

This file looks like this at the moment:

using FubuSample.Core.Web.Controllers;
 
public class HomeIndexView : FubuSamplePage<IndexViewModel> { }

You will notice that we don’t have a FubuSamplePage class anywhere in our project. So let’s go ahead and add the 3 main classes all of our Views and controls will inherit from.

We also need to add a reference to System.Web to our FubuSample.Core project, so do that quickly before we move on.

Page Interface

We need to create an interface that all of our pages will implement to give us some standard results. Our interface just says that every page that implements IFubuSamplePage will provide an object that is our Model or ViewModel. This class just goes in the FubuSample.Core.Web folder.

public interface IFubuSamplePage : IFubuViewWithModel
{
    object Model { get; }
}

The rest of these classes will be created in the Core.Web.WebForms folder. These pages implement our interface as well as a FubuMVC View interface so the framework can work with our view pages.

FubuSamplePage

public class FubuSamplePage<MODEL> : Page, IFubuSamplePage, IFubuView<MODEL>
    where MODEL : ViewModel
{
    public void SetModel(object model)
    {
        Model = (MODEL)model;
    }
 
    public ViewModel GetModel()
    {
        return Model;
    }
 
    public MODEL Model { get; set; }
 
    object IFubuSamplePage.Model { get { return Model; } }
}

FubuSampleUserControl

public class FubuSampleUserControl<MODEL> : UserControl, IFubuSamplePage, IFubuView<MODEL>
    where MODEL : class
{
    public void SetModel(object model)
    {
        Model = (MODEL)model;
    }
 
    public object GetModel()
    {
        return Model;
    }
 
    public MODEL Model { get; set; }
 
    object IFubuSamplePage.Model { get { return Model; } }
}

FubuSampleMasterPage

public class FubuSampleMasterPage : MasterPage, IFubuSamplePage
{
    object IFubuSamplePage.Model { get { return ((IFubuSamplePage) Page).Model; } }
 
    public ViewModel Model { get { return ((IFubuSamplePage) Page).Model as ViewModel; } }
 
    public void SetModel(object model)
    {
        throw new System.NotImplementedException();
    }
}

Once we have these three classes all setup we are ready to start adding some views!

Creating a Site.Master

Let’s go ahead and create a Site Master file so we have a place to display our content once we create it. First though, we need to declare our SiteMasterView in view_page_type_declarations, so add this line to that file:

public class SiteMasterView : FubuSampleMasterPage { }

Add another folder to the Views folder in our Web project, named Shared. Inside this folder create a new Site Master File. I am changing a few things in this generated file

  • Rename the ID for the main ContentPlaceHolder to be “MainContent” instead of ContentPlaceHolder1.
  • Delete the code behind files
  • Modify the page declaration like so:
    • Delete “AutoEventWireup="true"
    • Delete CodeBehind=”Site.master.cs”
    • Change Inherits to “SiteMasterView”

We can customize this further later on if we want to.

Adding the Corresponding View for our HomeController

Since we have our controller ready to go, lets setup a View in our Web project. In the Views folder add another folder named Home. Inside this folder create a new .aspx web form named Index (Index corresponds with our method name in our controller)

Once this file is created, go ahead and delete the two code behind files, and all the html code that was generated.

Next modify the page declaration in Index.aspx from:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="FubuSample.Web.Views.Home.Index" %>
 
TO:
 
<%@ Page Inherits="HomeIndexView" MasterPageFile="~/Views/Shared/Site.Master" %>

Now instead of cramming a bunch of logic into our view we will use some of FubuMVC’s built in Html helper magic to make this simple. Add the following Html/C# code to your Index.aspx

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<div>
    <div>
         <%= this.RenderPartial().Using<ProductInfo>().ForEachOf(Model.Products) %>
    </div>
</div>
</asp:Content>

What we are doing here is saying that For Each Product in our list Products render part of the view using a UserControl called ProductInfo, let’s make this control now.

Creating ProductInfo User Control

Back to View_page_type_declarations real quick so we can define our UserControl. Add the following line to your view page type declarations file:

public class ProductInfo : FubuSampleUserControl<ProductDisplay> { }

Now add a new user control to the Views/Shared folder named ProductInfo, same as before delete the code behind files and make your ascx file look like this:

<%@ Control Language="C#" Inherits="ProductInfo" %>
<h2><%= Model.Name %></a></h2>
<div><%= Model.Description %></div>

We are almost ready to see if our labor has produced any fruit. But we need to modify our Web.config file. I am getting tired so I am not going to go in depth on what all has to change, I just copied the AltOxite Web.Config and modified what needed to be changed. Here are the results:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appSettings>
    
  </appSettings>
  <connectionStrings />
  <system.web>
    <httpModules>
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpModules>
    <compilation debug="true" defaultLanguage="C#">
      <assemblies>
        <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
      </assemblies>
    </compilation>
 
    <authentication mode="Forms">
      <forms loginUrl="~/login" defaultUrl="~/"/>
    </authentication>
 
    <pages>
      <namespaces>
        <add namespace="FubuSample.Core.Web" />
        <add namespace="FubuSample.Core.Web.Controllers" />
        <add namespace="FubuSample.Web" />
 
        <add namespace="FubuMVC.Core.View" />
        <add namespace="FubuMVC.Core.Html" />
        <add namespace="FubuMVC.Core.Html.Expressions" />
      </namespaces>
    </pages>
 
  </system.web>
 
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <providerOption name="CompilerVersion" value="v3.5" />
        <providerOption name="WarnAsError" value="false" />
      </compiler>
    </compilers>
  </system.codedom>
 
  <!-- 
        The system.webServer section is required for running ASP.NET AJAX under Internet
        Information Services 7.0.  It is not necessary for previous version of IIS.
    -->
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="UrlRoutingModule" />
      <add name="UrlRoutingModule" preCondition="managedHandler" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-ISAPI-2.0-64" />
      <remove name="WebServiceHandlerFactory-ISAPI-2.0" />
      <remove name="WebServiceHandlerFactory-Integrated" />
      <remove name="SSINC-shtml" />
      <remove name="SSINC-stm" />
      <remove name="SSINC-shtm" />
      <remove name="SimpleHandlerFactory-ISAPI-2.0-64" />
      <remove name="SimpleHandlerFactory-ISAPI-2.0" />
      <remove name="SimpleHandlerFactory-Integrated" />
      <remove name="SecurityCertificate" />
      <remove name="PageHandlerFactory-ISAPI-2.0-64" />
      <remove name="PageHandlerFactory-ISAPI-2.0" />
      <remove name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" />
      <remove name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" />
      <remove name="HttpRemotingHandlerFactory-soap-Integrated" />
      <remove name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" />
      <remove name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" />
      <remove name="HttpRemotingHandlerFactory-rem-Integrated" />
      <remove name="ASPClassic" />
      <remove name="AboMapperCustom-78953" />
      <!--<remove name="PageHandlerFactory-Integrated" />-->
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </handlers>
    <defaultDocument>
      <files>
        <remove value="index.html" />
        <remove value="index.htm" />
        <remove value="Default.htm" />
        <remove value="Default.asp" />
        <remove value="iisstart.htm" />
        <remove value="default.aspx" />
      </files>
    </defaultDocument>
  </system.webServer>
 
</configuration>

I will tell you some of the more important aspects though:

  • Add UrlRoutingModule to <httpModules> under <system.web>
  • Add all the namespaces your projects uses be default under <namespaces> inside <pages> under <system.web>

With any luck, this should work when you debug it. Using the integrated Visual Studio Web server you will have to manually type “/Home” at the end of your localhost address.

You can find some information on running a FubuMVC project with the Visual Studio Web server out on the wiki

2 thoughts on “FubuMVC From Scratch – Part 3 (Adding View to project)”

  1. in your ProductInfo.ascx you have

    i don’t see any reason for the closing anchor tag, maybe this should be removed ?

Comments are closed.