ASP.NET MVC3 with Razor view engine using Monodevelop and Ubuntu 12.04

August 27, 2012
ASP.NET MVC3 with Razor view engine using Monodevelop and Ubuntu 12.04

ASP.NET MVC3 with Razor view engine using Monodevelop and Ubuntu 12.04

Developing .Net web applications in a Linux environment has been somewhat of a personal curiosity for quite some time. I have Ubuntu 12.04 installed in a dual boot configuration and every once in a while get an urge to actually boot Ubuntu and tinker with Monodevelop to see how far along the project has come. Since most of my time is spent developing ASP.NET MVC3 applications, I decided to see if it was possible to get a simple application running using the Razor view engine.

The last time I attempted this (over a year ago), it turned out to be more of a pain getting a web server configured to run ASP.NET applications than it was worth. The experience this time was much better as Monodevelop has xsp4 integrated out of the box for serving the web pages. xsp4 is a minimalistic web server which hosts the ASP.NET runtime.

To be honest, I was hoping that by now Monodevelop would have support for the Razor view engine and it would just work 'out of the box'. This of course was just wishful thinking. However, the actual process to get it working isn't a deal breaker anymore; especially after you have done it once.

To begin with, you will want to get the latest version of Monodevelop. The Ubuntu repository is a bit behind, so using a ppa is your best bet:

sudo add-apt-repository ppa:keks9n/monodevelop-latest 
sudo apt-get update 
sudo apt-get install monodevelop

This process will take a few minutes depending on your connection speed. Once installed, launch Monodevelop and click Start New Solution. Select ASP.NET MVC Project from the C# section and give your project a name and location.

Once the project is created, compile it and optionally run it. Compiling the project will create a bin folder with the relevant assemblies. If your project will not compile and the message refers to a .NET 3.5 compiler not being found, be sure to change your build to use .NET 4.0. Right click on your project (not the solution) and select options. Under build, click on 'General' and select 'Mono/.NET 4.0'.

In the bin folder, there will be a System.Web.Mvc.dll. This is an 'old' version and will be replaced. The first thing to do at this point is remove that reference from your project. In the solution explorer of Monodevelop, expand the references and then right-click delete System.Web.Mvc.

The next steps require that you have some assemblies from a Windows compiled MVC 3 project. If you don't have access to a Windows machine, just google for them. The assemblies that you will want to copy over to the bin folder are as follows:

  • System.Web.Helpers.dll
  • System.Web.Mvc.dll
  • System.Web.Razor.dll
  • System.Web.WebPages.dll
  • System.Web.WebPages.Deployment.dll
  • System.Web.WebPages.Razor.dll

Once you have copied them to the bin folder, add them as references to your project. To do this, right click 'references' in the solution explorer and select 'edit references'. Click the .Net Assembly tab and double click the bin folder. Control-click all of the above dll's and then click the 'add' button.

Almost there. The project that was created by Monodevelop is using aspx pages. You will need to configure the project to use the Razor view engine. You can manually edit the Web.config to include razor, or be lazy like I was and just copy everything from a project created in Visual Studio. Here's a complete Web.Config that you can copy and paste:

<?xml version="1.0"?>
 
<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    </sectionGroup>
  </configSections>
 
  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
 
  <appSettings>
    <add key="webpages:Enabled" value="false" />
  </appSettings>
 
  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>
 
    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>
 
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
 
    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

It's probably a good idea to copy Global.asax.cs for updated route configuration. This is the step where you will be glad to have copied System.Web.Mvc from a Windows build. Without it, you will not be able to compile the project because GlobalFilterCollection will not exist. Replace the complete class with the following:

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
 
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );
 
    }
 
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
 
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }
}

Finally, rename ~/Views/Home/Index.aspx to Index.cshtml and then replace its contents with the following:

@{
    ViewBag.Title = "Home Page";
}
 
<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>
</p>

If all went well, you can compile and run your project by hitting F5.