ASP.NET MVC: Exception rendering view in new thread

I want to create a process in my ASP.NET application that I trigger manually and will send a bunch of emails to my users. Since this process takes a while I am creating a new thread to send these messages and prevent having timeouts in my web app. (I know this is error prone in case the app pool is recycled or there’s an unhandled exception in the app, but that’s another subject).

For that I’m doing something like this:

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

inside the long running process I’m trying to render the view for the HTML email and send it. Like this:

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

Now, I know that my RenderView method works just fine since I use it to render email views in other places. The problem is when I try to execute it in a new thread as I’m doing here.
This is my RenderView method:

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

The error I’m getting is:

Value does not fall within the expected range.

When the viewResult.View.Render method is called.

I’m guessing this has to do with the fact that the controller context is no longer valid in the new thread, but I’m not sure.

So, what is the best way to approach this? What alternatives do I have?

Thanks

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I’m guessing this has to do with the fact that the controller context
is no longer valid in the new thread, but I’m not sure.

Precisely.

So, what is the best way to approach this?

Send emails from another process, not your ASP.NET MVC application.

What alternatives do I have?

One possibility is to use 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);
    }
}

You might also checkout MvcMailer and send the email asynchronously (take a look at the Send Email Asynchronously section of the step-by-step-guide).


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x