asp.net-mvc - 像字符串那样重绘视图

  显示原文与译文双语对照的内容

我想尽可能输出( 一个作为电子邮件发送的字符串) 两种不同视图,另一个测试把页面显示给用户。

这在 ASP.NET MVC测试版中是否可能?

我已经尝试了多个例子:

RenderPartial在 ASP.NET MVC测试版中字符串
如果我使用这个示例,我将收到"发送HTTP标头后无法重定向。"。

MVC框架:捕获视图的输出
如果我使用该,我似乎无法做一个 redirectToAction,而此次尝试渲染一个视图,它可能不存在。 如果我返回视图,它将完全损坏,并且看起来根本不正确。

于更好ones,相关有没有人有思路或者解决方案可以这些问题我有,或者有好的建议?

非常感谢!

下面是一个示例。我试图做的是创建GetViewForEmail方法:


public ActionResult OrderResult(string ref)
{
//Get the order
 Order order = OrderService.GetOrder(ref);

//The email helper would do the meat and veg by getting the view as a string
//Pass the control name (OrderResultEmail) and the model (order)
 string emailView = GetViewForEmail("OrderResultEmail", order);

//Email the order out
 EmailHelper(order, emailView);
 return View("OrderResult", order);
}

在蒂姆斯科特接受 answer:


public virtual string RenderViewToString(
 ControllerContext controllerContext,
 string viewPath,
 string masterPath,
 ViewDataDictionary viewData,
 TempDataDictionary tempData)
{
 Stream filter = null;
 ViewPage viewPage = new ViewPage();

//Right, create our view
 viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);

//Get the response context, flush it and get the response filter.
 var response = viewPage.ViewContext.HttpContext.Response;
 response.Flush();
 var oldFilter = response.Filter;

 try
 {
//Put a new filter into the response
 filter = new MemoryStream();
 response.Filter = filter;

//Now render the view into the memorystream and flush the response
 viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
 response.Flush();

//Now read the rendered view.
 filter.Position = 0;
 var reader = new StreamReader(filter, response.ContentEncoding);
 return reader.ReadToEnd();
 }
 finally
 {
//Clean up.
 if (filter!= null)
 {
 filter.Dispose();
 }

//Now replace the response filter
 response.Filter = oldFilter;
 }
}

示例用法

假设从控制器调用获得订单确认电子邮件,传递 Site.Master 位置。


string myString = RenderViewToString(this.ControllerContext,"~/Views/Order/OrderResultEmail.aspx","~/Views/Shared/Site.Master", this.ViewData, this.TempData);

时间:

这是我所想到的,它也为我工作。 在控制器基类中添加了以下方法。 ( 你可以将这些静态方法放在接受控制器作为参数的其他地方)

MVC2. ascx 样式


protected string RenderViewToString<T>(string viewPath, T model) {
 ViewData.Model = model;
 using (var writer = new StringWriter()) {
 var view = new WebFormView(ControllerContext, viewPath);
 var vdd = new ViewDataDictionary<T>(model);
 var viewCxt = new ViewContext(ControllerContext, view, vdd,
 new TempDataDictionary(), writer);
 viewCxt.View.Render(viewCxt, writer);
 return writer.ToString();
 }
}

Razor 。cshtml样式


public string RenderRazorViewToString(string viewName, object model)
{
 ViewData.Model = model;
 using (var sw = new StringWriter())
 {
 var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
 viewName);
 var viewContext = new ViewContext(ControllerContext, viewResult.View,
 ViewData, TempData, sw);
 viewResult.View.Render(viewContext, sw);
 viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
 return sw.GetStringBuilder().ToString();
 }
}

编辑:添加了 Razor 代码。

在我这里可以工作:


public virtual string RenderView(ViewContext viewContext)
{
 var response = viewContext.HttpContext.Response;
 response.Flush();
 var oldFilter = response.Filter;
 Stream filter = null;
 try
 {
 filter = new MemoryStream();
 response.Filter = filter;
 viewContext.View.Render(viewContext, viewContext.HttpContext.Response.Output);
 response.Flush();
 filter.Position = 0;
 var reader = new StreamReader(filter, response.ContentEncoding);
 return reader.ReadToEnd();
 }
 finally
 {
 if (filter!= null)
 {
 filter.Dispose();
 }
 response.Filter = oldFilter;
 }
}

我发现了一个新的解决方案,它将视图呈现为字符串,而不需要处理当前 HttpContext ( 它不允许你更改响应或者其他标头的ContentType )的响应流。

基本上,你所做的就是为视图创建一个假HttpContext来呈现自己:


///<summary>Renders a view to string.</summary>
public static string RenderViewToString(this Controller controller,
 string viewName, object viewData) {
//Create memory writer
 var sb = new StringBuilder();
 var memWriter = new StringWriter(sb);

//Create fake http context to render the view
 var fakeResponse = new HttpResponse(memWriter);
 var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
 var fakeControllerContext = new ControllerContext(
 new HttpContextWrapper(fakeContext),
 controller.ControllerContext.RouteData,
 controller.ControllerContext.Controller);

 var oldContext = HttpContext.Current;
 HttpContext.Current = fakeContext;

//Use HtmlHelper to render partial view to fake context
 var html = new HtmlHelper(new ViewContext(fakeControllerContext,
 new FakeView(), new ViewDataDictionary(), new TempDataDictionary()),
 new ViewPage());
 html.RenderPartial(viewName, viewData);

//Restore context
 HttpContext.Current = oldContext; 

//Flush memory and return output
 memWriter.Flush();
 return sb.ToString();
}

///<summary>Fake IView implementation used to instantiate an HtmlHelper.</summary>
public class FakeView : IView {
 #region IView Members

 public void Render(ViewContext viewContext, System.IO.TextWriter writer) {
 throw new NotImplementedException();
 }

 #endregion
}

HTTP标头已经发送之后这个系统对 ASP.NET MVC 1.0,连同 ContentResult 。JsonResult 。等等 ( 更改原始数据源上的标头不会引发"款式 、服务器不能设置内容

ASP.NET MVC中更新: 2.0钢筋混凝土,代码变了一些,因为我们必须通过在 StringWriter 用于编写中进入了 ViewContext:的观点


//...

//Use HtmlHelper to render partial view to fake context
var html = new HtmlHelper(
 new ViewContext(fakeControllerContext, new FakeView(),
 new ViewDataDictionary(), new TempDataDictionary(), memWriter),
 new ViewPage());
html.RenderPartial(viewName, viewData);

//...

更新 2: 我有一个扩展的博客帖子,关于这个解决方案和它与其他方法的区别。 下面是第二篇关于不同解决方案性能的博客文章。

这个答案不在我的路上。 这最初来自 http://stackoverflow.com 2759898/2318354,但这里我展示了将它与"静态"关键字一起使用的方法,使得所有控制器都可以使用它。

因为你必须在类文件中创建"静态"类。 ( 假设你的类文件名是 Utils.cs )

这里示例用于 Razor 。

Utils.cs


 public static class RazorViewToString
{

 public static string RenderRazorViewToString(this Controller controller, string viewName, object model)
 {

 controller.ViewData.Model = model;
 using (var sw = new StringWriter())
 {
 var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
 var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
 viewResult.View.Render(viewContext, sw);
 viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
 return sw.GetStringBuilder().ToString();
 }
 }

}

现在可以通过在控制器文件中添加命名空间来调用这个类,方法是将"这个"作为参数传递给控制器。


string result = RazorViewToString.RenderRazorViewToString(this,"ViewName", model);

我希望这对你的代码整洁和整洁有帮助。

我使用的是 MVC 1.0 RTM,上面的解决方案都没有为我工作。 但这个是:


Public Function RenderView(ByVal viewContext As ViewContext) As String

 Dim html As String =""

 Dim response As HttpResponse = HttpContext.Current.Response

 Using tempWriter As New System.IO.StringWriter()

 Dim privateMethod As MethodInfo = response.GetType().GetMethod("SwitchWriter", BindingFlags.NonPublic Or BindingFlags.Instance)

 Dim currentWriter As Object = privateMethod.Invoke(response, BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, New Object() {tempWriter}, Nothing)

 Try
 viewContext.View.Render(viewContext, Nothing)
 html = tempWriter.ToString()
 Finally
 privateMethod.Invoke(response, BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, New Object() {currentWriter}, Nothing)
 End Try

 End Using

 Return html

End Function

如果你想完全放弃 MVC,从而避免所有的HttpContext混乱。


string razorText = System.IO.File.ReadAllText(razorTemplateFileLocation);
string emailBody = Razor.Parse(razorText, myViewModel);

这里使用了出色的开源 Razor 引擎: https://github.com/Antaris/RazorEngine

本文介绍如何将视图呈现到不同场景中的字符串:

  1. MVC控制器调用自己的ActionMethods
  2. MVC控制器调用另一个MVC控制器的ActionMethod
  3. WebAPI控制器调用一个MVC控制器的ActionMethod

解决方案/代码作为一个名为 ViewRenderer的类提供。 它是 WestwindToolkit的Rick的一部分。

用法 ( 3 。- WebAPI示例):


string html = ViewRenderer.RenderView("~/Areas/ReportDetail/Views/ReportDetail/Index.cshtml", ReportVM.Create(id));

我从另一个网站看到了 MVC 3和 Razor的实现,它为我工作:


 public static string RazorRender(Controller context, string DefaultAction)
 {
 string Cache = string.Empty;
 System.Text.StringBuilder sb = new System.Text.StringBuilder();
 System.IO.TextWriter tw = new System.IO.StringWriter(sb); 

 RazorView view_ = new RazorView(context.ControllerContext, DefaultAction, null, false, null);
 view_.Render(new ViewContext(context.ControllerContext, view_, new ViewDataDictionary(), new TempDataDictionary(), tw), tw);

 Cache = sb.ToString(); 

 return Cache;

 } 

 public static string RenderRazorViewToString(string viewName, object model)
 {

 ViewData.Model = model;
 using (var sw = new StringWriter())
 {
 var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
 var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
 viewResult.View.Render(viewContext, sw);
 return sw.GetStringBuilder().ToString();
 }
 } 

 public static class HtmlHelperExtensions
 {
 public static string RenderPartialToString(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
 {
 ViewEngineResult result = ViewEngines.Engines.FindPartialView(context, partialViewName);

 if (result.View!= null)
 {
 StringBuilder sb = new StringBuilder();
 using (StringWriter sw = new StringWriter(sb))
 {
 using (HtmlTextWriter output = new HtmlTextWriter(sw))
 {
 ViewContext viewContext = new ViewContext(context, result.View, viewData, tempData, output);
 result.View.Render(viewContext, output);
 }
 }
 return sb.ToString();
 } 

 return String.Empty;

 }

 }

更多关于 Razor render- MVC3视图呈现的更多信息

...