Render .ascx-Files in ASP.NET MVC Using Only RazorViewEngine

If you're stuck in an environment where you're migrating from ASP.NET MVC to ASP.NET WebForms it's good to know that you can actually render your existing WebForms-Controls in you MVC-views. This might sound like a crazy thing to do (and it is in the long run!) but it might be useful if you're stuck between sprints and have perfectly working WebForms-Controls (.ascx-files) that you don't have time to migrate right now. All you have to do is use the HtmlHelper's helper-method .RenderPartial(string partialViewName) and pass it the path to the WebForms-Control.

// Write the content of a control inside a view:
Html.RenderPartial("~/Controls/ControlVirtualPath.ascx");

// Or to get the content of a control as a MvcHtmlString, for further manipulation:
Html.Partial("~/Controls/CustomControl.ascx")

It's important that your controls inherits from System.Web.Mvc.ViewUserControl and NOT the old System.Web.UI.UserControl.

One performance-tip that is often mentioned around ASP.NET MVC is to deactivate the WebForms-View Engine for MVC Razor-views (which actually turns out to maybe not make such a big difference after all). This will not prevent .aspx, .ascx and other WebForms-files from working.

But you still want your .ascx-files to work inline in your MVC Razor-views. This can be achieved by implementing your own class that inherits RazorViewEngine, which only uses the WebFormViewEngine when actually needed.

Global.asax (or other config-class)

// Remove WebFormViewEngine (and RazorViewEngine)
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomRazorViewEngine());

CustomRazorViewEngine : System.Web.Mvc.RazorViewEngine

private static readonly WebFormViewEngine WebFormsEngine = new WebFormViewEngine();

public override ViewEngineResult FindPartialView(
    ControllerContext context, string name, bool useCache)
{
    if (name.EndsWith(".ascx"))
    {
        return WebFormsEngine.FindPartialView(context, name, useCache);
    }

    return base.FindPartialView(context, name, useCache);
}

If you need the actual class of the control to do some further analysis/manipulation, you can do the following anywhere in your code:

var viewPage = new ViewPage();
var control = viewPage.LoadControl("~/Controls/ControlVirtualPath.ascx") as ControlType;
Comments