2010-03-29 16 views
38

Tengo el siguiente código:el modo de hacer la vista parcial en una cadena

public ActionResult SomeAction() 
{ 
    return new JsonpResult 
    { 
     Data = new { Widget = "some partial html for the widget" } 
    }; 
} 

me gustaría modificarlo para que yo pudiera tener

public ActionResult SomeAction() 
{ 
    // will render HTML that I can pass to the JSONP result to return. 
    var partial = RenderPartial(viewModel); 
    return new JsonpResult 
    { 
     Data = new { Widget = partial } 
    }; 
} 

es esto posible? ¿Alguien podría explicar cómo?

nota, edité la pregunta antes de publicar la solución.

+0

para todas las respuestas - como gotcha, si usted está tratando de hacer que la vista desde otro controlador, tiene que totalmente especificar el nombre de la vista '" ~/Vistas// .cshtml "' – drzaus

Respuesta

20

Ésta es una versión ligeramente modificada de una respuesta que funciona:

public static string RenderPartialToString(string controlName, object viewData) 
{ 
    ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() }; 

    viewPage.ViewData = new ViewDataDictionary(viewData); 
    viewPage.Controls.Add(viewPage.LoadControl(controlName)); 

    StringBuilder sb = new StringBuilder(); 
    using (StringWriter sw = new StringWriter(sb)) 
    { 
     using (HtmlTextWriter tw = new HtmlTextWriter(sw)) 
     { 
      viewPage.RenderControl(tw); 
     } 
    } 

    return sb.ToString(); 
} 

Uso:

string ret = RenderPartialToString("~/Views/MyController/MyPartial.ascx", model); 
+5

Esto funciona bien para mí. Sin embargo, si agrego un RenderPartial a la vista parcial que paso a este método, empiezo a recibir una excepción en la llamada RenderControl: "El valor no puede ser nulo. Nombre del parámetro: ver" –

+3

No funcionó para mí, estoy usando razor view engine, parece que esto funciona con los controles de usuario ascx en lugar de vistas cshtml parciales. Publiqué aquí mi propia versión que funciona con la afeitadora: http://stackoverflow.com/questions/5532345/mvc-render-to-string-in-the-controller-or-else-were/8677839#comment10788063_8677839 – Nestor

1

de Dave,

una variación sobre el mismo tema (v1.0 MVC) :

 protected static string RenderPartialToString(Controller controller, string partialName, object model) 
    { 
     var vd = new ViewDataDictionary(controller.ViewData); 
     var vp = new ViewPage 
     { 
      ViewData = vd, 
      ViewContext = new ViewContext(), 
      Url = new UrlHelper(controller.ControllerContext.RequestContext) 
     }; 

     ViewEngineResult result = ViewEngines 
            .Engines 
            .FindPartialView(controller.ControllerContext, partialName); 

     if (result.View == null) 
     { 
      throw new InvalidOperationException(
      string.Format("The partial view '{0}' could not be found", partialName)); 
     } 
     var partialPath = ((WebFormView)result.View).ViewPath; 

     vp.ViewData.Model = model; 

     Control control = vp.LoadControl(partialPath); 
     vp.Controls.Add(control); 

     var sb = new StringBuilder(); 

     using (var sw = new StringWriter(sb)) 
     { 
      using (var tw = new HtmlTextWriter(sw)) 
      { 
       vp.RenderControl(tw); 
      } 
     } 
     return sb.ToString(); 
    } 

us edad dentro del controlador: Respuesta

 public string GetLocationHighlites() 
    { 
     IBlockData model = WebPagesMapper.GetLocationHighlites(); 
     // **this** being the controoler instance 
     // LocationPartial.ascx can be defined in shared or in view folder 
     return RenderPartialToString(**this**,"LocationPartial", model); 
    } 
8

de DaveDev funcionó bien para mí, sin embargo, cuando la vista parcial llama a otro parcial consigo "El valor no puede ser nulo. Nombre de parámetro:. vista"

Buscando en He hecho una variante del following que parece funcionar bien

public static string RenderPartialToString(string viewName, object model, ControllerContext ControllerContext) 
    { 
     if (string.IsNullOrEmpty(viewName)) 
      viewName = ControllerContext.RouteData.GetRequiredString("action"); 
     ViewDataDictionary ViewData = new ViewDataDictionary(); 
     TempDataDictionary TempData = new TempDataDictionary(); 
     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(); 
     } 

    } 

Uso:

String result = MVCHelpers.RenderPartialToString("PartialViewHere", Model, ControllerContext) 
5

Puede crear extensión que hacen la vista en cadena

public static class RenderPartialToStringExtensions 
{ 
    /// <summary> 
    /// render PartialView and return string 
    /// </summary> 
    /// <param name="context"></param> 
    /// <param name="partialViewName"></param> 
    /// <param name="model"></param> 
    /// <returns></returns> 
    public static string RenderPartialToString(this ControllerContext context, string partialViewName, object model) 
    { 
     return RenderPartialToStringMethod(context, partialViewName, model); 
    } 

    /// <summary> 
    /// render PartialView and return string 
    /// </summary> 
    /// <param name="context"></param> 
    /// <param name="partialViewName"></param> 
    /// <param name="viewData"></param> 
    /// <param name="tempData"></param> 
    /// <returns></returns> 
    public static string RenderPartialToString(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData) 
    { 
     return RenderPartialToStringMethod(context, partialViewName, viewData, tempData); 
    } 

    public static string RenderPartialToStringMethod(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData) 
    { 
     ViewEngineResult result = ViewEngines.Engines.FindPartialView(context, partialViewName); 

     if (result.View != null) 
     { 
      StringBuilder sb = new StringBuilder(); 
      using (StringWriter sw = new StringWriter(sb)) 
      { 
       using (HtmlTextWriter output = new HtmlTextWriter(sw)) 
       { 
        ViewContext viewContext = new ViewContext(context, result.View, viewData, tempData, output); 
        result.View.Render(viewContext, output); 
       } 
      } 

      return sb.ToString(); 
     } 
     return String.Empty; 
    } 

    public static string RenderPartialToStringMethod(ControllerContext context, string partialViewName, object model) 
    { 
     ViewDataDictionary viewData = new ViewDataDictionary(model); 
     TempDataDictionary tempData = new TempDataDictionary(); 
     return RenderPartialToStringMethod(context, partialViewName, viewData, tempData); 
    } 
} 

Y luego úsala en acción

[HttpPost] 
public ActionResult GetTreeUnit(string id) 
{ 
    int _id = id.ExtractID(); 
    string render = ControllerContext.RenderPartialToString("SomeView"); 
    return Json(new { data = render }); 
} 
34

Opté por un método de extensión como el siguiente para una aplicación ASP.NET MVC 4. Creo que es más simple que algunas de las sugerencias que he visto:

public static class ViewExtensions 
{ 
    public static string RenderToString(this PartialViewResult partialView) 
    { 
     var httpContext = HttpContext.Current; 

     if (httpContext == null) 
     { 
      throw new NotSupportedException("An HTTP context is required to render the partial view to a string"); 
     } 

     var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString(); 

     var controller = (ControllerBase)ControllerBuilder.Current.GetControllerFactory().CreateController(httpContext.Request.RequestContext, controllerName); 

     var controllerContext = new ControllerContext(httpContext.Request.RequestContext, controller); 

     var view = ViewEngines.Engines.FindPartialView(controllerContext, partialView.ViewName).View; 

     var sb = new StringBuilder(); 

     using (var sw = new StringWriter(sb)) 
     { 
      using (var tw = new HtmlTextWriter(sw)) 
      { 
       view.Render(new ViewContext(controllerContext, view, partialView.ViewData, partialView.TempData, tw), tw); 
      } 
     } 

     return sb.ToString(); 
    } 
} 

Me permite hacer lo siguiente:

var html = PartialView("SomeView").RenderToString(); 

Además, este enfoque persiste cualquier Modelo, ViewBag y otros datos de vista para la vista.

2

funciona perfecto (Sólo ver el nombre requerido)
* para los parámetros que puede utilizar un modelo
* puede llamar a esto desde un punto de vista también

Vista lateral o lado llamante

BuyOnlineCartMaster ToInvoice1 = new BuyOnlineCartMaster(); // for passing parameters 
ToInvoice1.CartID = 1; 

string HtmlString = RenderPartialViewToString("PartialInvoiceCustomer", ToInvoice1); 

función de generación HTML

public static string RenderPartialViewToString(string viewName, object model) 
    {  
    using (var sw = new StringWriter()) 
      { 
       BuyOnlineController controller = new BuyOnlineController(); // instance of the required controller (you can pass this as a argument if needed) 

       // Create an MVC Controller Context 
       var wrapper = new HttpContextWrapper(System.Web.HttpContext.Current); 

       RouteData routeData = new RouteData(); 

       routeData.Values.Add("controller", controller.GetType().Name 
                  .ToLower() 
                  .Replace("controller", "")); 

       controller.ControllerContext = new ControllerContext(wrapper, routeData, controller); 

       controller.ViewData.Model = model; 

       var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); 

       var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw); 
       viewResult.View.Render(viewContext, sw); 

       return sw.ToString(); 
      } 
    } 
1

Puede hacerlo de la caja con:

var partial = new HtmlString(Html.Partial("_myPartial", Model).ToString()); 
+0

No puedo obtener Html.Partial. – Machado

+0

@ Dan-p por lo que sé Html.Partial no se puede utilizar directamente en un controlador. ¿Cómo estás haciendo funcionar esta línea de código? – Mike

+0

Lo sentimos, está en lo correcto, estamos usando esa línea en un bloque @ {} en la Navaja de una vista, no directamente en el controlador. Tal vez su controlador podría devolver una vista parcial que use ese código. –

0
public virtual string RenderPartialViewToString(string viewName, object viewmodel) 
     { 
      if (string.IsNullOrEmpty(viewName)) 
      { 
       viewName = this.ControllerContext.RouteData.GetRequiredString("action"); 
      } 

      ViewData.Model = viewmodel; 

      using (var sw = new StringWriter()) 
      { 
       ViewEngineResult viewResult = System.Web.Mvc.ViewEngines.Engines.FindPartialView(this.ControllerContext, viewName); 
       var viewContext = new ViewContext(this.ControllerContext, viewResult.View, this.ViewData, this.TempData, sw); 
       viewResult.View.Render(viewContext, sw); 
       viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View); 

       return sw.GetStringBuilder().ToString(); 
      } 
     } 
Cuestiones relacionadas