5

I've tried following this link Asynchronous call but some classes are obsolete.
So I want an exact answer for my project.

public class RegisterInfo
{
    public bool Register(UserInfo info)
    {
        try
        {
            using (mydatabase db = new mydatabase())
            {
                userinfotable uinfo = new userinfotable();
                uinfo.Name = info.Name;
                uinfo.Age = info.Age;
                uinfo.Address = info.Address;

                db.userinfotables.AddObject(uinfo);
                db.SaveChanges();

                // Should be called asynchronously
                Utility.SendEmail(info); // this tooks 5 to 10 seconds or more.

                return true;
            }
        }
        catch { return false; }
    }
} 

public class UserInfo
{
    public UserInfo() { }

    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
}  

public class Utility
{
    public static bool SendEmail(UserInfo info)
    {
        MailMessage compose = SomeClassThatComposeMessage(info);
        return SendEmail(compose);
    }

    private static bool SendEmail(MailMessage mail)
    {
        try
        {
            SmtpClient client = new SmtpClient();
            client.Host = "smtp.something.com";
            client.Port = 123;
            client.Credentials = new System.Net.NetworkCredential("username@domainserver.com", "password");
            client.EnableSsl = true;

            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
            client.Send(mail);

            return true;
        }
        catch { return false; }
    }
}    

Please look at the Register method. After saving the data, I don't want to wait for the sending of mail. If possible I want to process the sending of mail on other thread so the user will not wait for a longer time.
I don't need to know if mail has sent successfully.
Hope you could understand what I mean. Sorry for my bad English.

M.Babcock
  • 18,753
  • 6
  • 54
  • 84
fiberOptics
  • 6,955
  • 25
  • 70
  • 105
  • There is a bug in your code when the SendEmail function throws an exception, it will return false but in the Register function it will still return true. This is assuming that the bool signifies success/failure. – cubski Apr 12 '12 at 04:34
  • Thanks for the concern, but this not the original code. I just wanted to know how to make an asynchronous call. – fiberOptics Apr 12 '12 at 07:59
  • possible duplicate of [How to call any method asynchronously in c#](http://stackoverflow.com/questions/5563299/how-to-call-any-method-asynchronously-in-c-sharp) – nawfal Jun 10 '14 at 10:14

3 Answers3

14

Using Thread:

new Thread(() => Utility.SendEmail(info)).Start();

Using ThreadPool:

ThreadPool.QueueUserWorkItem(s => Utility.SendEmail(info));

Using Task:

Task.Factory.StartNew(() => Utility.SendEmail(info));

Of course Thread and ThreadPool require using System.Threading while Task requires using System.Threading.Tasks


As stated by David Anderson, SmtpClient already supports asynchronous send (I probably should have paid attention to the content of the function rather than answering the question), so technically you could just use that to handle the send though it won't offload the processing of your entire method.

Community
  • 1
  • 1
M.Babcock
  • 18,753
  • 6
  • 54
  • 84
  • First time I saw this with lambda expression. Took some seconds to figure out how it worked. +1 – Ramesh Apr 12 '12 at 03:48
  • 1
    @DavidAnderson - Appreciated. I've actually used it in the past in MVC with much success so I'm surprised to hear that it isn't recommended. – M.Babcock Apr 12 '12 at 04:55
  • Erg, you'll have to mind me it has been a extremely very long day. There is nothing wrong with using System.Net.Mail.SmtpClient. System.Web.Mail.SmtpMail is obsolete and you should use *.Net.Mail.SmtpClient. (Read my updated post) – David Anderson Apr 12 '12 at 05:01
3

SmtpClient has already has a SendAsync method. You don't need to write your own asynchronous code to do this.

@Comment regarding that SmtpClient does not work out of the box with ASP.NET:
This is absolutely just not true, it works great and is the recommended API. You however must understand the ASP.NET Page Life-Cycle and how threading behaves on the server. Otherwise there is no reason not to use it.

David Anderson
  • 13,558
  • 5
  • 50
  • 76
  • From your link, I saw that it will not work fine out of box with ASP.NET. Just want to highlight this http://blog.jdconley.com/2009/01/fire-and-forget-email-webservices-and.html – Ramesh Apr 12 '12 at 03:54
  • You need to setup your page to allow for asynchronous methods and make sure you are following the pages life-cycle properly. There isn't anything wrong with using SendAsync otherwise. The blog discusses a problem with load, which isn't an issue with good design and proper hardware for the expected load of your pages. – David Anderson Apr 12 '12 at 04:49
2

Or using Async CTP.

public async Task<bool> Register(UserInfo info)
{
    try
    {
        using (mydatabase db = new mydatabase())
        {
            userinfotable uinfo = new userinfotable();
            uinfo.Name = info.Name;
            uinfo.Age = info.Age;
            uinfo.Address = info.Address;

            db.userinfotables.AddObject(uinfo);
            db.SaveChanges();

            //Wait for task to finish asynchronously
            await Utility.SendEmail(info);

            return true;
        }
    }
    catch { return false; }
}

private Task SendEmail(MailMessage mail)
{
    SmtpClient client = new SmtpClient();
    client.Host = "smtp.something.com";
    client.Port = 123;
    client.Credentials = new System.Net.NetworkCredential("username@domainserver.com", "password");
    client.EnableSsl = true;

    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);

    //The smtp SendTaskAsync is an extension method when using Async CTP
    return client.SendTaskAsync("from", "recipients", "subject", "body");
}

There is also a bug in your original code. When an exception is thrown inside SendEmail function, it returns false but inside the register function it will still return true. Assuming that the bool signifies success or failure.

cubski
  • 3,218
  • 1
  • 31
  • 33