在电子邮件中发送asp.net mvc操作结果

22
我想在ASP.NET MVC中使用我的Action作为模板引擎,将结果作为字符串发送到电子邮件中。
伪代码:
public ActionResult Register()
{
    SendEmail(View().ToString());

    return new EmptyResult();
}

你能解释一下你想要做什么吗? - Craig Stuntz
用伪代码?这样更清晰吗? - Igor Golodnitsky
向Web服务器发出的请求必须返回某些内容。您希望它返回什么?HTML?JSON?还是其他东西?或者您想知道如何发送电子邮件?不,现在还不清楚。 - Craig Stuntz
你期望它返回什么? 它返回EmptyResult,在伪代码中非常清晰!我需要 - View().ToString() - Igor Golodnitsky
这里是如何将视图转换为字符串的方法。 - Tim Scott
显示剩余6条评论
5个回答

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中已更改),以呈现到我控制的流而不是响应的输出流。因此,它会精确地提取出文本,就像它将被呈现给客户端机器一样。

接下来,您将如何在控制器操作中使用它:

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方法。哦,算了吧....

通常与流有关。您在流中编写HTML,然后尝试将该流提供给其他人,他们可能不会回到开头。寻找0,你就能找到你的HTML。 - user1228
2
天啊.... MVC 1 完全忽略了流并直接写入响应。http://ayende.com/Blog/archive/2008/11/11/another-asp.net-mvc-bug-rendering-views-to-different-output-source.aspx 我想知道他们在2中是否已经修复了这个问题? - user1228

6

5

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();
}

1

在控制器内部无法看到页面本身。要实现你所要求的功能,需要编写一个自定义的ActionResult子类和一个自定义的ViewEngine来处理它。重写ExecuteResult方法以实际发送电子邮件。查看MVC的开源Spark、NHAML等视图引擎以获取示例。


0

嘿Will,根据我所阅读的(以及我自己尝试实现您的解决方案),View.Render方法完全忽略了writer参数。我的writer内容始终为空,而渲染的视图会直接呈现在响应流中。因此,似乎无法像那样使用视图(或者至少非常复杂)。我认为在您的测试用例中,您将会看到渲染的视图两次,并且您的电子邮件将为空。

我在这里找到了一些讨论:http://ayende.com/Blog/archive/2008/11/11/another-asp.net-mvc-bug-rendering-views-to-different-output-source.aspx


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接