伪代码:
public ActionResult Register()
{
SendEmail(View().ToString());
return new EmptyResult();
}
public ActionResult Register()
{
SendEmail(View().ToString());
return new EmptyResult();
}
首先,您可能仍然希望从操作中返回视图,因此返回EmptyResult并不是最好的选择;但是当您处理注册流程中的页面流时,您会弄清楚这一点。
我假设您希望使用已经创建的视图创建HTML电子邮件。这意味着您希望获取类似以下内容的结果:
public ActionResult CreateEmailView(RegistrationInformation info)
{
var userInformation = Membership.CreateNewUserLol(info);
return View(userInformation)
}
并将其作为电子邮件正文发送。您可以重复使用视图和所有有趣的东西。
您可以通过创建自定义ActionResult并使用它来生成文本来利用框架。
这里是一些类似C#的伪代码,它可能实际编译并工作。首先,是自定义的ActionResult:
public class StringResult : ViewResult
{
public string Html { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (string.IsNullOrEmpty(this.ViewName))
{
this.ViewName =
context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (this.View == null)
{
result = this.FindView(context);
this.View = result.View;
}
ViewContext viewContext = new ViewContext(
context, this.View, this.ViewData, this.TempData);
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
{
// used to write to context.HttpContext.Response.Output
this.View.Render(viewContext, writer);
writer.Flush();
Html = Encoding.UTF8.GetString(stream.ToArray());
}
if (result != null)
{
result.ViewEngine.ReleaseView(context, this.View);
}
}
}
这将覆盖基本方法的ExecuteResult(这是我要重写的基本方法的代码;可能在RC1中已更改),以呈现到我控制的流而不是响应的输出流。因此,它会精确地提取出文本,就像它将被呈现给客户端机器一样。
接下来,您将如何在控制器操作中使用它:
public ActionResult CreateEmailView(RegistrationInformation info)
{
var userInformation = Membership.CreateNewUserLol(info);
// grab our normal view so we can get some info out of it
var resultView = View(userInformation);
// create our string result and configure it
StringResult sr = new StringResult();
sr.ViewName = resultView.ViewName;
sr.MasterName = resultView.MasterName;
sr.ViewData = userInformation;
sr.TempData = resultView.TempData;
// let them eat cake
sr.ExecuteResult(this.ControllerContext);
string emailHtml = sr.Html;
// awesome utils package, dude
Utils.SendEmailKThx(userInformation, emailHtml);
return resultView;
}
我没有足够的声誉来发表评论,但我想指出似乎被接受的答案可以起作用,如果它能起作用那就太好了。然而,似乎WebForm视图引擎只是吞噬了TextWriter参数。这里有更多信息:http://ayende.com/Blog/archive/2008/11/11/another-asp.net-mvc-bug-rendering-views-to-different-output-source.aspx
http://www.brightmix.com/blog/renderpartial-to-string-in-asp-net-mvc/ 提供了一个很好的解决方案,可以将视图渲染为字符串,以便您可以通过电子邮件发送。 作者指出:“渲染部分视图到字符串已经变得更加容易了。”
/// Static Method to render string - put somewhere of your choosing
public static string RenderPartialToString(string controlName, object viewData)
{
ViewDataDictionary vd = new ViewDataDictionary(viewData);
ViewPage vp = new ViewPage { ViewData = vd };
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
在控制器内部无法看到页面本身。要实现你所要求的功能,需要编写一个自定义的ActionResult子类和一个自定义的ViewEngine来处理它。重写ExecuteResult方法以实际发送电子邮件。查看MVC的开源Spark、NHAML等视图引擎以获取示例。
嘿Will,根据我所阅读的(以及我自己尝试实现您的解决方案),View.Render方法完全忽略了writer参数。我的writer内容始终为空,而渲染的视图会直接呈现在响应流中。因此,似乎无法像那样使用视图(或者至少非常复杂)。我认为在您的测试用例中,您将会看到渲染的视图两次,并且您的电子邮件将为空。