When a user registers on my website, I don't see why I need to make him "wait" for the smtp to go through so that he gets an activation email.
I decided I want to launch this code asynchronously, and it's been an adventure.
Lets imagine I have a method, such as:
private void SendTheMail() { // Stuff }
My first though.. was threading. I did this:
Emailer mailer = new Emailer();
Thread emailThread = new Thread(() => mailer.SendTheMail());
emailThread.Start();
This works... until I decided to test it for error-handling capability. I purposely broke the SMTP server address in my web.config and tried it. The scary result was that IIS basically BARFED with an unhandled exception error on w3wp.exe (it was a windows error! how extreme...) ELMAH (my error logger) did NOT catch it AND IIS was restarted so anyone on the website had their session erased. Completely unacceptable result!
My next thought, was to do some research on Asynchronous delegates. This seems to work better because exceptions are being handled within the asynch delegate (unlike the thread example above). However, i'm concerned if i'm doing it wrong or maybe I'm causing memory leaks.
Here's what i'm doing:
Emailer mailer = new Emailer();
AsyncMethodCaller caller = new AsyncMethodCaller(mailer.SendMailInSeperateThread);
caller.BeginInvoke(message, email.EmailId, null, null);
// Never EndInvoke...
Am I doing this right?
As of .NET 4.5 SmtpClient implements async awaitable method
SendMailAsync
. As a result, to send email asynchronously is as the following:Use this way-
So, why not have a separate poller/service which deals exclusively with sending emails? Thus, allowing your registration post-back to execute in only the time it takes to write to the database/message queue and delaying the sending of the email til the next polling interval.
I'm pondering the same issue just now and I'm thinking that I really don't want to even initiate the email sending within the server post back request. The process behind serving the web pages should be interested in getting a response back to the user ASAP, the more work you try to do the slower it will be.
Have a look at the Command Query Segregation Principal (http://martinfowler.com/bliki/CQRS.html). Martin Fowler explains that different models can be used in the command part of an operation than are used in the query part. In this scenario the command would be "register user", the query would be the activation email, using the loose analogy. The pertinent quote would probably be:
Also worth a read is the Wikipedia article on CQRS (http://en.wikipedia.org/wiki/Command%E2%80%93query_separation). An important point which this highlights is:
Meaning, use it where your code, program execution and programmer understanding would benefit. This being a good example scenario.
This approach has the added benefit of negating all the mufti-threading concerns and the headaches all that can bring.