ASP.NET MVC Razor: Wie man den HTML-Code einer Razor Partial View in der Controller-Aktion rendert

Es ist bekannt, wie ein HTML einer bestimmten Teilansicht der ASP.NET-View-Engine generiert wird .

Wenn diese functionalität jedoch in der Rasierer-Teilansicht verwendet wird, funktioniert sie nicht, da die Ausnahme besagt, dass die Teilansicht nicht von “UserControl” stammt.

Wie behebt man das Rendering, um die partielle Ansicht des Rasierers zu unterstützen?

Ich brauche das, weil ich aus diesen Teilansichten E-Mails erzeuge …

AKTUALISIEREN:

Code, der fehlschlägt (@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) 

Aktualisieren

 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(); } } 

Obwohl bereits ausreichende Antworten gegeben wurden, möchte ich eine weniger ausführliche Lösung vorschlagen, die ohne die in einer MVC-Controller-class verfügbaren Hilfsmethoden verwendet werden kann. Mit einer Drittanbieter-Bibliothek namens “RazorEngine” können Sie .Net-Datei IO verwenden, um den Inhalt der Rasiererdatei abzurufen und aufzurufen

 string html = Razor.Parse(razorViewContentString, modelObject); 

Holen Sie sich die Third-Party-Bibliothek hier .

Sie können hier auch die RenderView Controller extension ( Quelle )

und benutze es so:

 public ActionResult Do() { var html = this.RenderView("index", theModel); ... } 

Es funktioniert für Rasierer und Web- Forms View Engines

Ich habe gesehen, dass jemand sich gefragt hat, wie man es für einen anderen Controller macht.

In meinem Fall hatte ich alle meine E-Mail-Vorlagen im Ordner “Ansichten / E-Mail”, aber Sie konnten diese ändern, um sie an den Controller zu übergeben, mit dem Sie Ansichten verknüpft haben.

 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; } } 

Im Wesentlichen ist dies ein Controller wie AccountController und ändern Sie es zu denken, dass es ein EmailController ist, so dass der Code in den Views/Email Ordner aussehen wird. Dies ist erforderlich, da die FindView Methode keinen geraden Pfad als Parameter benötigt, sondern einen ControllerContext .

Sobald das Rendern der Zeichenfolge abgeschlossen ist, wird der AccountController wieder auf seinen ursprünglichen Zustand zurückgesetzt, um vom Response-Objekt verwendet zu werden.

toller Code; kleiner Tipp: wenn man manchmal mehr Daten umgehen muss und nicht nur das Viewmodel ..

  if (model is ViewDataDictionary) { controller.ViewData = model as ViewDataDictionary; } else { controller.ViewData.Model = model; } 

@Jgauffin-Antwort als HtmlHelper-Erweiterung entlehnen:

 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); } } 

Verwendung in einer Rasierklingenansicht:

 Html.RenderPartialViewToString(ViewContext, ViewData, TempData, "Search", Model)