views:

107

answers:

1

ASP.NET MVC 1 doesn't support asynchronous threads spawned inside of a controller (yet, there is stuff in the Futures assembly and MVC 2 Preview, but nothing in production level release). However, I want to send my email asynchronously and I'm currently exploring options to do so.

Once seemingly easy option, instead of actually sending the email synchronously, appears to set the delivery method to drop directory instead of sending it, and then have the SMTP server pick up the email at its own pace.

Is the performance of using the drop directory similar to using asynchronous email sending?

A: 

SmtpClient actually has SendAsync method which can be used.


UPDATE:

After further analyzing this scenario it seems that using SmtpClient.SendAsync inside a synchronous controller throws the following exception:

Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the Async attribute set to true and an asynchronous operation can only be started on a page prior to PreRenderComplete event.

As a workaround a manual thread can be spawned:

public ActionResult Index()
{
    new Thread(() =>
    {
        // TODO: Add exception handling here:
        var client = new SmtpClient("host");
        client.Send("from", "to", "subject", "body");
    }).Start();

    return View();
}
Darin Dimitrov
As I stated in my question, I can't use asynchronous sending because ASP.NET MVC controllers don't support asynchronous thread spawning (which renders SendAsync unusable.)
Alex
Do you need to wait for the mail to be actually sent in order to render the page? I've proposed this because this is a common scenario for a fire-and-forget action.
Darin Dimitrov
No I don't need to wait, and I don't want to wait for the email to be sent. I'm just bound by the ASP.NET MVC framework that I can't start asynchronous operations from a controller so I'm trying to figure out a way around the issue of being forced to send synchronously, or at least get performance that is comparable to asynchronous sending.
Alex
So then the SendAsync method is exactly what you need! You just call it from your controller action and forget about it. It will just spawn a background thread from the pool, send the mail and return, the view might be long rendered before the callback is actually invoked. There's nothing wrong with this approach. You can also spawn a thread manually and call the Send method in it.
Darin Dimitrov
Asynchronous controllers are useful in scenarios when you have some I/O-bound requests and your view depends on the results of these operations (File operations, ADO.NET, web service calls, ...).
Darin Dimitrov
It seems like you don't know ASP.NET MVC. I wrote in the first sentence "ASP.NET MVC 1 doesn't support asynchronous threads spawned inside of a controller". That means *no background thread is allowed*, including methods that *create* a background thread (such as SendAsync). If I try SendAsync I get a runtime *error* because I'm *not allowed* to use asynchronous methods. That's why I was looking for a work around in the first place. I know SendAsync but it does *not* help in this case.
Alex
"ASP.NET MVC 1 doesn't support asynchronous threads spawned inside a controller", could you point to some documentation stating this. Because the following action works perfectly well:public ActionResult Index(){ new Thread(() => Thread.Sleep(5000)).Start(); return View();}
Darin Dimitrov
What kind of runtime error are you getting when you call SendAsync?
Darin Dimitrov
I'll test your workaround solution. While I understand that new Thread() is already creating a new thread, can you in this scenario call .SendAsync inside the new Thread() part as well?
Alex
IMHO calling .SendAsync inside a new Thread is useless because it will create yet another thread. If you want to use a thread from the thread pool you could use ThreadPool.QueueUserWorkItem method.
Darin Dimitrov