我想在asp.net mvc中使用我的Action作为模板引擎,它会产生字符串形式,我可以通过电子邮件发送.
伪代码:
public ActionResult Register() { SendEmail(View().ToString()); return new EmptyResult(); }
小智.. 13
首先,你仍然可能想要从你的动作返回一个视图,所以返回一个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中已更改)以呈现为我控制的流而不是Response的输出流.因此,它会准确地提取文本如何呈现给客户端计算机.
接下来,如何在控制器操作中使用它:
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; }
我两次渲染相同的视图; 我第一次将它渲染到流中,第二次我正常渲染它.有可能潜入其他地方的ViewResult调用链并改变Render的操作方式,但粗略地看一眼代码并没有透露任何东西.虽然框架非常好,但部分流程的调用堆栈不够精细,无法轻松更改流程中的单个步骤.如果他们将ExecuteResult分解为几个不同的可覆盖方法,我们可以将它从渲染更改为输出流,以渲染到我们的流,而不会覆盖整个ExecuteResult方法.那好吧....
首先,你仍然可能想要从你的动作返回一个视图,所以返回一个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中已更改)以呈现为我控制的流而不是Response的输出流.因此,它会准确地提取文本如何呈现给客户端计算机.
接下来,如何在控制器操作中使用它:
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; }
我两次渲染相同的视图; 我第一次将它渲染到流中,第二次我正常渲染它.有可能潜入其他地方的ViewResult调用链并改变Render的操作方式,但粗略地看一眼代码并没有透露任何东西.虽然框架非常好,但部分流程的调用堆栈不够精细,无法轻松更改流程中的单个步骤.如果他们将ExecuteResult分解为几个不同的可覆盖方法,我们可以将它从渲染更改为输出流,以渲染到我们的流,而不会覆盖整个ExecuteResult方法.那好吧....
我没有足够的评论来评论,但我想我会节省一些时间,指出似乎接受的答案会起作用,如果它确实会很好.但是,似乎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/有一个很好的解决方案,可以将View渲染为字符串,以便您可以通过电子邮件发送它.他指出"幸运的是,渲染部分视图到字符串变得更容易了."
/// 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(); }