Dans MVC3 Razor, comment obtenir le html d'une vue rendue dans une action?

90

Est-ce que quelqu'un sait comment obtenir le html généré d'une vue à l'intérieur d'une action?

Est-ce quelque chose comme ça:

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

Réponses:

152

J'utilise une méthode statique dans une classe que Utilities.Commonj'ai appelée.Je transmets constamment les vues au client en tant que propriétés des objets JSON, donc j'avais besoin de les rendre dans une chaîne. Et voilà:

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

Cela fonctionnera aussi bien pour les vues complètes que pour les vues partielles, il suffit de changer ViewEngines.Engines.FindPartialViewpour ViewEngines.Engines.FindView.

Chev
la source
14
FindView a besoin d'un autre paramètre ( masterName) que vous spécifiez null. Je recommande également d'enregistrer et de restaurer (après le rendu) controller.ViewData.Model au cas où la méthode est appelée sur l'instance de contrôleur actuelle et le modèle a été attribué avant cet appel.
Andrei Rînea
4
Vous devez également appeler viewResult.ViewEngine.ReleaseView (controller.ControllerContext, viewResult.View)
sjmeverett
3
Cela fonctionne très bien, mais je ne voudrais pas attraper et rendre des exceptions dans mon code en direct.
pauloya
3
Si vous l'appelez depuis le contrôleur lui-même, passez simplement thiscomme argument du contrôleur. RenderPartialViewToString(this, "index", viewModel). Je pense qu'il est ridicule qu'il n'y ait pas de moyen plus simple d'appeler simplement le moteur de vue et de récupérer une chaîne, mais dans ASP.NET, le moteur de vue a besoin de référence à l'instance de contrôleur afin de compiler la vue. Je suis un développeur nodeJS maintenant et les moteurs de vue dans node sont des modules entièrement séparés que vous pouvez appeler manuellement ou avec un framework MVC comme express .
Chev
5
@PauloManuelSantos Je suis d'accord avec vous. J'ai écrit cela il y a des années et je ne sais pas ce que je pensais en incluant la gestion des erreurs dans la réponse. J'ai mis à jour la réponse pour exclure le try / catch. Merci pour les commentaires.
Chev
4

La réponse acceptée par @Chev ci-dessus est bonne, mais je voulais rendre le résultat d'une action spécifique , pas seulement une vue particulière .

De plus, j'avais besoin de pouvoir passer des paramètres à cette action plutôt que de compter sur l'injection d'un modèle.

J'ai donc mis au point ma propre méthode, que j'ai mise dans la classe de base de mes contrôleurs (en la rendant disponible à tous):

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

Supposons que j'ai une action appelée Fooqui prend un objet modèle et quelques autres paramètres, qui ensemble influencent la vue qui sera utilisée:

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

Maintenant, si je veux obtenir le résultat de l'appel à l'action Foo, je peux simplement obtenir le ViewResulten appelant la Foométhode, puis appeler RenderViewResultAsStringpour obtenir le texte HTML:

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

    var html = this.RenderViewResultAsString(viewResult);
Gary McGill
la source