How to Render Partial View into a String
I have the following code:
public ActionResult SomeAction()
{
return new JsonpResult
{
Data = new { Widget = "some partial html for the widget" }
};
}
I'd like to modify it so that I could have
public ActionResult SomeAction()
{
// will render HTML that I can pass to the JSONP result to return.
var partial = RenderPartial(viewModel);
return new JsonpResult
{
Data = new { Widget = partial }
};
}
is this possible? Could somebody explain how?
note, I edited the question before posting the solution.
Solution 1:
I opted for an extension method like the following for an ASP.NET MVC 4 app. I think it's simpler than some of the suggestions I've seen:
public static class ViewExtensions
{
public static string RenderToString(this PartialViewResult partialView)
{
var httpContext = HttpContext.Current;
if (httpContext == null)
{
throw new NotSupportedException("An HTTP context is required to render the partial view to a string");
}
var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString();
var controller = (ControllerBase)ControllerBuilder.Current.GetControllerFactory().CreateController(httpContext.Request.RequestContext, controllerName);
var controllerContext = new ControllerContext(httpContext.Request.RequestContext, controller);
var view = ViewEngines.Engines.FindPartialView(controllerContext, partialView.ViewName).View;
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
using (var tw = new HtmlTextWriter(sw))
{
view.Render(new ViewContext(controllerContext, view, partialView.ViewData, partialView.TempData, tw), tw);
}
}
return sb.ToString();
}
}
It allows me to do the following:
var html = PartialView("SomeView").RenderToString();
Also, this approach persists any Model, ViewBag and other view data for the view.
Solution 2:
This is a slightly modified version of an answer that works:
public static string RenderPartialToString(string controlName, object viewData)
{
ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
viewPage.ViewData = new ViewDataDictionary(viewData);
viewPage.Controls.Add(viewPage.LoadControl(controlName));
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
viewPage.RenderControl(tw);
}
}
return sb.ToString();
}
Usage:
string ret = RenderPartialToString("~/Views/MyController/MyPartial.ascx", model);
Solution 3:
DaveDev's answer worked well for me, however when the partial view calls another partial I get "Value cannot be null. Parameter name: view"
Searching around I have made a variant of the following that seems to work well.
public static string RenderPartialToString(string viewName, object model, ControllerContext ControllerContext)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewDataDictionary ViewData = new ViewDataDictionary();
TempDataDictionary TempData = new TempDataDictionary();
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
Usage:
String result = MVCHelpers.RenderPartialToString("PartialViewHere", Model, ControllerContext)
Solution 4:
You can create extension that render view into string.
public static class RenderPartialToStringExtensions
{
/// <summary>
/// render PartialView and return string
/// </summary>
/// <param name="context"></param>
/// <param name="partialViewName"></param>
/// <param name="model"></param>
/// <returns></returns>
public static string RenderPartialToString(this ControllerContext context, string partialViewName, object model)
{
return RenderPartialToStringMethod(context, partialViewName, model);
}
/// <summary>
/// render PartialView and return string
/// </summary>
/// <param name="context"></param>
/// <param name="partialViewName"></param>
/// <param name="viewData"></param>
/// <param name="tempData"></param>
/// <returns></returns>
public static string RenderPartialToString(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
{
return RenderPartialToStringMethod(context, partialViewName, viewData, tempData);
}
public static string RenderPartialToStringMethod(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
{
ViewEngineResult result = ViewEngines.Engines.FindPartialView(context, partialViewName);
if (result.View != null)
{
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter output = new HtmlTextWriter(sw))
{
ViewContext viewContext = new ViewContext(context, result.View, viewData, tempData, output);
result.View.Render(viewContext, output);
}
}
return sb.ToString();
}
return String.Empty;
}
public static string RenderPartialToStringMethod(ControllerContext context, string partialViewName, object model)
{
ViewDataDictionary viewData = new ViewDataDictionary(model);
TempDataDictionary tempData = new TempDataDictionary();
return RenderPartialToStringMethod(context, partialViewName, viewData, tempData);
}
}
And then use it in action
[HttpPost]
public ActionResult GetTreeUnit(string id)
{
int _id = id.ExtractID();
string render = ControllerContext.RenderPartialToString("SomeView");
return Json(new { data = render });
}
Solution 5:
Works perfect (Only view name required)
* for parameters you can use a model
* can call this from a view also
View side or Calling Side
BuyOnlineCartMaster ToInvoice1 = new BuyOnlineCartMaster(); // for passing parameters
ToInvoice1.CartID = 1;
string HtmlString = RenderPartialViewToString("PartialInvoiceCustomer", ToInvoice1);
Function Generating HTML
public class BuyOnlineCartMaster
{
public int CartID { get; set; }
}
public static string RenderPartialViewToString(string viewName, object model)
{
using (var sw = new StringWriter())
{
BuyOnlineController controller = new BuyOnlineController(); // instance of the required controller (you can pass this as a argument if needed)
// Create an MVC Controller Context
var wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
RouteData routeData = new RouteData();
routeData.Values.Add("controller", controller.GetType().Name
.ToLower()
.Replace("controller", ""));
controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
controller.ViewData.Model = model;
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.ToString();
}
}
Partial View page
@{
var ModelContents = (Common.BuyOnlineCartMaster)ViewData.Model;
}
Your cart id : @(ModelContents.CartID)