ASP.NET MVC Razor:如何在控制器动作中渲染Razor Partial View的HTML
如何在ASP.NET视图引擎上生成给定的部分视图的HTML 是已知的 。
但是,如果在剃刀部分视图上使用此function,则不起作用,例外情况是部分视图不是从“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(); } }
虽然已经有了足够的答案,但是我想提出一个不太详细的解决scheme,可以在没有MVC控制器类中可用的帮助器方法的情况下使用。 使用称为“RazorEngine”的第三方库,您可以使用.Net文件IO获取razor文件的内容并调用
string html = Razor.Parse(razorViewContentString, modelObject);
在这里获取第三方库。
您也可以使用此处的RenderView Controller extension
( 源 )
并像这样使用它:
public ActionResult Do() { var html = this.RenderView("index", theModel); ... }
它适用于剃刀和网页forms的 viewengines
我看到有人想知道如何去做另一个控制器。
在我的情况下,我把所有的电子邮件模板都放在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
方法不会将直线path作为参数,它需要一个ControllerContext
。
一旦完成渲染string,它就会将AccountController返回到由Response对象使用的初始状态。
伟大的代码; 小提示:如果你有时不得不绕过更多的数据,而不仅仅是viewmodel ..
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)