如何在 ASP.NET 视图引擎 is known 上生成给定局部视图的 HTML。
但是,如果在剃刀局部视图上使用此功能,则它不起作用,因为异常表示局部视图不是从“UserControl”派生的。
如何修复渲染以支持剃刀局部视图?
我需要这个,因为我从这个部分视图生成电子邮件......
更新:
失败的代码(@mcl):
public string RenderPartialToString(string controlName, object viewData)
{
ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
viewPage.Url = this.GetUrlHelper();
string fullControlName = "~/Views/Email/" + controlName + ".ascx";
viewPage.ViewData = new ViewDataDictionary(viewData);
viewPage.Controls.Add(viewPage.LoadControl(fullControlName));
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
viewPage.RenderControl(tw);
}
}
return sb.ToString();
}
@Html.Partial("nameOfPartial", Model)
更新
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
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();
}
}
尽管已经给出了足够的答案,但我想提出一个不那么冗长的解决方案,它可以在没有 MVC 控制器类中可用的辅助方法的情况下使用。使用名为“RazorEngine”的第三方库,您可以使用 .Net 文件 IO 获取 razor 文件的内容并调用
string html = Razor.Parse(razorViewContentString, modelObject);
获取第三方库 here。
您也可以使用 here (source) 中的 RenderView Controller extension
并像这样使用它:
public ActionResult Do() {
var html = this.RenderView("index", theModel);
...
}
它适用于剃须刀和网络表单视图引擎
我看到有人想知道如何为另一个控制器做这件事。
在我的例子中,我的所有电子邮件模板都在 Views/Email 文件夹中,但您可以修改它以传入您有关联视图的控制器。
public static string RenderViewToString(Controller controller, string viewName, object model)
{
var oldController = controller.RouteData.Values["controller"].ToString();
if (controller.GetType() != typeof(EmailController))
controller.RouteData.Values["controller"] = "Email";
var oldModel = controller.ViewData.Model;
controller.ViewData.Model = model;
try
{
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName,
null);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
//Cleanup
controller.ViewData.Model = oldModel;
controller.RouteData.Values["controller"] = oldController;
return sw.GetStringBuilder().ToString();
}
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
throw ex;
}
}
本质上,它的作用是获取一个控制器,例如 AccountController 并将其修改为认为它是一个 EmailController,以便代码将在 Views/Email
文件夹中查找。这样做是必要的,因为 FindView
方法不采用直接向上的路径作为参数,它需要一个 ControllerContext
。
完成字符串的呈现后,它将 AccountController 返回到其初始状态,以供 Response 对象使用。
很棒的代码;小提示:如果您有时必须绕过更多数据而不仅仅是视图模型..
if (model is ViewDataDictionary)
{
controller.ViewData = model as ViewDataDictionary;
} else {
controller.ViewData.Model = model;
}
借用@jgauffin 答案作为 HtmlHelper 扩展:
public static class HtmlHelperExtensions
{
public static MvcHtmlString RenderPartialViewToString(
this HtmlHelper html,
ControllerContext controllerContext,
ViewDataDictionary viewData,
TempDataDictionary tempData,
string viewName,
object model)
{
viewData.Model = model;
string result = String.Empty;
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);
result = sw.GetStringBuilder().ToString();
}
return MvcHtmlString.Create(result);
}
}
剃刀视图中的用法:
Html.RenderPartialViewToString(ViewContext, ViewData, TempData, "Search", Model)