Compile your asp.net mvc Razor views into a seperate dll

by Chris van de Steeg. 112 Comments

NOTE: THE GENERATOR HAS EVOLVED SINCE THIS POST.Although the post is still worth reading, please go to http://razorgenerator.codeplex.com/ for the most up to date version.

Inspired by David Ebbo’s blog post ‘Turn your Razor helpers into reusable libraries’ I wanted to be able to embed compiled Razor views in a dll. This would allow for easy distribution of asp.net mvc ‘modules’ that have their default views embedded, but allowing you to place files in your ‘views’ folder to override those default views.

To generate the c# code for the views, I just started out with David Ebbo’s single file generator and modified it to generate views instead of helpers only. To do this, there had to be a WebRazorHostFactory that knew about all the mvc stuff (what dll’s to reference, what namespaces to use, etc) .I could either choose to include all that information statically in the code, or I could look for a web.config in the same project and let the WebRazorHostFactory use that config. I chose the latter option, so that everyone can easily change the WebRazorHostFactory behavior  by adding a web.config file to their project.

Next, I started figuring out how the PageVirtualPathAttribute inside System.Web.Webpages.dll is used by Microsoft. I found out that it is used when you call ApplicationPart.Register and after that call, there’s not much you can use of this functionality without some heavy reflection. I know it’s the wrong path to choose, but did it anyway. I ended up creating a ViewEngine calling into ApplicationPart’s internal methods to output compiled views. It worked, but I didn’t like it much: there had to be a better way.

I then tried if I could hook into the BuildManager stuff that asp.net mvc uses to generate the views. It was actually much easier then expected, now why didn’t I go on that path the first time!

I ended up creating

  • a CompiledRazorBuildProvider, which inherits from the default RazorBuildProvider,
  • a CompiledVirtualPathProvider which returns a CompiledVirtualFile if it decides that a compiled view should be used
  • and a ApplicationPartRegistry, which registers which compiled views are available.

To view the source, head over to

To just get started without viewing the source, read on, I will explain step by step how to use this library with some screenshots.

If you have improvements, fork the project on GitHub and let me know! If you have suggestions for improvement, just drop it in the comments.

Step 1: Install the FileGenerator

Download and install the Visual Studio extension: http://visualstudiogallery.msdn.microsoft.com/en-us/f28290ce-d987-4f91-b034-707031e10ce6/file/39295/0/RazorSingleFileGenerator.vsix

Step 2: Create new mvc project

image

image

Step 3: Add a class library to hold the views

image

image

Step 4: Cut your Models & Views folders

image

Step 5: Paste them into the just created Class Library

image

Step 6: Copy the website’s web.config file

image

Step 7: Paste that web.config file into the class library

image

Step 8: Select all your .cshtml files in the class library and set the Custom Tool to ‘MvcRazorClassGenerator’

Does anyone have a suggestion on improving this step??

image

Step 9: Build your class library

Step 10: Add your class library to the references of the web application

image

image

Step 11: Add ‘Commons.web.mvc.precompiledviews.dll’ as a reference to your website

this dll is copied to the class library’s output folder (in this case ../EmbeddedViews/bin/debug’)

image

Step 12: Register your views by adding a line to the application_start in global.asax.cs

image

Step 13: Run your website!

Now, you will see the normal default website, even though there aren’t any views in your website path!

If you wish to override some views, just create the normal folders (eg /Views/Home) and add your views there, but don’t forget to copy back the deleted /Views/web.config back into your project then!

112 Responses to Compile your asp.net mvc Razor views into a seperate dll

  1. elvy says:

    Chris,

    I am using RazorSingleFileGenerator.vsix extension with MVC4 VS2010.

    Setting the custom tool to MvcRazorClassGenerator and compiling the class libary (step 8 & 9 above) doesn’t create the generated view files.

    Ran the ‘Run Custom tool’ option on one of the views to spot the issue. It errors out with:

    “The custom tool ‘MvcRazorClassGenerator’ failed. Could not load file or assembly ‘System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35′ or one of its dependencies. The system cannot find the file specified.

    Looks like the tool expects 1.0.0.0 of the version but I am using the latest. Probably the tool source is compiled with Specific Version set to true for this binary.

    Any solution would be greatly appreciated.

    Thanks,
    elvy

  2. elvee says:

    Chris,

    I earlier posted a question on the workings of this tool – RazorSingleFileGenerator.vsix (v1.05 or v1.07) with MVC4, but it looks like it has been deleted. Any issues?

    Regards.

  3. neelam says:

    I followed the steps specified and this works fine in one solution. i.e. my application project and embedded library project when both are in one solution.

    Can I use this across project? Can you give steps for the same?

  4. Kanag says:

    Dear Folks.

    I have no any compile time error and runtime error, but how can i set layout from EmbeddedViews Class library

    Thanks & Regards,
    kanag.M

  5. Happy says:

    Its not working in mvc 4 razor.
    Not getting Commons.web.mvc.precompiledviews.dll in class library in mvc 4 razor.

  6. Lelala says:

    Wow, great: Thanks for that idea! Cool.
    I liked the original post from David very much, but i missed exactly that opportunity – especially if you are doing somewhat automated deploys, its great help to have all stuff in an extra DLL :-)
    Thanks

  7. lalitha says:

    Hi Chris,

    We have MVC forum downloaded from codeplex.com. We wish to integrate it with a MVC 4 web project. How can we do that? We feel to create a DLL for Forum and to add its reference to MVC 4 web project. Can you help me in approach.

  8. Dheeraj says:

    Hello,

    Interesting and helpful article Chris. I am new to MVC development and have some trouble in separating views from the main MVC project. (I have already separated models from main MVC project.)

    Using Visual Studio 2012, Framework 4.5, MVC 3.0 application.

    I have followed all the steps mentioned in the post. Difference is, I am using .aspx pages in Views and the view engine is ASPX(C#)).

    In Step 8 (Select all your .cshtml files in the class library and set the Custom Tool to ‘MvcRazorClassGenerator’), after doing this I will get error since my view engine is ASPX(C#.) I am not able to do Step 11 and Step 12.

    If i run the application, will get this following error:

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

    Can anyone suggest some ideas to solve this please?

    Thanks in advance.
    Dheeraj

  9. Jay says:

    Chris, we dont have models in our project so, we are not going to register in global.asax.
    this application will work on this scenarios.

  10. Giovanni says:

    I’ve tried to develop a plugin but using the Visual Studio 2013 and Framework 4.5. But this version of the framework doesn’t work? I only can work just if I change to framework 4.0. Is there any solution for this?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>