以编程方式将视图渲染为字符串

时间:2010-07-13 03:31:42

标签: c# asp.net asp.net-mvc asp.net-mvc-2

我想获取视图将在字符串中生成的html代码,在我的控制器中修改它,然后将其添加到我的JsonResult。

我发现代码可以完成我所说的部分内容。我想从aspx View中做到这一点。

- 额外说明:

假设我有一个页面Frame.aspx,/ Controller / Frame将返回

我希望在它出来之前得到响应,所以我可以用jsonp包装它。 我不希望每次都在代码中编辑返回结果,这就是我想以编程方式加载视图的原因。

/ Controller / Frame当前返回Frame.aspx的内容:<html><body>hello</body></html>

假设有一个函数可以在字符串构建器中呈现视图

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

现在接受sb并用jsonp包装它:

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

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

3 个答案:

答案 0 :(得分: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();
        }
    }
}

答案 1 :(得分:1)

Mike Hadlow在博客中发表了一篇名为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();
        }
    }
}

答案 2 :(得分:1)

这是在MVC 2.0和&gt; net 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();
    } 



    }
}

欢呼声!!