Saturday, August 6, 2011

Asp.Net MVC3 and Asp.Net Web Forms Side-By-Side in One Project - With Razor Views

In The previous post, I explained how we could use MVC3 and Asp.Net Web Forms Side-By-Side in One Project.  In that post, we were rendering MVC3 pages using the ASPX View Engine.  ASPX View Engine is the legacy view engine, Razor View Engine has significant advantages over the ASPX View Engine.  In this post we will see how we could use the Razor View Engine instead of the ASPX View Engine. 

The Asp.Net MVC 3 has always supported the concept of view engines – which are the pluggable modules that implement different template syntax options.  Razor view engine is optimized around HTML generation using a code-focused templating approach.

Why Razor View engine?

Razor View engine is build with the following design goals (read the detail design goals here)
  • Compact, Expressive, and Fluid: Razor minimizes the number of characters and keystrokes required in a file, and enables a fast, fluid coding workflow. Unlike most template syntax's, you do not need to interrupt your coding to explicitly denote server blocks within your HTML. The parser is smart enough to infer this from your code. This enables a really compact and expressive syntax which is clean, fast and fun to type.
  • Easy to Learn: Razor is easy to learn and enables you to quickly be productive. You use all your existing language and HTML skills.
  • Is not a new language: Razor enables developers to use their existing C#/VB (or other) language skills and deliver a template markup syntax that enables an awesome HTML construction workflow with language of our choice.
  • Works with any Text Editor: Razor doesn’t require a specific tool and enables you to be productive in any plain old text editor (notepad works great).  That said, I have to mention this, Resharper 6.0 has one of the best support for Razor Syntax.  Its a paid tool but its definitely worth the price.
  • Has great Intellisense: While Razor has been designed to not require a specific tool or code editor, it will have awesome statement completion support within Visual Studio.
  • Unit Testable: This is one of the most important Design Goal.  Razor implementation supports the ability to unit test views (without requiring a controller or web-server and can be hosted in any unit test project – no special app-domain required).
If you want to see a detailed reasoning of why Razor is better then ASPX View Engine, I strongly recommend vising this link

Now that we are convinced that, Razor View Engine is better than ASPX View Engine, lets integrate the Razor views in our Asp.Net Web Forms application with MVC3 integrated in it.

How Do they do it?

Initially, I though there must be setting somewhere in the project properties which will enable us to use the Razor View Engine, however, after several wasteful minutes of searching and researching in the project properties I found that, there is no such setting, we can directly go ahead and create the Razor view in the project.

Razor views have an extension of cshtml.  Lets create our first Razor view called RazorIndex.cshtml right next to the Index.aspx that we had created in the previous post.  This view will have nothing special, it will display one message that we set in the ViewBag.

Notice that we are displaying the UserName from the ViewBag.  Notice that, in the new Razor syntax, we have to use the @ sign to access any objects and properties.

Let's add one more method in our HomeController which will render the RazorIndex view and set the UserName in the ViewBag.  The controller code will look no different from how it looked for rendering ASPX pages.

This is a very good example of showing, how well the Seperation of Concerns Design Pattern has been implemented in MVC3.  Even though we want to use a different View Engine, controller code remains unchanged.  In fact, Controller has no idea about which View Engine will be used to render the view.  This is an excellent example of why things should be loosely coupled to achieve modular and clean code!

Before we can see if our Razor view is rendered correctly or not let's not forget to add one more route to our routes collection in Global.asax.cs file

We have just added one route called RazorHome. All set! Lets build the project and access the URL /home/razorindex and see whats the outcome.
First attempt to render Razor View results in an compilation error
OK does not look too good.  The error states that The type or namespace name 'Helpers' does not exist in the namespace 'System.Web'  To fix this we will have to do a change in the web.config.  We will need to add a few assemblies in the  <system.web><compilation> section.  The updated web.config would look like

After this lets build and access the URL /home/razorindex and les see what happens
Second attempt at rendering the Razor view also results in compilation error, this time it cribs for ViewBag
Still not quite there, but getting closer.  This time the error says that The name 'ViewBag' does not exist in the current context.  The problem is that the compiled class RazorIndex_cshtml is extending System.Web.WebPages.WebPage class.  As we had seen in the previous post, MVC views needs to extend from System.Web.Mvc.WebViewPage and not System.Web.WebPages.WebPage. 

How do we fix this issue?

We need to some how tell the framework that the Razor pages should extend System.Web.Mvc.WebViewPage class.  This is done by adding another web.config in the Views directory.  The project structure would now look like this
Project Structure with two web.config's
The content of this new web.config should look like

The element <pages pageBaseType="System.Web.Mvc.WebViewPage"> tells that, the Razor views will have base class of System.Web.Mvc.WebViewPage.

Lets Rebuild the app and browse the URL /home/razorindex and see what happens.
Success! Razor view renders correctly
Bingo!  We have an Asp.Net Web Forms application with MVC3 Razor views integrated in it!

PS: Now you have no reason to not move to ASP.NET MVC3 from Web Forms, we have proved that MVC3 can co-exist with a Web Forms in the same project!
Have some Fun!