How to enable partial view inside web form

Some sites that I program use both ASP.NET MVC and WebForms.

I have a partial view and want to include it in a web form. A partial view has some code that needs to be processed on the server, so using Response.WriteFile does not work. It should work with javascript disabled.

How can i do this?

+78
asp.net-mvc webforms partial-views
Mar 31 '09 at 19:50
source share
7 answers

I looked at the source of MVC to find out if I can figure out how to do this. There seems to be a very close relationship between the controller context, views, view data, routing data, and html rendering methods.

Basically, for this to happen, you need to create all these additional elements. Some of them are relatively simple (for example, presentation data), but some of them are slightly more complicated - for example, routing data will take into account ignoring the current WebForms page.

The big problem is that the HttpContext - MVC pages are based on the HttpContextBase (and not on the HttpContext, such as WebForms), and although they both implement IServiceProvider, they are not related. MVC designers made a deliberate decision not to modify legacy WebForms to use the new context database, but they provided a wrapper.

This works and allows you to add a partial view to WebForm:

public class WebFormController : Controller { } public static class WebFormMVCUtil { public static void RenderPartial( string partialName, object model ) { //get a wrapper for the legacy WebForm context var httpCtx = new HttpContextWrapper( System.Web.HttpContext.Current ); //create a mock route that points to the empty controller var rt = new RouteData(); rt.Values.Add( "controller", "WebFormController" ); //create a controller context for the route and http context var ctx = new ControllerContext( new RequestContext( httpCtx, rt ), new WebFormController() ); //find the partial view using the viewengine var view = ViewEngines.Engines.FindPartialView( ctx, partialName ).View; //create a view context and assign the model var vctx = new ViewContext( ctx, view, new ViewDataDictionary { Model = model }, new TempDataDictionary() ); //render the partial view view.Render( vctx, System.Web.HttpContext.Current.Response.Output ); } } 

Then in your WebForm you can do this:

 <% WebFormMVCUtil.RenderPartial( "ViewName", this.GetModel() ); %> 
+96
Jul 02 '09 at 12:26
source share

It took some time, but I found a great solution. Keith's solution works for many people, but in certain situations it’s not the best, because sometimes you want your application to go through the controller process to render the view, and the Keith solution just displays the view with the given model. I’m introducing a new solution here, which will start the normal process.

The main steps:

  1. Create Utility Class
  2. Create a dummy controller with a dummy view
  3. On your aspx or master page call the utility method for partial rendering, passing the Controller, view and, if you need, the model to render (as an object),

Let's check this carefully in this example.

1) Create a class called MVCUtility and create the following methods:

  //Render a partial view, like Keith solution private static void RenderPartial(string partialViewName, object model) { HttpContextBase httpContextBase = new HttpContextWrapper(HttpContext.Current); RouteData routeData = new RouteData(); routeData.Values.Add("controller", "Dummy"); ControllerContext controllerContext = new ControllerContext(new RequestContext(httpContextBase, routeData), new DummyController()); IView view = FindPartialView(controllerContext, partialViewName); ViewContext viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextBase.Response.Output); view.Render(viewContext, httpContextBase.Response.Output); } //Find the view, if not throw an exception private static IView FindPartialView(ControllerContext controllerContext, string partialViewName) { ViewEngineResult result = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName); if (result.View != null) { return result.View; } StringBuilder locationsText = new StringBuilder(); foreach (string location in result.SearchedLocations) { locationsText.AppendLine(); locationsText.Append(location); } throw new InvalidOperationException(String.Format("Partial view {0} not found. Locations Searched: {1}", partialViewName, locationsText)); } //Here the method that will be called from MasterPage or Aspx public static void RenderAction(string controllerName, string actionName, object routeValues) { RenderPartial("PartialRender", new RenderActionViewModel() { ControllerName = controllerName, ActionName = actionName, RouteValues = routeValues }); } 

Create a class to pass parameters, I will call here RendeActionViewModel (you can create the MvcUtility class in the same file)

  public class RenderActionViewModel { public string ControllerName { get; set; } public string ActionName { get; set; } public object RouteValues { get; set; } } 

2) Now create a controller named DummyController

  //Here the Dummy controller with Dummy view public class DummyController : Controller { public ActionResult PartialRender() { return PartialView(); } } 

Create a Dummy view named PartialRender.cshtml ( PartialRender.cshtml view) for the DummyController with the following contents, note that it will perform another rendering action using the Html helper.

 @model Portal.MVC.MvcUtility.RenderActionViewModel @{Html.RenderAction(Model.ActionName, Model.ControllerName, Model.RouteValues);} 

3) Now just put this in a MasterPage or aspx file to partially display the desired view. Note that this is a great answer when you have several types of razors that you want to mix with your MasterPage or aspx pages. (Suppose we have a PartialView called Login for Controller Home).

  <% MyApplication.MvcUtility.RenderAction("Home", "Login", new { }); %> 

or if you have a model to go into action

  <% MyApplication.MvcUtility.RenderAction("Home", "Login", new { Name="Daniel", Age = 30 }); %> 

This is a great solution, it does not use an ajax call , which does not cause deferred rendering for nested views, does not create a new WebRequest, so it will not bring you a new session and will process the method to retrieve. ActionResult for the view you need, it works without going through any model

Using MVC RenderAction in a Web Form

+34
Jul 21 '14 at 2:06
source share

The most obvious way is through AJAX

something like this (using jQuery)

 <div id="mvcpartial"></div> <script type="text/javascript"> $(document).load(function () { $.ajax( { type: "GET", url : "urltoyourmvcaction", success : function (msg) { $("#mvcpartial").html(msg); } }); }); </script> 
+20
Mar 31 '09 at 20:22
source share

This is great, thanks!

I am using MVC 2 on .NET 4, which requires TextWriter to be passed to ViewContext, so you need to pass httpContextWrapper.Response.Output as shown below.

  public static void RenderPartial(String partialName, Object model) { // get a wrapper for the legacy WebForm context var httpContextWrapper = new HttpContextWrapper(HttpContext.Current); // create a mock route that points to the empty controller var routeData = new RouteData(); routeData.Values.Add(_controller, _webFormController); // create a controller context for the route and http context var controllerContext = new ControllerContext(new RequestContext(httpContextWrapper, routeData), new WebFormController()); // find the partial view using the viewengine var view = ViewEngines.Engines.FindPartialView(controllerContext, partialName).View as WebFormView; // create a view context and assign the model var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextWrapper.Response.Output); // render the partial view view.Render(viewContext, httpContextWrapper.Response.Output); } 
+10
Sep 12 '11 at 21:11
source share

Here is a similar approach that worked for me. The strategy is to display a partial view of the line and then display it on the WebForm page.

  public class TemplateHelper { /// <summary> /// Render a Partial View (MVC User Control, .ascx) to a string using the given ViewData. /// http://www.joeyb.org/blog/2010/01/23/aspnet-mvc-2-render-template-to-string /// </summary> /// <param name="controlName"></param> /// <param name="viewData"></param> /// <returns></returns> public static string RenderPartialToString(string controlName, object viewData) { ViewDataDictionary vd = new ViewDataDictionary(viewData); ViewPage vp = new ViewPage { ViewData = vd}; Control control = vp.LoadControl(controlName); vp.Controls.Add(control); StringBuilder sb = new StringBuilder(); using (StringWriter sw = new StringWriter(sb)) { using (HtmlTextWriter tw = new HtmlTextWriter(sw)) { vp.RenderControl(tw); } } return sb.ToString(); } } 

On the codebehind page you can do

 public partial class TestPartial : System.Web.UI.Page { public string NavigationBarContent { get; set; } protected void Page_Load(object sender, EventArgs e) { NavigationVM oVM = new NavigationVM(); NavigationBarContent = TemplateHelper.RenderPartialToString("~/Views/Shared/NavigationBar.ascx", oVM); } } 

and on the page you will have access to the provided content

 <%= NavigationBarContent %> 

Hope this helps!

+5
Aug 14 2018-11-11T00:
source share

This solution takes a different approach. It defines a System.Web.UI.UserControl that can be hosted on any web form and configured to display content from any URL ... including a partial view of MVC. This approach is similar to calling AJAX for HTML in that parameters (if any) are provided via the URL query string.

First define a user control in two files:

/controls/PartialViewControl.ascx file

 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="PartialViewControl.ascx.cs" Inherits="PartialViewControl" %> 

/controls/PartialViewControl.ascx.cs:

 public partial class PartialViewControl : System.Web.UI.UserControl { [Browsable(true), Category("Configutation"), Description("Specifies an absolute or relative path to the content to display.")] public string contentUrl { get; set; } protected override void Render(HtmlTextWriter writer) { string requestPath = (contentUrl.StartsWith("http") ? contentUrl : "http://" + Request.Url.DnsSafeHost + Page.ResolveUrl(contentUrl)); WebRequest request = WebRequest.Create(requestPath); WebResponse response = request.GetResponse(); Stream responseStream = response.GetResponseStream(); var responseStreamReader = new StreamReader(responseStream); var buffer = new char[32768]; int read; while ((read = responseStreamReader.Read(buffer, 0, buffer.Length)) > 0) { writer.Write(buffer, 0, read); } } } 

Then add the user control to the page of your web form:

 <%@ Page Language="C#" %> <%@ Register Src="~/controls/PartialViewControl.ascx" TagPrefix="mcs" TagName="PartialViewControl" %> <h1>My MVC Partial View</h1> <p>Below is the content from by MVC partial view (or any other URL).</p> <mcs:PartialViewControl runat="server" contentUrl="/MyMVCView/" /> 
+3
Jun 10 '14 at 23:05
source share

By the way, I needed to be able to dynamically render a partial view from an existing web form code and paste it at the top of this control. I found that Keith's answer might trigger a partial view outside of <html/> .

Using Keith and Hilarius' answers for inspiration, instead of drawing directly HttpContext.Current.Response.Output, I rendered the html string and added it as LiteralControl to the appropriate control.

In a static helper class:

  public static string RenderPartial(string partialName, object model) { //get a wrapper for the legacy WebForm context var httpCtx = new HttpContextWrapper(HttpContext.Current); //create a mock route that points to the empty controller var rt = new RouteData(); rt.Values.Add("controller", "WebFormController"); //create a controller context for the route and http context var ctx = new ControllerContext(new RequestContext(httpCtx, rt), new WebFormController()); //find the partial view using the viewengine var view = ViewEngines.Engines.FindPartialView(ctx, partialName).View; //create a view context and assign the model var vctx = new ViewContext(ctx, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), new StringWriter()); // This will render the partial view direct to the output, but be careful as it may end up outside of the <html /> tag //view.Render(vctx, HttpContext.Current.Response.Output); // Better to render like this and create a literal control to add to the parent var html = new StringWriter(); view.Render(vctx, html); return html.GetStringBuilder().ToString(); } 

In the calling class:

  internal void AddPartialViewToControl(HtmlGenericControl ctrl, int? insertAt = null, object model) { var lit = new LiteralControl { Text = MvcHelper.RenderPartial("~/Views/Shared/_MySharedView.cshtml", model}; if (insertAt == null) { ctrl.Controls.Add(lit); return; } ctrl.Controls.AddAt(insertAt.Value, lit); } 
0
Mar 07 '19 at 12:19
source share



All Articles