Render View programmatically into a string

前端 未结 3 1493
小鲜肉
小鲜肉 2020-12-30 14:51

I would like to get the html code a view would generate in a string, modify it in my controller, then add it to my JsonResult.

I found code that would do what i\'m t

相关标签:
3条回答
  • 2020-12-30 15:14

    Mike Hadlow blogged about a function called CaptureActionHtml() that does this. I've used it to compose large reports out of smaller, more manageable reports and then pass them around.

    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 讨论(0)
  • 2020-12-30 15:28

    This works like a charm (got it through SO).

    I use it like this:

    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 讨论(0)
  • 2020-12-30 15:34

    Here is another workaround for capturing the view in MVC 2.0 and >net 4.0. I just added few lines of code to Andrews original content.

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

    cheers!!

    0 讨论(0)
提交回复
热议问题