2010-07-13 7 views
6

Me gustaría obtener el código html que generaría una vista en una cadena, modificarlo en mi controlador y luego agregarlo a mi JsonResult.Render Ver programáticamente en una cadena

Encontré código que haría lo que estoy hablando de un parcial. Me gustaría hacerlo desde una vista aspx.

- explicación adicional:

Digamos que tengo una página que Frame.aspx/Controlador/Marco volverá

me gustaría tener mi mano en la respuesta antes de que fuera por lo que pueda para envuélvelo con jsonp. No deseo editar el resultado de retorno en el código cada vez, es por eso que quiero cargar la vista mediante programación.

/Controlador/Frame actualmente regresa contenido de Frame.aspx: <html><body>hello</body></html>

Digamos que hay una función que hace una vista en un constructor de cadena

StringBuilder sb = new StringBuilder(); 
RenderView(sb, "Frame"); 

ahora tomar SB y se envuelve con jsonp:

public JsonResult Frame(string callback) 
{ 
    StringBuilder sb = new StringBuilder(); 
    RenderView(sb, "Frame"); 

    return new JsonResult 
    { 
     Data = "(function() { " + callback + "(" + clientResponse + "); })();" 
     , 
     JsonRequestBehavior = JsonRequestBehavior.AllowGet 
    }; 
} 
+1

posible duplicado de [Interpretar una vista como una cadena] (http://stackoverflow.com/questions/483091/render-a-view-as-a-string) –

+0

Por favor edite esta pregunta con más detalle, y tal vez un código de ejemplo No hay suficientes detalles aquí para intentar una respuesta. –

+0

No incluya etiquetas como "C#" en el título. Simplemente es redundante. Dejándolos en las etiquetas es suficiente. –

Respuesta

19

Esto funciona como un encanto (lo consiguió a través SO).

lo uso como esto:

public class OfferController : Controller 
{ 
    [HttpPost] 
    public JsonResult EditForm(int Id) 
    { 
     var model = Mapper.Map<Offer, OfferEditModel>(_repo.GetOffer(Id)); 

     return Json(new { status = "ok", partial = this.RenderPartialViewToString("Edit", model) }); 
    } 
} 



public static partial class ControllerExtensions 
{ 
    public static string RenderPartialViewToString(this ControllerBase controller, string partialPath, object model) 
    { 
     if (string.IsNullOrEmpty(partialPath)) 
      partialPath = controller.ControllerContext.RouteData.GetRequiredString("action"); 

     controller.ViewData.Model = model; 

     using (StringWriter sw = new StringWriter()) 
     { 
      ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, partialPath); 
      ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw); 
      // copy model state items to the html helper 
      foreach (var item in viewContext.Controller.ViewData.ModelState) 
       if (!viewContext.ViewData.ModelState.Keys.Contains(item.Key)) 
       { 
        viewContext.ViewData.ModelState.Add(item); 
       } 


      viewResult.View.Render(viewContext, sw); 

      return sw.GetStringBuilder().ToString(); 
     } 
    } 
} 
+0

¡Fantástico! Gracias :-) – Abdo

+1

¿Cómo puedo hacer lo mismo con .NET CORE? –

0

Mike Hadlow escribió en su blog sobre una función llamada CaptureActionHtml() que hace esto. Lo he usado para redactar grandes informes a partir de informes más pequeños y manejables, y luego los paso por alto.

http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

using System; 
using System.IO; 
using System.Web; 
using System.Web.Mvc; 

namespace Suteki.Common.Extensions 
{ 
    public static class ControllerExtensions 
    { 
     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The controller</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this TController controller, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      return controller.CaptureActionHtml(controller, null, action); 
     } 

     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The controller</param> 
     /// <param name="masterPageName">The master page to use for the view</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this TController controller, 
      string masterPageName, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      return controller.CaptureActionHtml(controller, masterPageName, action); 
     } 

     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The current controller</param> 
     /// <param name="targetController">The controller which has the action to execute</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this Controller controller, 
      TController targetController, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      return controller.CaptureActionHtml(targetController, null, action); 
     } 

     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The current controller</param> 
     /// <param name="targetController">The controller which has the action to execute</param> 
     /// <param name="masterPageName">The name of the master page for the view</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this Controller controller, 
      TController targetController, 
      string masterPageName, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      if (controller == null) 
      { 
       throw new ArgumentNullException("controller"); 
      } 
      if (targetController == null) 
      { 
       throw new ArgumentNullException("targetController"); 
      } 
      if (action == null) 
      { 
       throw new ArgumentNullException("action"); 
      } 

      // pass the current controller context to orderController 
      var controllerContext = controller.ControllerContext; 
      targetController.ControllerContext = controllerContext; 

      // replace the current context with a new context that writes to a string writer 
      var existingContext = System.Web.HttpContext.Current; 
      var writer = new StringWriter(); 
      var response = new HttpResponse(writer); 
      var context = new HttpContext(existingContext.Request, response) {User = existingContext.User}; 
      System.Web.HttpContext.Current = context; 

      // execute the action 
      var viewResult = action(targetController); 

      // change the master page name 
      if (masterPageName != null) 
      { 
       viewResult.MasterName = masterPageName; 
      } 

      // we have to set the controller route value to the name of the controller we want to execute 
      // because the ViewLocator class uses this to find the correct view 
      var oldController = controllerContext.RouteData.Values["controller"]; 
      controllerContext.RouteData.Values["controller"] = typeof(TController).Name.Replace("Controller", ""); 

      // execute the result 
      viewResult.ExecuteResult(controllerContext); 

      // restore the old route data 
      controllerContext.RouteData.Values["controller"] = oldController; 

      // restore the old context 
      System.Web.HttpContext.Current = existingContext; 

      return writer.ToString(); 
     } 
    } 
} 
+0

Esto funciona bien para mí con V3.5 y MVc1.0. pero cuando lo actualicé a V4.0 y MVC 2.0, el contexto devuelve nulo ... ¿Alguna idea? – Gokul

0

Aquí hay otra solución para la captura de la vista en MVC 2.0 y> 4.0 neta. Acabo de agregar algunas líneas de código al contenido original de Andrews.

public static class ControllerExtensions 
    { 

     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The controller</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this TController controller, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      return controller.CaptureActionHtml(controller, null, action); 
     } 

     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The controller</param> 
     /// <param name="masterPageName">The master page to use for the view</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this TController controller, 
      string masterPageName, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      return controller.CaptureActionHtml(controller, masterPageName, action); 
     } 

     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The current controller</param> 
     /// <param name="targetController">The controller which has the action to execute</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     public static string CaptureActionHtml<TController>(
      this Controller controller, 
      TController targetController, 
      Func<TController, ViewResult> action) 
      where TController : Controller 
     { 
      return controller.CaptureActionHtml(targetController, null, action); 
     } 




     /// <summary> 
     /// Captures the HTML output by a controller action that returns a ViewResult 
     /// </summary> 
     /// <typeparam name="TController">The type of controller to execute the action on</typeparam> 
     /// <param name="controller">The current controller</param> 
     /// <param name="targetController">The controller which has the action to execute</param> 
     /// <param name="masterPageName">The name of the master page for the view</param> 
     /// <param name="action">The action to execute</param> 
     /// <returns>The HTML output from the view</returns> 
     ///  
    public static string CaptureActionHtml<TController>(this Controller controller, TController targetController, string masterPageName, Func<TController, ViewResult> action) where TController : Controller 

     { 
    if (controller == null) 
    { 
    throw new ArgumentNullException("controller"); 
    } 
    if (targetController == null) 
    { 
    throw new ArgumentNullException("targetController"); 
    } 
    if (action == null) 
    { 
    throw new ArgumentNullException("action"); 
    } 
    // pass the current controller context to orderController 
    var controllerContext = controller.ControllerContext; 
    targetController.ControllerContext = controllerContext; 

    // replace the current context with a new context that writes to a string writer 
    var existingContext = HttpContext.Current; 
    var writer = new StringWriter(); 
    var response = new HttpResponse(writer); 
    var context = new HttpContext(existingContext.Request, response) { User = existingContext.User }; 
    HttpContext.Current = context; 

    // execute the action 
    var viewResult = action(targetController); 

    // change the master page name 
    if (masterPageName != null) 
    { 
    viewResult.MasterName = masterPageName; 
    } 

    // we have to set the controller route value to the name of the controller we want to execute 
    // because the ViewLocator class uses this to find the correct view 
    var oldController = controllerContext.RouteData.Values["controller"]; 
    controllerContext.RouteData.Values["controller"] = typeof(TController).Name.Replace("Controller", ""); 

    // execute the result 
    viewResult.ExecuteResult(controllerContext); 

    StringWriter sw = new StringWriter(); 
    var xx = targetController.TempData["pdf"]; 
    //var viewContext = new ViewContext(controllerContext, viewResult.View, new ViewDataDictionary(targetController.ViewData.Model), new TempDataDictionary(), sw); 
    var viewContext = new ViewContext(controllerContext, viewResult.View, viewResult.ViewData, new TempDataDictionary(), sw); 
    viewResult.View.Render(viewContext, HttpContext.Current.Response.Output); 
    response.Flush(); 

    // restore the old route data 
    controllerContext.RouteData.Values["controller"] = oldController; 

    // restore the old context 
    HttpContext.Current = existingContext; 

    return sw.ToString(); 
    } 



    } 
} 

aplausos !!