首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >.Wait()导致TaskCanceledException

.Wait()导致TaskCanceledException
EN

Stack Overflow用户
提问于 2016-11-06 05:27:13
回答 1查看 5.1K关注 0票数 5

我有一个发送电子邮件的功能,如下所示:

代码语言:javascript
复制
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()方法:

代码语言:javascript
复制
EmailService.Instance.SendEmail("from@blah.com", "to@blah.com", "Subject", "Body text").Wait();

最后是一个.Wait()。

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

System.Threading.Tasks.TaskCanceledException:一个任务被取消了

问题:

( 1)我为什么要得到这一例外?

2)如何强制该方法的同步执行?

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-11-06 06:52:03

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

你得到这个例外是因为,

  • 原始任务顺利完成,没有任何错误
  • 您有一个TaskContinuationOptions设置为TaskContinuationOptions.OnlyOnFaulted延续
  • 由于原始任务的执行没有错误,所以会得到一个AggregateException:一个任务被取消了。

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

你可以强制同步执行,

例如:

代码语言:javascript
复制
var task = new Task(() => { ... });
task.RunSynchronously();

检查当您在原始任务中抛出错误时,以及当原始任务通过注释/取消注释虚拟异常而完成时,下面的程序是如何运行的。您可以在http://rextester.com/上执行以下程序

代码语言:javascript
复制
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,并在原始任务中放置一个尝试捕获块,以捕获任何异常并记录它们。

代码语言:javascript
复制
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);
        }
    });
}

否则,如果您想在原始任务完成后做一些额外的工作,您可以这样做:

代码语言:javascript
复制
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
                }
            });
        }
    }
}
票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40446298

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档