ASP.NET MVC 3 Razor Views in SharePoint
ASP.NET MVC 3 has just been released, and I really like the new Razor syntax for views. However, I work with SharePoint, which is solidly based on WebForms and .NET 3.5. Razor requires .NET 4, and while you can host WebForms MVC pages in _layouts, it’s an ugly hack that gives you the worst features of both systems.
Razor is internally quite different from WebForms, and the core functionality doesn’t actually require MVC, so it should be possible to use it in a system that can’t use MVC.
My first attempt to make Razor work under SharePoint was to see if it would compile without .NET 4. That didn’t work, but I did notice that most of the dependencies on .NET 4 are in parsing the templates - you can’t build cshtml files without .NET 4, but the generated code doesn’t require anything special.
Starting with the code from http://razorengine.codeplex.com/ I was able to convert a cshtml file into a cs file that can be compiled in a .NET 3.5 project. My version of the code is at https://github.com/tqc/RazorEngine.
RazorEngine came pretty close to what I needed, only requiring fairly minor changes:
Add methods to return the generated source code rather than compiling and running it
Copy the template base classes into a .NET 3.5 library (RazorEngine.Run). This meant removing support for dynamic objects, but apart from that the code doesn’t require the latest version.
I set up a console app (GenerateViewCode) that will generate code files for all cshtml files in a project. I considered using a single file generator, but a console app is easier to debug and more likely to work properly on a build server. It is intended to be set up as an external tool in Visual Studio:
Arguments (base class for views): RazorEngine.Templating.TemplateBase
Initial Directory: $(ProjectDir)
After you run the tool on a project containing cshtml files and include the generated code in the project, you will be able to render the view from your code:
var view = new TestViewLibrary.Views.Shared.DocView() view.Model = newTestViewLibrary.Models.DocSection(); view.Execute(); ParentControl.Controls.Add(new LiteralControl(View.Result));
This replaces either trying to build html in code (with code that looks a lot like the generated output from Razor) or finding and loading a usercontrol in _layouts.
MVC isn’t just about the view though - more on that shortly.