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.

    Advertisement

    11 Comments to “ASP.NET MVC3 with Razor view engine using Monodevelop and Ubuntu 12.04”

    1. Wow, I gave a about a year ago, had so many problems with mono develop on Suse. I will have to give it a try again.

    2. Thanks for this!!!

      I copied over System.Web.Mvc.dll from Windows, and still choking on GlobalFilterCollection. Any advise on what else to try?

    3. I got it to work!! I had to add the following using statements to your global.asax.cs example to resolve the errors with being unable to find GlobalFilterCollection and RouteCollection.

      using System.Web.Mvc;
      using System.Web.Routing;

      Yay! Thanks for the great article! 🙂

    4. Is it safe to just copy the .dlls to the /usr/lib/mono/4.0 folder so that all future projects will just use them?

      • You can do that too, but it’s more intrusive than what I’ve shown for a one off project. Please let me know if storing the DLLs in /use/lib/mono/4.0 worked out for you. Thanks!

    5. I am breathless… I was looking so much to dig into Mono technology. I will try to migrate one medium sized project from razor to mono. Will let you know how hard it was.
      Thanks a lot!

    6. Awesome finding… thanks a lot!!! I was really curious to port a project to mono. Now I know it is possible.

    7. Hey thank you for your article
      I’ve tryed to follow your directives but got an error when trying to run…
      Here is what I got, any Idea?

      p.s. Sorry for my english

      Server Error in ‘/’ Application
      The view ‘Index’ or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Views/Home/Index.aspx ~/Views/Home/Index.ascx ~/Views/Shared/Index.aspx ~/Views/Shared/Index.ascx ~/Views/Home/Index.cshtml ~/Views/Home/Index.vbhtml ~/Views/Shared/Index.cshtml ~/Views/Shared/Index.vbhtml

      Description: HTTP 500. Error processing request.

      Stack Trace:

      System.InvalidOperationException: The view ‘Index’ or its master was not found or no view engine supports the searched locations. The following locations were searched:
      ~/Views/Home/Index.aspx
      ~/Views/Home/Index.ascx
      ~/Views/Shared/Index.aspx
      ~/Views/Shared/Index.ascx
      ~/Views/Home/Index.cshtml
      ~/Views/Home/Index.vbhtml
      ~/Views/Shared/Index.cshtml
      ~/Views/Shared/Index.vbhtml
      at System.Web.Mvc.ViewResult.FindView (System.Web.Mvc.ControllerContext context) [0x00000] in :0
      at System.Web.Mvc.ViewResultBase.ExecuteResult (System.Web.Mvc.ControllerContext context) [0x00000] in :0
      at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult (System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ActionResult actionResult) [0x00000] in :0
      at System.Web.Mvc.ControllerActionInvoker+c__DisplayClass1c.b__19 () [0x00000] in :0
      at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter (IResultFilter filter, System.Web.Mvc.ResultExecutingContext preContext, System.Func`1 continuation) [0x00000] in :0

      Version information: Mono Runtime Version: 2.10.8.1 (Debian 2.10.8.1-8); ASP.NET Version: 4.0.30319.1

      • Daniel :
        I saw you have the problem in APS.NET MVC3, I just meet the same problem like you did. Have you slove this problem,can you give me some advise?

      • I once had this problem, and the issue was that in I forgot in *nix urls are case sensitive. meaning when you type the url into the address bar you have to type it in the same way it appears in your file system so instead of localhost:8080/home/index it should be localhost:8080/Home/Index

        Hope this helps

    8. Great artícle! I just want to mention something: regarding the required assemblies:
      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

      You can actually download them using nuget (the Ms package manager). You just need to download it (nuget-signed.exe) from https://nuget.codeplex.com/releases and run it from linux with a command line like the following example:

      /opt/mono/bin/mono –runtime=v4.0.30319 /home/daniel/nuget/nuget-signed.exe install microsoft.aspnet.webpages -version 2.0.30506

      The names/versions of the packages are the following (at this point there could be newer versions, but these are the ones I downloaded):
      Microsoft.AspNet.Mvc.4.0.30506.0
      Microsoft.AspNet.Razor.2.0.30506.0
      Microsoft.AspNet.WebPages.2.0.30506.0

      I beleive I also needed this:
      Microsoft.Web.Infrastructure.1.0.0.0

    Leave a Reply to danielC Cancel reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out /  Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out /  Change )

    Connecting to %s

    %d bloggers like this: