2015-05-20 9 views
13

Nelle versioni precedenti di ASP.NET era possibile, anche se non molto semplice, rendere le viste Razor come stringhe. I metodi che ho sembrano sono quelli di utilizzare un controller falso, o anche di usare un motore esterno come RazorEngine.Render Razor view to string in ASP.NET 5

Ora, molte cose sono cambiate con ASP.NET 5 e mi chiedevo se ora sia più semplice di prima. Quindi nella nuova versione del framework c'è un modo semplice per rendere le visualizzazioni di Razor come stringhe o dobbiamo ancora utilizzare i metodi delle versioni precedenti?

+0

Si desidera inserire il contenuto HTML di un'azione su una variabile stringa? O semplicemente esegui un ActionResult in un'altra vista? –

+0

@FabioLuz Voglio renderizzare la vista e inserire il codice HTML reso all'interno di una variabile stringa. – user1620696

+0

Se vuoi farlo mentre sei sotto MVC 6, dovrebbe essere abbastanza semplice. È solo questione di ottenere la giusta dipendenza per migliorare la vista del rasoio. Tuttavia, se si è al di fuori di esso, ecco un esempio: https://github.com/tugberkugurlu/RazorOnConsole/blob/34c2e308f1976680c654a06a066b6c7fda1387b6/RazorTemplatingSample.Console/Program.cs#L15 scavare per vedere come 'Templater.Run' è implementato. – tugberk

risposta

17

uso i seguenti tipi iniettato dalla IServiceProvider:

ICompositeViewEngine viewEngine; 
ITempDataProvider tempDataProvider; 
IHttpContextAccessor httpContextAccessor; 

rendo il contenuto utilizzando il seguente metodo:

private async Task<string> RenderView(string path, ViewDataDictionary viewDataDictionary, ActionContext actionContext) 
{ 
    using (var sw = new System.IO.StringWriter()) 
    { 
     var viewResult = viewEngine.FindView(actionContext, path); 

     var viewContext = new ViewContext(actionContext, viewResult.View, viewDataDictionary, new TempDataDictionary(httpContextAccessor, tempDataProvider), sw); 

     await viewResult.View.RenderAsync(viewContext); 
     sw.Flush(); 

     if (viewContext.ViewData != viewDataDictionary) 
     { 
      var keys = viewContext.ViewData.Keys.ToArray(); 
      foreach (var key in keys) 
      { 
       viewDataDictionary[key] = viewContext.ViewData[key]; 
      } 
     } 

     return sw.ToString(); 
    } 
} 

mi chiamano così:

var path = "~/Views/Home/Index.cshtml"; 
var viewDataDictionary = new ViewDataDictionary(new Microsoft.AspNet.Mvc.ModelBinding.EmptyModelMetadataProvider(), new Microsoft.AspNet.Mvc.ModelBinding.ModelStateDictionary()); 
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new Microsoft.AspNet.Routing.RouteData(), new ActionDescriptor()); 
viewDataDictionary.Model = null; 
var text = await RenderView(path, viewDataDictionary, actionContext); 

Naturalmente, le mie variabili viewDataDictionary e actionContext sono impostate da un altro metodo per l'incapsulamento. Una modifica alla linea new ViewDataDictionary può comportare il collegamento di un Modello tipizzato alla vista, se lo si desidera.

Questo codice utilizza utilizzi pesanti, penso di averli elencati di seguito. Altrimenti, VS2015 è abbastanza buono nel trovarli.

using Microsoft.AspNet.Mvc; 
using Microsoft.AspNet.Mvc.Rendering; 

Questo è stato scritto in beta-3; continua a crescere, ma alcune cose potrebbero cambiare. Cercherò di tornare qui per aggiornare se lo fa.

+0

Felice di aiutare! E grazie per averlo notato funziona ancora - non avevo dovuto tornare indietro e cambiarlo, quindi non avevo aggiunto quella nota alla mia risposta. –

+1

Non vedere come ottieni quegli oggetti iniettati e anche la firma del metodo è incoerente con il modo in cui la chiami ... – Shockwaver

+1

@Shockwaver - nel caso in cui qualcuno si chiedesse di questo, è solo un'iniezione di dipendenza (DI). Le dipendenze del servizio sono in genere parametri per il costruttore della classe e il contenitore DI risolve dove ottenerle. Per quanto riguarda l'incoerenza della firma, Matt probabilmente ha scritto il metodo originale all'interno di un controller che ha una proprietà ActionContext in modo da poter semplicemente passare alla A maiuscola e iniziare a testare il codice da un controller. – Seth

3

C'è una soluzione che ho usato un anno fa. Non sono sicuro se c'è un modo nuovo/migliore, ma risolve il problema.

public string RenderViewToString(string viewName, object model) 
{ 
    ViewData.Model = model; 
    using (var sw = new StringWriter()) 
    { 
     var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName); 
     var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw); 
     viewResult.View.Render(viewContext, sw); 
     viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View); 
     return sw.GetStringBuilder().ToString(); 
    } 
} 
+2

Sfortunatamente, la classe ViewEngines non esiste anche con asp.net-5. –

+0

@MattDeKrey Ma lo fa in v4 (non la richiesta OP, lo so)! E questo è assolutamente il modo di andare per quella versione! Bello, ho salvato la mia giornata, nessun problema con nessuno degli aiutanti html usati con il rasoio. GRAZIE – Shockwaver