I have a function that sends out an email, like so:
public async Task SendEmail(string from, string to, string subject, string body, bool isBodyHtml = false)
        {
            await Task.Run(() =>
            {
                using (SmtpClient smtp = new SmtpClient(host, port))
                {
                    smtp.Credentials = new NetworkCredential(userName, password);
                    smtp.EnableSsl = true;
                    smtp.SendCompleted += SmtpOnSendCompleted;
                    MailMessage message = new MailMessage(from, to, subject, body);
                    message.IsBodyHtml = isBodyHtml;
                    smtp.Send(message);
                }
            }).ContinueWith(task =>
            {
                LoggingService.Instance.BusinessLogger.Error(task.Exception.Flatten().InnerException);
            }, TaskContinuationOptions.OnlyOnFaulted);
        }
As you can see it is not a "true async", but rather a "deffered execution", so that I can call this method and it wouldn't block the current calling thread.
Now, I sometimes need a way to wait for the email to be sent, before proceeding. So I call my SendMail() method like so:
EmailService.Instance.SendEmail("[email protected]", "[email protected]", "Subject", "Body text").Wait();
with a .Wait() at the end.
For some reason using .Wait() - trying to force synchronous execution, cause exception:
System.Threading.Tasks.TaskCanceledException: A task was canceled
Questions:
1) Why am I getting this exception?
2) How do I force synchronous execution of this method?
Thanks
1) Why am I getting this exception?
You are getting the exception because,
2) How do I force synchronous execution of this method?
You can force synchronous execution by,
e.g.
var task = new Task(() => { ... });
task.RunSynchronously();
Check how the below program behaves when you throw an error in the original Task and when the original Task completes without any faults by commenting/uncommenting the dummy exception. You can execute the below program at http://rextester.com/
using System;
using System.Threading.Tasks;
namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            try
            {
                DoSomething().Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex.InnerException.Message);
            }
            Console.WriteLine("DoSomething completed");
        }
        public static async Task DoSomething()
        {
            await Task.Factory.StartNew(() =>
            {
                System.Threading.Thread.Sleep(1000);
                Console.WriteLine("Doing Something");
                // throw new Exception("Something wen't wrong");
            }).ContinueWith(task =>
            {
                Console.WriteLine(task.Exception.InnerException.Message);
            }, TaskContinuationOptions.OnlyOnFaulted);
        }
    }
}
If you're only logging the exception when anything goes wrong using the ContinueWith method, then you can get rid of that ContinueWith and put a try catch block inside the original Task to catch any exceptions and log them.
static void Main(string[] args)
{
    DoSomething().Wait();
    Console.WriteLine("DoSomething completed");
    Console.ReadKey();
}
public static async Task DoSomething()
{
    await Task.Factory.StartNew(() =>
    {
        try
        {
            System.Threading.Thread.Sleep(1000);
            Console.WriteLine("Doing Something");
            throw new Exception("Something wen't wrong");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    });
}
Otherwise, if you want to do some additional work after original Task completes you can do it as follows.
namespace SO
{
    using System;
    using System.Threading.Tasks;
    class Program
    {
        static void Main(string[] args)
        {
            DoSomething().Wait();
            Console.WriteLine("DoSomething completed");
            Console.ReadKey();
        }
        public static async Task DoSomething()
        {
            await Task.Factory.StartNew(() =>
            {
                System.Threading.Thread.Sleep(1000);
                Console.WriteLine("Doing Something");
                // throw new Exception("Something wen't wrong");
            }).ContinueWith(task =>
            {
                if (task.Status == TaskStatus.Faulted)
                {
                    // log exception
                    Console.WriteLine(task.Exception.InnerException.Message);
                }
                else if (task.Status == TaskStatus.RanToCompletion)
                {
                    // do continuation work here
                }
            });
        }
    }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With