Click here to Skip to main content
13,145,068 members (54,833 online)
Click here to Skip to main content
Add your own
alternative version

Stats

6.2K views
117 downloads
20 bookmarked
Posted 29 Aug 2017

Mixing WebForms and MVC Razor Views

, 10 Sep 2017
Rate this:
Please Sign up or sign in to vote.
Old and new style all in one project

Intro

I was asked to maintain and extend a WebForms application. My first reaction was migrate to MVC, but Dave Paquette explains very well why this is usually a bad idea. Migrating is expensive, takes much time and creates a lot of risk. WebForms was launched in 2001 and is now slowly dying. Sure, it will be supported by Microsoft for many years to come. So what to do with the WebForms application? Adding new features with a dying technology feels wrong. After some googling I found that you can mix WebForms and MVC. Well that's a good a start. With a bit of luck I can build the new stuff with MVC. The material I found on the web, was quite old and did not work, but they gave a good direction. I started coding and the result was even simpler than I could have imaged. In this blog I share my findings on how you can mix WebForms and MVC Razor Views in one web application.

The Problem

From Visual Studio 2013 and later you can mix WebForms and MVC Razor views in one application. The application has two render engines and the routing takes care for selecting the correct render engine.

public class RazorDemoController : Controller
{
  public ActionResult Index()
  {
    return View();
  }
...

Here starts the problem. The razor view has no Master Page knowledge. The Master Page is the WebForms way for creating a site layout. In MVC the layout is set by a Razor Layout Page. These two types don't mix  and the result is a "standalone" page.

The Solution

I start with the solution and explain the steps how to get there.

The actual work is done by the RazorController base class and makes coding fairly simple, render a RazorView() instead of a normal View().

public class RazorDemoController : RazorController
 {
   public ActionResult Index()
   {
     return RazorView();
   }

How it works

Fooling the application to render a Razor view in a Web Form is the solution.

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="RazorContent" ContentPlaceHolderID="MainContent" runat="server">
  <% Html.RenderPartial((String)ViewBag.ViewName); %>
</asp:Content>

The RazorView.aspx is the Web Form and has a content placeholder for the Razor view. Please note I tweaked Inherits= from "System.Web.UI.Page" to "System.Web.Mvc.ViewPage". This little tweak selects the MVC render engine in Html.RenderPartial instead of the default WebForms engine and does the trick. The RazorView.aspx is located in the Shared Views area and is available for all Razor views.

Passing ViewName

The Html.RenderPartial needs the Razor viewname to render. The RazorView.aspx is a shared page and has no knowledge which view to render and we need some way to pass the viewname. The RazorView.aspx descends from Mvc.ViewPage and has the ViewBag property. The ViewBag is accessible from the controller so we have found a way for passing the view name to Html.RenderPartial  in the RazorView.aspx page.

RazorController

The RazorController encapsulates all the required code:

public class RazorController : Controller
 {
   public ActionResult RazorView(String viewName, Object model)
   {
     // pass the viewname to RazorView.aspx
     // the view will be rendered as partial view
     ViewBag.ViewName = viewName;

     return View("RazorView", model);
   }

   public ActionResult RazorView(Object model)
   {
     return RazorView(GetCurrentViewName(), model);
   }

   public ActionResult RazorView(String viewName)
   {
     return RazorView(viewName, null);
   }

   public ActionResult RazorView()
   {
     return RazorView(GetCurrentViewName(), null);
   }

   private String GetCurrentViewName()
   {
     var result = $"{Url.RequestContext.RouteData.Values["action"]}";

     return result;
   }
 }

The RazorView() method has several overloads. If the view name is omitted the function GetCurrentViewName() takes the current action name as the viewname.

RazorDemoController inherits from the RazorController and as you can see the RazorView methods are now easy to use.

public class RazorDemoController : RazorController
  {
    public ActionResult Index()
    {
      return RazorView();
    }


    // Example render some other view
    public ActionResult RenderOtherView()
    {
      return RazorView("Hello");
    }

    // Example Render view with Model
    public ActionResult Customer(Int32 id)
    {
      var model = new Customer()
      {
        Id = id,
        Name = "Company ABC",
        City = "The One that never sleeps"
      };

      return RazorView(model);
    }

    [HttpGet]
    public ActionResult SomeAjaxCall(Int32 id)
    {
      var model = new Customer()
      {
        Id = id,
        Name = "Company ABC",
        City = "The One that never sleeps"
      };

      return View("Customer", model);
    }
  }

The associated RazorView calls

<div>
  <h3>I am really a MVC Razor view in a WebForms world</h3>
</div>
<div>
  <h3>Hi there...</h3>
</div>
@model Models.Customer

<div>
  <h3>Customer</h3>
  <p>Id : <strong>@Model.Id</strong>
  <p>Name : <strong>@Model.Name</strong>
  <p>City : <strong>@Model.City</strong>

</div>

Customer.cshtml renders to:

Visual Studio Project Setup

"Old" WebForms applications are not configured for both WebForms and MVC. Migrating the solution to the latest Visual Studio will not solve this problem. You can add extra MVC references to the existing project or move all your forms to a new project. What works best for you is hard to tell. If you create a new WebForms project make sure you set the MVC reference.

Step 1 Setup dual WebForms MVC project

Choose Web Forms and add the MVC reference

Step 2

A new project is created with all the required references for the dual render engine. You can use it as an example for upgrading the existing solution or as the new solution.

 jQuery and Ajax

Another option is jQuery with Ajax. The concept is easy, create a div element in the Web Form page and get the contents with an Ajax call to the MVC controller and illustrated in the next example. The Web Form AjaxDemo.aspx invokes action SomeAjaxCall on controller RazorDemo and loads the content in the div razorViewContent.

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="AjaxDemo.aspx.cs" 

Inherits="WebForm.WebForms.AjaxDemo" %>

<asp:Content ID="content" ContentPlaceHolderID="MainContent" runat="server">
  <h3>Ajax demo</h3>

  <%--Setup place holder for Razor MVC view content--%>
  <div id="razorViewContent">
  </div>

  <script type="text/javascript">
    $(function () {

      // Call MCV view on document completed
      $.ajax({
        type: "Get",
        url: "/RazorDemo/SomeAjaxCall",        
        data: 'id=55',              
        success: function (document) {
          $('#razorViewContent').html(document);
        }
      }); 
    });
</script>

</asp:Content>

Controller implementation:

[HttpGet]
   public ActionResult SomeAjaxCall(Int32 id)
   {
     var model = new Customer()
     {
       Id = id,
       Name = "Company ABC",
       City = "The One that never sleeps"
     };

     return View("Customer", model);
   }

The Ajax approach has one drawback, it takes one extra file web form file for the same result, although I can image situations where the Ajax principle is really convenient.

Dot Net Core Options

If you want to mix MVC and WebForms on Dot Net Core, you have no luck. There is no WebForms support on Dot Net Core, so mixing is out of the question.

Conclusion

WebForms and MVC Razor views perfectly mix together and provides possibilities to extend existing WebForms application with new MVC techniques. Mixing can be done by rendering a Razor view as a Web Form page or use jQuery and Ajax and render a div element with MVC content. Both options use the original site layout. Which method is best is up to you.

 

Version History

1.0.02017 July Initial version
 1.0.1 2017 august Minor text changes. Source code cleaned

Further Reading and thanks to

So you inherited an ASP.NET Web Forms application

Dino Esposito Mixing WebForms and MVC

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

Matthaw Using Razor Pages with WebForm Master Pages

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Bart-Jan Brouwer
Technical Lead
Netherlands Netherlands
I graduated as Bachelor of Mechanical Engineering. Soon I moved from mechanical to software engineering. With more than 20 years of experience in software design, development, and architecture I love building software that users enjoy en suit their needs.

You may also be interested in...

Pro

Comments and Discussions

 
GeneralMy vote of 5 Pin
Carsten V2.030-Aug-17 4:27
memberCarsten V2.030-Aug-17 4:27 
GeneralRe: My vote of 5 Pin
Bart-Jan Brouwer31-Aug-17 4:49
memberBart-Jan Brouwer31-Aug-17 4:49 
QuestionDownload Pin
Nelek29-Aug-17 20:46
protectorNelek29-Aug-17 20:46 
AnswerRe: Download Pin
Bart-Jan Brouwer1-Sep-17 1:36
memberBart-Jan Brouwer1-Sep-17 1:36 
GeneralRe: Download Pin
Nelek1-Sep-17 9:16
protectorNelek1-Sep-17 9:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170915.1 | Last Updated 11 Sep 2017
Article Copyright 2017 by Bart-Jan Brouwer
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid