在MVC2.0中捕获HTML到字符串

时间:2011-04-05 14:38:11

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

我是MVC2.0的新手。我使用下面的代码来捕获HTML并将其作为字符串返回。但这在MVC1.0和.NET 3.5框架中运行良好。最近我将代码升级到.NET 4.0和MVC 2.0。现在这不再起作用,上下文返回null。当我探索时,我看到了两个错误 1.“此操作需要IIS集成管道模式。” 2.OutputStream ='response.OutputStream'抛出了类型system.Web.HttpException的异常'

这是调用函数

var htmlstring = this.CaptureActionHtml(new PdfController(_paService, _configService), c => (ViewResult)paController.GetHTML(p));

//和捕获方法。

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

我找到了一个解决方案..但是遇到了另一个问题..模型没有通过视图......这是更新后的代码

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 viewContext = new ViewContext(controllerContext, viewResult.View, new ViewDataDictionary(controllerContext.Controller.ViewData.Model), new TempDataDictionary(), sw);
    var viewContext = new ViewContext(controllerContext, viewResult.View, targetController.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();
    } 

任何建议都会非常有用..

1 个答案:

答案 0 :(得分:1)

感谢您的复习..我自己找到了......傻我!它只是简单的事情..这是完整的代码..

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

我刚刚更换了这行代码

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

工作正常..干杯!!