2010-07-13 3 views
6

Я хотел бы получить код html, который будет генерировать представление в строке, изменить его в моем контроллере, а затем добавить в мой JsonResult.Render Посмотреть программно в строку

Я нашел код, который будет делать то, о чем я говорю, из частичного. Я бы хотел сделать это из представления aspx.

- Дополнительное объяснение:

Скажем, у меня есть страница Frame.aspx что/Controller/Кадр будет возвращать

Я хотел бы получить мою руку на ответ перед ним так, я могу оберните его jsonp. Я не хочу каждый раз редактировать результат возврата в код, поэтому я хочу загрузить представление программно.

/Controller/Рамные в настоящее время возвращает содержание Frame.aspx в: <html><body>hello</body></html>

Скажем, есть функция, которая делает вид в струнной строитель

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

теперь взять С.Б. и обернуть его JSONP:

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

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

Возможный дубликат [Render the view as a string] (http://stackoverflow.com/questions/483091/render-a-view-as-a-string) –

+0

Пожалуйста, отредактируйте этот вопрос более подробно, и, возможно, некоторый пример кода. Здесь недостаточно деталей, чтобы попытаться ответить. –

+0

Пожалуйста, не включайте теги типа «C#» в названии. Это просто избыточно. Оставлять их в тегах достаточно. –

ответ

19

Это работает как шарм (получил его через SO).

Я использую это так:

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

Фантастический! Спасибо :-) – Abdo

+1

Как я могу сделать то же самое с .NET CORE? –

0

Майк Хэдлоу написал о функции CaptureActionHtml(), которая делает это. Я использовал его для составления больших отчетов из меньших, более управляемых отчетов, а затем передал их.

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

Это отлично работает для меня с V3.5 и MVc1.0. но когда я обновил его до версии V4.0 и MVC 2.0, контекст возвращает null .. любая идея? – Gokul

0

Вот еще один обходной путь для захвата вид в MVC 2.0 и> чистый 4.0. Я просто добавил несколько строк кода к оригинальному контенту Эндрюса.

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



    } 
} 

ура !!

Смежные вопросы