我想获取视图将在字符串中生成的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
};
}
答案 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();
}
}
}
欢呼声!!