2010-12-03 41 views
95

Cómo generar un HTML de una vista parcial determinada en el motor de vista ASP.NET is known.ASP.NET MVC Razor: Cómo renderizar un HTML de la vista parcial de Razor dentro de la acción del controlador

Pero si esta funcionalidad se utiliza en la vista parcial de la maquinilla de afeitar, no funciona, ya que la excepción dice que la vista parcial no se deriva de "UserControl".

¿Cómo arreglar la representación para apoyar la vista parcial de la maquinilla de afeitar?

Necesito esto porque me generan correos electrónicos forman vistas parciales ...

ACTUALIZACIÓN:

código que falla (@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(); 
    } 
+1

¿Puede mostrar el código que tiene hasta ahora que genera la excepción? – mlibby

Respuesta

152
@Html.Partial("nameOfPartial", Model) 

actualización

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

Sí, así es como se renderiza una vista parcial dentro de una vista. ¿Pero cómo renderizarlo dentro de una acción de controlador? –

+0

Actualizó la respuesta. – jgauffin

+0

¡Genial, esto es todo ahora! Funciona con la notación Razon y ASP. –

6

También es posible usar el RenderView Controller extension de here (source)

y utilizar de esta manera:

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

funciona para afeitar y formularios web viewengines

+0

Ha revisado el enlace. @ChurkNorris es el autor de [ASP.net MVC Awesome] (http://www.aspnetawesome.com/), que es un producto comercial [de la versión 2.0] (http://awesome.codeplex.com/releases/) (actualmente último lanzamiento 12 de marzo de 2012). [Versión 1.9] (http://awesome.codeplex.com/releases/view/66067) (última versión del 9 de junio de 2011) sigue siendo de código abierto, pero probablemente ya no se desarrolle. Cualquier tenedor de 1.9 por ahí? –

+0

@Omu: RenderView es nulo. Consulte https://msdn.microsoft.com/en-us/library/system.web.mvc.viewpage.renderview(v=vs.118).aspx – roland

+0

@Roland esta es una extensión de controlador personalizado – Omu

1

Vi que alguien se preguntaba cómo hacerlo para otro controlador.

En mi caso tenía todas mis plantillas de correo electrónico en la carpeta Vistas/Correo electrónico, pero podría modificar esto para pasar el controlador en el que tiene vistas asociadas.

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

En esencia lo que esto hace es tomar un controlador, como AccountController y modificarlo a pensar que es un EmailController para que el código se verá en la carpeta Views/Email. Es necesario hacer esto porque el método FindView no toma una ruta recta como parámetro, quiere un ControllerContext.

Una vez hecho el renderizado de la cadena, devuelve AccountController a su estado inicial para ser utilizada por el objeto Response.

7

Aunque ya se han dado las respuestas adecuadas, me gustaría proponer una solución menos detallada, que se puede utilizar sin los métodos de ayuda disponibles en una clase de controlador MVC. Usando una biblioteca de terceros llamado "RazorEngine" que puede utilizar .Net archivo IO para obtener los contenidos del archivo de afeitar y llamar

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

Consigue la biblioteca de terceros here.

1

buen código; pequeña pista: si a veces tiene que omitir más datos y no solo el modelo de vista ...

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

No ha completado su responder – poohdedoo

0

El préstamo de respuesta @jgauffin como una extensión HtmlHelper:

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

uso en una vista de afeitar:

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