10

我想在我的 ASP.NET 应用程序中创建一个手动触发的进程,并将一堆电子邮件发送给我的用户。由于这个过程需要一段时间,我正在创建一个新线程来发送这些消息并防止我的网络应用程序超时。(我知道如果应用程序池被回收或应用程序中有未处理的异常,这很容易出错,但这是另一个主题)。

为此,我正在做这样的事情:

public ActionResult SendMessages()
{
  Task.Factory.StartNew(() => { SendMessagesLongRunningProcess(); });
  return View();
}

在长期运行的过程中,我试图呈现 HTML 电子邮件的视图并发送它。像这样:

private void SendMessagesLongRunningProcess()
{
  var users = GetUsers();
  foreach (var user in users)
  {
    string message = RenderView("EmailMessage", user);
    SendEmail(user.email, message);
  }
}

现在,我知道我的 RenderView 方法工作得很好,因为我使用它在其他地方呈现电子邮件视图。问题是当我在这里尝试在新线程中执行它时。这是我的 RenderView 方法:

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

我得到的错误是:

Value does not fall within the expected range.

当调用 viewResult.View.Render 方法时。

我猜这与控制器上下文在新线程中不再有效的事实有关,但我不确定。

那么,解决这个问题的最佳方法是什么?我有什么选择?

谢谢

4

1 回答 1

6

我猜这与控制器上下文在新线程中不再有效的事实有关,但我不确定。

恰恰。

那么,解决这个问题的最佳方法是什么?

从另一个进程发送电子邮件,而不是您的 ASP.NET MVC 应用程序。

我有什么选择?

一种可能性是使用RazorEngine

private void SendMessagesLongRunningProcess()
{
    var users = GetUsers();
    foreach (var user in users)
    {
        string view = Server.MapPath("~/Views/MailTemplates/SomeTemplate.cshtml");
        string template = System.IO.File.ReadAllText(view);
        string message = Razor.Parse(template, user);
        SendEmail(user.email, message);
    }
}

您也可以MvcMailer异步结帐和发送电子邮件(查看Send Email Asynchronously分步指南部分)。

于 2012-08-17T05:15:15.833 回答