eWorld.UI - Matt Hawley

Ramblings of Matt

Using Razor Pages with WebForms Master Pages

January 7, 2011 14:56 by matthaw

There's been some recent chatter about mixing ASP.NET MVC with WebForms, which is something I'm all too familiar with. This setup works just fine, but what if you wanted to use the new Razor view engine within ASP.NET MVC? A bit of backstory.

 

On a secondary project that I work on within Microsoft, we were given the ability to rewrite the entire UI of the application in ASP.NET MVC. At that time, the first beta of MVC3 was rolling out and we decided to take our first plunge and use the Razor view engine. Unfortunately, the common UI layout that is shared across multiple properties that we had to use was WebForms based. Our attempts to convince the developers of the common UI components to support more of a modularized infrastructure failed for any foreseeable future, so we were left with the conundrum of figuring out an intermediary solution.

 

After discussions with the ASP.NET team to see if using a Razor view where it's layout was a WebForms master page was or could be a supported scenario - the general consensus being "No". The primary reason is that WebForms and Razor pages have a completely different architecture and runtime execution model (renders from a control tree vs. mostly-single pass template, respectively). However, what ASP.NET MVC does allow is context switching between view engines based on partials that are rendered. With that in mind, I decided to see if a partial based implementation could be achieved.

 

The solution is fairly simple, and provides an easy upgrade path if and when you could ditch the WebForms master page. We'll start by creating a few extensions to the controller for rendering Razor based views. The reason we're doing this, is so that a WebForms based view can be rendered, while you think you're rendering a Razor based view.

 

   1:  public static ViewResult RazorView(this Controller controller)
   2:  {
   3:      return RazorView(controller, null, null);
   4:  }
   5:   
   6:  public static ViewResult RazorView(this Controller controller, object model)
   7:  {
   8:      return RazorView(controller, null, model);
   9:  }
  10:   
  11:  public static ViewResult RazorView(this Controller controller, string viewName)
  12:  {
  13:      return RazorView(controller, viewName, null);
  14:  }
  15:   
  16:  public static ViewResult RazorView(this Controller controller, string viewName, object model)
  17:  {
  18:      if (model != null)
  19:          controller.ViewData.Model = model;
  20:   
  21:      controller.ViewBag._ViewName = GetViewName(controller, viewName);
  22:   
  23:      return new ViewResult
  24:      {
  25:          ViewName = "RazorView",
  26:          ViewData = controller.ViewData,
  27:          TempData = controller.TempData
  28:      };
  29:  }
  30:   
  31:  static string GetViewName(Controller controller, string viewName)
  32:  {
  33:      return !string.IsNullOrEmpty(viewName)
  34:          ? viewName
  35:          : controller.RouteData.GetRequiredString("action");
  36:  }

 

The thing to note from above, is that we're actually rendering a view called "RazorView" specifying the actual view to be rendered on ViewBag._ViewName. This value will later be used to render the appropriate RazorView.

Side note: This is a naive implementation of GetViewName assuming that if you do not specify the view name, you're rendering a view with the same action name from the route data. This may not be correct in all places, but seems to work reasonably well.

You'll also need to create a "RazorView" WebForms view in the Shared directory which inherits from your master page. This view will ultimately render the Razor view as a partial defined by your action result. I've also created a Razor layout page that all Razor views will use to alleviate the issue of having to touch each view if and when a conversion to only the Razor view engine takes place. You'll find each of the view files below.

 

Shared/Site.Master:

   1:  <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
   2:  <!DOCTYPE html>
   3:  <html>
   4:  <head runat="server">
   5:      <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
   6:  </head>
   7:  <body>
   8:      <div>
   9:          <asp:ContentPlaceHolder ID="MainContent" runat="server" />
  10:      </div>
  11:  </body>
  12:  </html>

Shared/_SiteLayout.cshtml:

   1:  @RenderBody()

Shared/RazorView.aspx:

   1:  <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
   2:      Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
   3:   
   4:  <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
   5:      <% Html.RenderPartial((string) ViewBag._ViewName); %>
   6:  </asp:Content>

Home/Index.cshtml:

   1:  @{
   2:      Layout = "~/Views/Shared/_SiteLayout.cshtml";
   3:  }
   4:   
   5:  <h2>This is the index page</h2>

 

What you'll notice, is that it's not possible to utilize Razor content sections to render different parts from the WebForms master page. However, you are able to use Razor content sections from the Razor layout file since you're in that model. If you do have to render multiple WebForm content sections, you may need to make things a bit more elaborate by specifying specific content areas manually. Ultimately, I wouldn't recommend that, and just try to limit your output to a main content panel.

 

Within your controller, your action result is simply:

   1:  public ActionResult Index()
   2:  {
   3:      return this.RazorView();
   4:  }

 

While this solution isn't optimal, it does allow you to utilize Razor views while still adhering to a common WebForms master page. If possible, I recommend not doing this, but sometimes (like in our solution) you have to do what is necessary. If your master pages are simple enough (and primarily just layout), I fully recommend having a WebForms master page and a Razor layout page. Regardless, the way this has been setup, migration to a Razor only architecture is fairly trivial - just simply change all this.RazorView() calls to View() calls and copy over your layout to _SiteLayout.cshtml.

 

Click here to download the source for this solution.



Comments

January 7. 2011 15:41

Pingback from topsy.com

Twitter Trackbacks for
        
        Using Razor Pages with WebForms Master Pages
        [eworldui.net]
        on Topsy.com

topsy.com

January 12. 2011 05:30

Hi,
I am planning to implement MVC in http://www.HRStop.com . I am sure this would be helpful.

Shekhar

January 14. 2011 11:29

Exactly what I was looking for. Thanks for the tips.

Criação de Sites

January 18. 2011 01:06

        
thank you

mcp certification

January 25. 2011 16:47

Mixing Razor Views and WebForms Master Pages with ASP.NET MVC 3

Scott Hanselman

January 26. 2011 15:53

It works like a charm. My only problem is the page title. My solution is:

In the Controller:
ViewBag._Title = "Admin";

In the RazorView.aspx:
<%
    if (ViewBag._Title != null)
        Page.Title = ViewBag._Title;
%>

Anybody got a better solutions, please share Laughing

Anders Nygaard

January 30. 2011 20:38

Pingback from pozitive.net

Mixing Razor Views and WebForms Master Pages with ASP.NET MVC 3 | Pozitive.NeT

pozitive.net

February 17. 2011 20:25

Jquery with mvc3

Jquery with mvc3

Crasch

July 26. 2011 07:27

用ASP.NET MVC3混合Razor视图和WebForms母版页

[原文发表地址] Mixing Razor Views and WebForms Master Pages with ASP.NET MVC 3 [原文发表时间] Jan 25, 2011 ,12:17

Scott Hanselman的中文博客

September 11. 2011 19:15

Pingback from programmersgoodies.com

RazorEngine: Possible to use in Webforms application? - Programmers Goodies

programmersgoodies.com

October 18. 2011 21:09

Pingback from sstringa.com

Integrating MVC into a LargeScale ASP.NET WebForms Application | stringa's Developer Blog

sstringa.com

January 24. 2012 16:17

Pingback from facecolony.org

Passing Title to WebForms Master Page from Razor Pages | FaceColony.org - Developers Network

facecolony.org

February 15. 2012 21:43

ASP.NET MVC 3, Razor-C#, and VB.NET WebForms - A Tale of Black Magic Voodoo

ASP.NET MVC 3, Razor-C#, and VB.NET WebForms - A Tale of Black Magic Voodoo

try-catch-FAIL

March 14. 2012 20:15

Pingback from stringa.co

Integrating MVC into a LargeScale ASP.NET WebForms Application | stringa's Developer Blog

stringa.co

June 21. 2013 14:05

Pingback from aaronprohaska.wordpress.com

Moving a large ASP.NET WebForms project to MVC 4 | Aaron Prohaska's Blog

aaronprohaska.wordpress.com

November 9. 2013 01:02

Pingback from jptab.com

Autoformating of inline code in MVC | Jptab

jptab.com

March 30. 2014 13:21

Pingback from devio.wordpress.com

Adding MVC 3 to an existing ASP.Net 4 Web Application | devioblog

devio.wordpress.com

Comments are closed

Copyright © 2000 - 2014 , Excentrics World