如何将 ASP.NET MVC 视图呈现为字符串?
我想输出两个不同的视图(一个作为字符串,将作为电子邮件发送),另一个是向用户显示的页面。
这在 ASP.NET MVC beta 中可能吗?
我尝试过多个示例:
1. ASP.NET MVC Beta 中的 RenderPartial 为字符串
如果我使用此示例,我会收到“无法在 HTTP 之后重定向 标头已发送。”。
如果我使用这个,我似乎无法执行redirectToAction,因为它 尝试渲染一个可能不存在的视图。 如果我返回视图,它 完全乱七八糟,看起来根本不正确。
有人对我遇到的这些问题有任何想法/解决方案,或者有更好的建议吗?
非常感谢!
下面是一个例子。 我想做的是创建 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);
}
接受 Tim Scott 的答案(我稍作更改和格式化):
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);
I want to output two different views (one as a string that will be sent as an email), and the other the page displayed to a user.
Is this possible in ASP.NET MVC beta?
I've tried multiple examples:
1. RenderPartial to String in ASP.NET MVC Beta
If I use this example, I receive the "Cannot redirect after HTTP
headers have been sent.".
2. MVC Framework: Capturing the output of a view
If I use this, I seem to be unable to do a redirectToAction, as it
tries to render a view that may not exist. If I do return the view, it
is completely messed up and doesn't look right at all.
Does anyone have any ideas/solutions to these issues i have, or have any suggestions for better ones?
Many thanks!
Below is an example. What I'm trying to do is create the GetViewForEmail method:
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);
}
Accepted answer from Tim Scott (changed and formatted a little by me):
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;
}
}
Example usage
Assuming a call from the controller to get the order confirmation email, passing the Site.Master location.
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
这是我想出的,它对我有用。 我将以下方法添加到我的控制器基类中。 (我认为您始终可以在其他地方创建这些静态方法,接受控制器作为参数)
MVC2 .ascx 样式
Razor .cshtml 样式
编辑:添加了 Razor 代码。
Here's what I came up with, and it's working for me. I added the following method(s) to my controller base class. (You can always make these static methods somewhere else that accept a controller as a parameter I suppose)
MVC2 .ascx style
Razor .cshtml style
Edit: added Razor code.
这个答案不在我的路上。 这最初来自 https://stackoverflow.com/a/2759898/2318354 但在这里我展示了使用方法它带有“Static”关键字,使其对所有控制器通用。
为此,您必须在类文件中创建
static
类。 (假设您的类文件名为 Utils.cs )此示例适用于 Razor。
Utils.cs
现在,您可以通过在控制器文件中添加命名空间来从控制器调用此类,方法如下,将“this”作为参数传递给控制器。
正如 @Sergey 给出的建议,这个扩展方法也可以从控制器调用,如下所示,
我希望这对您使代码干净整洁有用。
This answer is not on my way . This is originally from https://stackoverflow.com/a/2759898/2318354 but here I have show the way to use it with "Static" Keyword to make it common for all Controllers .
For that you have to make
static
class in class file . (Suppose your Class File Name is Utils.cs )This example is For Razor.
Utils.cs
Now you can call this class from your controller by adding NameSpace in your Controller File as following way by passing "this" as parameter to Controller.
As suggestion given by @Sergey this extension method can also call from cotroller as given below
I hope this will be useful to you make code clean and neat.
这对我有用:
This works for me:
我找到了一个新的解决方案,可以将视图呈现为字符串,而不必弄乱当前 HttpContext 的响应流(它不允许您更改响应的 ContentType 或其他标头)。
基本上,您所做的就是创建一个假的 HttpContext 以便视图自行呈现:
这适用于 ASP.NET MVC 1.0,以及 ContentResult、JsonResult 等(更改原始 HttpResponse 上的 headers 不会抛出“发送 HTTP 标头后,服务器无法设置内容类型”异常)。
更新:在 ASP.NET MVC 2.0 RC 中,代码发生了一些变化,因为我们必须传入用于将视图写入
ViewContext
StringWriter代码>:I found a new solution that renders a view to string without having to mess with the Response stream of the current HttpContext (which doesn't allow you to change the response's ContentType or other headers).
Basically, all you do is create a fake HttpContext for the view to render itself:
This works on ASP.NET MVC 1.0, together with ContentResult, JsonResult, etc. (changing Headers on the original HttpResponse doesn't throw the "Server cannot set content type after HTTP headers have been sent" exception).
Update: in ASP.NET MVC 2.0 RC, the code changes a bit because we have to pass in the
StringWriter
used to write the view into theViewContext
:本文介绍了如何在不同场景下将视图渲染为字符串:
解决方案/代码作为名为 ViewRenderer 的类提供。 它是 Rick Stahl GitHub 上的 WestwindToolkit。
用法(3. - WebAPI 示例):
This article describes how to render a View to a string in different scenarios:
The solution/code is provided as a class called ViewRenderer. It is part of Rick Stahl's WestwindToolkit at GitHub.
Usage (3. - WebAPI example):
如果你想完全放弃 MVC,从而避免所有 HttpContext 的混乱......
这里使用了很棒的开源 Razor 引擎:
https://github.com/Antaris/RazorEngine
If you want to forgo MVC entirely, thereby avoiding all the HttpContext mess...
This uses the awesome open source Razor Engine here:
https://github.com/Antaris/RazorEngine
ASP NET CORE 的附加提示:
接口:
实现:
在 Startup.cs 中注册
并在控制器中使用:
Additional tip for ASP NET CORE:
Interface:
Implementation:
Registration in
Startup.cs
And usage in controller:
要在服务层中渲染字符串视图而无需传递 ControllerContext,这里有一篇很好的 Rick Strahl 文章 http://www.codemag.com/Article/1312081 创建通用控制器。 代码摘要如下:
然后在Service类中渲染View:
To render a view to a string in the Service Layer without having to pass ControllerContext around, there is a good Rick Strahl article here http://www.codemag.com/Article/1312081 that creates a generic controller. Code summary below:
Then to render the View in the Service class:
您可以使用这种方式获取字符串中的视图
我们可以通过两种方式调用此方法
或
you can get the view in string using this way
We can call this method in two way
OR
我正在使用 MVC 1.0 RTM,以上解决方案都不适合我。 但这个却做到了:
I am using MVC 1.0 RTM and none of the above solutions worked for me. But this one did:
我从另一个网站看到了 MVC 3 和 Razor 的实现,它对我有用:
更多关于 Razor 渲染 - MVC3 视图渲染到字符串
I saw an implementation for MVC 3 and Razor from another website, it worked for me:
More on Razor render- MVC3 View Render to String
快速提示
对于强类型模型,只需将其添加到 ViewData.Model 属性,然后再传递给 RenderViewToString。 例如
Quick tip
For a strongly typed Model just add it to the ViewData.Model property before passing to RenderViewToString. e.g
要重复一个更未知的问题,请查看 MvcIntegrationTestFramework。
它使您无需编写自己的助手来传输结果,并且已被证明工作得足够好。 我假设这将在一个测试项目中,并且作为奖励,一旦您完成此设置,您将拥有其他测试功能。 主要的麻烦可能是整理依赖链。
To repeat from a more unknown question, take a look at MvcIntegrationTestFramework.
It makes saves you writing your own helpers to stream result and is proven to work well enough. I'd assume this would be in a test project and as a bonus you would have the other testing capabilities once you've got this setup. Main bother would probably be sorting out the dependency chain.
这是我为 ASP.NETCore RC2 编写的一个类。 我使用它是为了使用 Razor 生成 html 电子邮件。
Here is a class I wrote to do this for ASP.NETCore RC2. I use it so I can generate html email using Razor.
当我使用上述方法出错时,我找到了一种更好的方法来渲染 razor 视图页面,该解决方案适用于 Web 表单环境和 MVC 环境。
不需要控制器。
下面是代码示例,在这个示例中,我使用异步 http 处理程序模拟了 mvc 操作:
I found a better way to render razor view page when I got error with the methods above, this solution for both web form environment and mvc environment.
No controller is needed.
Here is the code example, in this example I simulated a mvc action with an async http handler:
对我来说最简单的方法是:
我将其用于电子邮件并确保该文件仅包含 CSS 和 HTML
The easiest way for me was:
I use this for emails and make sure that the file only contains CSS and HTML