In MVC3 Razor, come ottengo l'html di una vista renderizzata all'interno di un'azione?


90

Qualcuno sa come ottenere l'html generato di una vista all'interno di un'azione?

È qualcosa del genere:

public ActionResult Do()
{
    var html = RenderView("hello", model);
...
}

Risposte:


152

Uso un metodo statico in una classe che ho chiamato Utilities.Common. Passo le visualizzazioni al client come proprietà degli oggetti JSON costantemente, quindi avevo bisogno di renderle in una stringa. Ecco qua:

public static string RenderPartialViewToString(Controller controller, string viewName, object model)
{
    controller.ViewData.Model = model;
    using (StringWriter sw = new StringWriter())
    {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.ToString();
    }
}

Funzionerà sia per le visualizzazioni complete che per quelle parziali, basta passare ViewEngines.Engines.FindPartialViewa ViewEngines.Engines.FindView.


14
FindView necessita di un altro parametro ( masterName) da specificare null. Inoltre, consiglio di salvare e ripristinare (dopo il rendering) controller.ViewData.Model nel caso in cui il metodo venga chiamato sull'istanza del controller corrente e il modello sia stato assegnato prima di questa chiamata.
Andrei Rînea

4
Dovresti anche chiamare viewResult.ViewEngine.ReleaseView (controller.ControllerContext, viewResult.View)
sjmeverett

3
Funziona benissimo, ma non vorrei catturare e visualizzare eccezioni nel mio codice live.
pauloya

3
Se lo chiami dall'interno del controller stesso, passa semplicemente thiscome argomento del controller. RenderPartialViewToString(this, "index", viewModel). Penso che sia sciocco che non ci sia un modo più semplice per invocare semplicemente il motore di visualizzazione e ottenere una stringa, ma in ASP.NET il motore di visualizzazione deve fare riferimento all'istanza del controller per compilare la visualizzazione. Sono uno sviluppatore nodeJS ora e i motori di visualizzazione in node sono interi moduli separati che puoi richiamare manualmente o con un framework MVC come express .
Chev

5
@PauloManuelSantos Sono d'accordo con te. L'ho scritto anni fa e non so cosa stavo pensando includendo la gestione degli errori nella risposta. Ho aggiornato la risposta per escludere la prova / cattura. Grazie per il feedback.
Chev

4

La risposta accettata da @Chev sopra è buona, ma volevo rendere il risultato di un'azione specifica , non solo una vista particolare .

Inoltre, dovevo essere in grado di passare parametri a quell'azione piuttosto che fare affidamento sull'iniezione di un modello.

Quindi ho escogitato il mio metodo, che ho inserito nella classe base dei miei controller (rendendolo disponibile a tutti):

    protected string RenderViewResultAsString(ViewResult viewResult)
    {
        using (var stringWriter = new StringWriter())
        {
            this.RenderViewResult(viewResult, stringWriter);

            return stringWriter.ToString();
        }
    }

    protected void RenderViewResult(ViewResult viewResult, TextWriter textWriter)
    {
        var viewEngineResult = this.ViewEngineCollection.FindView(
            this.ControllerContext, 
            viewResult.ViewName, 
            viewResult.MasterName);
        var view = viewEngineResult.View;

        try
        {
            var viewContext = new ViewContext(
                this.ControllerContext, 
                view, 
                this.ViewData, 
                this.TempData, 
                textWriter);

            view.Render(viewContext, textWriter);
        }
        finally
        {
            viewEngineResult.ViewEngine.ReleaseView(this.ControllerContext, view);
        }
    }

Supponiamo di avere un'azione chiamata Fooche accetta un oggetto del modello e alcuni altri parametri, che insieme influenzano la vista che verrà utilizzata:

    public ViewResult Foo(MyModel model, int bar)
    {
        if (bar == 1)
            return this.View("Bar1");
        else
            return this.View("Bar2", model);
    }

Ora, se voglio ottenere il risultato della chiamata all'azione Foo, posso semplicemente ottenere ViewResultinvocando il Foometodo e quindi chiamare RenderViewResultAsStringper ottenere il testo HTML:

    var viewResult = this.Foo(model, bar);

    var html = this.RenderViewResultAsString(viewResult);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.