.Wait() causes TaskCanceledException

本文关键字:TaskCanceledException causes Wait | 更新日期: 2023-09-27 18:16:27

我有一个发送电子邮件的函数,像这样:

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

正如你所看到的,它不是一个"真正的异步",而是一个"延迟执行",所以我可以调用这个方法,它不会阻塞当前调用线程。

现在,我有时需要一种方法等待电子邮件发送,然后再继续。所以我这样调用SendMail()方法:

EmailService.Instance.SendEmail("from@blah.com", "to@blah.com", "Subject", "Body text").Wait();

以. wait()结尾

由于某些原因,使用.Wait() -试图强制同步执行,导致异常:

System.Threading.Tasks。TaskCanceledException: task was cancelled

问题:

1)为什么我得到这个异常?

2)我如何强制同步执行这个方法?

谢谢

.Wait() causes TaskCanceledException

1)为什么我得到这个异常?

你得到异常是因为,

  • 原始任务成功完成,无任何故障
  • 你有一个延续TaskContinuationOptions设置为TaskContinuationOptions。OnlyOnFaulted
  • 由于在原始Task的执行中没有错误,因此您将获得AggregateException: a Task被取消。因为延续没有执行,它被取消了

2)如何强制同步执行这个方法?

你可以强制同步执行,

  • 使用任务。等待方法(TimeSpan)
  • 使用任务。runsynchronous Method ()

var task = new Task(() => { ... });
task.RunSynchronously();

通过注释/取消注释虚拟异常,检查以下程序在原始任务中抛出错误时的行为,以及原始任务在没有任何错误的情况下完成时的行为。您可以在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);
        }
    }
}

如果你只是在使用ContinueWith方法出错时才记录异常,那么你可以去掉ContinueWith,并在原始任务中放置一个try catch块来捕获任何异常并记录它们。

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

否则,如果您想在原始任务完成后做一些额外的工作,您可以按如下操作。

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
                }
            });
        }
    }
}
相关文章:
  • 没有找到相关文章