2014-05-06 10 views
16

Es scheint, die meisten Code für Blick in String-Rendering funktioniert nicht in MVC 5.MVC 5 Render Blick auf String

Ich habe neuesten MVC 5.1.2 Vorlagen und ich versuche, Blick in Zeichenfolge zu machen.

public static String RenderViewToString(ControllerContext context, String viewPath, object model = null) 
    { 
     context.Controller.ViewData.Model = model; 
     using (var sw = new StringWriter()) 
     { 
      var viewResult = ViewEngines.Engines.FindView(context, viewPath, null); 
      var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw); 
      viewResult.View.Render(viewContext, sw); 
      viewResult.ViewEngine.ReleaseView(context, viewResult.View); 
      return sw.GetStringBuilder().ToString(); 
     } 
    } 

Nun, es funktioniert, aber seine Ausgabe enthält viele $ Marken statt Tags. Ich habe gelesen, dass es in der RC-Version behoben wurde, aber das sind alte Nachrichten.

Problem sieht wie folgt aus

<$A$><h1></h1> 
<table</$A$><$B$> class=""</$B$><$C$>> <tbody</$C$><$D$></$D$><$E$>></tbody> 
</table></$E$> 

Ich möchte Sie fragen, wie Sie Ansichten in Zeichenfolge in neueste MVC 5 Vorlage machen Sie? Danke.

+0

Ist das ein Duplikat http://stackoverflow.com/questions/18387499/render-razor-view-to-string-without-munging-the-html?rq=1? – Sentinel

Antwort

23

Ok, scheint ich eine Lösung gefunden. Autor der Idee ist Yakir Manor.

class FakeController : ControllerBase 
{ 
    protected override void ExecuteCore() { } 
    public static string RenderViewToString(string controllerName, string viewName, object viewData) 
    { 
     using (var writer = new StringWriter()) 
     { 
      var routeData = new RouteData(); 
      routeData.Values.Add("controller", controllerName); 
      var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController()); 
      var razorViewEngine = new RazorViewEngine(); 
      var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false); 

      var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer); 
      razorViewResult.View.Render(viewContext, writer); 
      return writer.ToString(); 

     } 
    } 
} 

Es ist ein Trick mit falschem Kontext und Antwort.

Beispiel:

String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel); 

Meine Datei MyHTMLView.cstml in Views/Email/MyHTMLView.cshtml gespeichert ist. E-Mail ist ein gefälschter Controller-Name.

+0

Hallo, ich habe versucht, diese Lösungen es funktioniert gut für normale Ansichten. aber nicht für Ansichten im Bereich funktioniert, keine Ahnung, was damit zu tun, diese Fehler Wert kann nicht null sein. Parametername: view Beschreibung: Bei der Ausführung der aktuellen Webanforderung ist eine nicht behandelte Ausnahme aufgetreten. Bitte überprüfen Sie die Stack-Trace für weitere Informationen über den Fehler und wo es aus dem Code stammt. Ausnahmedetails: System.ArgumentNullException: Wert kann nicht null sein. Parametername: view on var viewContext = neuer ViewContext ... – Alok

+0

@Alok, weiß nicht, ob Sie bereits eine Lösung gefunden haben, aber ich hatte kürzlich ein ähnliches Problem und stellte fest, dass die Controlleraktion, die diesen Aufruf von "RenderViewToString" initiierte, nicht mit dem vollständig qualifizierten Aktionsnamen gestartet wurde. Es fehlte die Gegend. Ich machte einen Post von einem Formular, das nur den Controller- und Aktionsnamen und nicht den Bereichsnamen als Teil der Formularaktion enthielt. – Hopeless

+0

@Hopeless Ja, ich habe meine Lösung gefunden und ich habe es sogar mit Sitzungen arbeiten lassen, die diese Funktion nicht ausführt Ich werde sie bald posten – Alok

4

Folgendes ist die Lösung, die mit Sitzung und Bereichen auf MVC5 funktioniert.

public class FakeController : ControllerBase 
{ 
    protected override void ExecuteCore() { } 
    public static string RenderViewToString(string controllerName, string viewName,string areaName, object viewData,RequestContext rctx) 
    { 
     try 
     { 
      using (var writer = new StringWriter()) 
      { 
       var routeData = new RouteData(); 
       routeData.Values.Add("controller", controllerName); 
       routeData.Values.Add("Area", areaName); 
       routeData.DataTokens["area"] = areaName; 

       var fakeControllerContext = new ControllerContext(rctx, new FakeController()); 
       //new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController()); 
       fakeControllerContext.RouteData = routeData; 

       var razorViewEngine = new RazorViewEngine(); 

       var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false); 

       var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer); 

       razorViewResult.View.Render(viewContext, writer); 
       return writer.GetStringBuilder().ToString(); 
       //use example 
       //String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel); 
       //where file MyHTMLView.cstml is stored in Views/Email/MyHTMLView.cshtml. Email is a fake controller name. 
      } 
     } 
     catch (Exception ex) 
     { 
      //do your exception handling here 
     } 
    } 
} 

hier, wie Sie diese von einem anderen Controller rufen

var modal = getModal(params); 
return FakeController.RenderViewToString(controllerName, viewName, areaName, modal, this.Request.RequestContext); 

Request wir die Verwendung leicht aktuelle Sitzung in fakecontroller passieren können und Rasierer String machen.

+0

Sie haben meinen Tag dankend gespeichert –

0

Ich musste sofort 6 Teilansichten als Zeichenfolgen in einem JSON-Objekt zurückgeben. Anstatt eine statische Methode zu erstellen und alle nicht benötigten Parameter zu übergeben, habe ich beschlossen, unserer ControllerBase-Klasse, die von Controller abgeleitet ist, geschützte Methoden hinzuzufügen, die als Basisklasse für alle unsere Controller verwendet wird.

Hier ist eine voll funktionsfähige ControllerBase-Klasse, die diese Funktionalität bietet und den PartialView() - und View() - Methoden in der Controller-Klasse sehr ähnlich ist. Es enthält die Ergänzungen von @ Alok.

public abstract class ControllerBase : Controller 
{ 
    #region PartialViewToString 

    protected string PartialViewToString(string partialViewName, object model = null) 
    { 
     ControllerContext controllerContext = new ControllerContext(Request.RequestContext, this); 

     return ViewToString(
      controllerContext, 
      ViewEngines.Engines.FindPartialView(controllerContext, partialViewName) ?? throw new FileNotFoundException("Partial view cannot be found."), 
      model 
     ); 
    } 

    #endregion 

    #region ViewToString 

    protected string ViewToString(string viewName, object model = null) 
    { 
     ControllerContext controllerContext = new ControllerContext(Request.RequestContext, this); 

     return ViewToString(
      controllerContext, 
      ViewEngines.Engines.FindView(controllerContext, viewName, null) ?? throw new FileNotFoundException("View cannot be found."), 
      model 
     ); 
    } 

    protected string ViewToString(string viewName, string controllerName, string areaName, object model = null) 
    { 
     RouteData routeData = new RouteData(); 
     routeData.Values.Add("controller", controllerName); 

     if (areaName != null) 
     { 
      routeData.Values.Add("Area", areaName); 
      routeData.DataTokens["area"] = areaName; 
     } 

     ControllerContext controllerContext = new ControllerContext(HttpContext, routeData, this); 

     return ViewToString(
      controllerContext, 
      ViewEngines.Engines.FindView(controllerContext, viewName, null) ?? throw new FileNotFoundException("View cannot be found."), 
      model 
     ); 
    } 

    #endregion 

    #region Private Methods 

    private string ViewToString(ControllerContext controllerContext, ViewEngineResult viewEngineResult, object model) 
    { 
     using (StringWriter writer = new StringWriter()) 
     { 
      ViewContext viewContext = new ViewContext(
       ControllerContext, 
       viewEngineResult.View, 
       new ViewDataDictionary(model), 
       new TempDataDictionary(), 
       writer 
      ); 

      viewEngineResult.View.Render(viewContext, writer); 

      return writer.ToString(); 
     } 
    } 

    #endregion 
}