gpt4 book ai didi

c# - .Wait() 导致 TaskCanceledException

转载 作者:行者123 更新时间:2023-11-30 13:54:39 25 4
gpt4 key购买 nike

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

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: A task was canceled

问题:

1) 为什么我会收到此异常?

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

谢谢

最佳答案

1) 为什么我会收到此异常?

你得到异常是因为,

  • 原始任务成功完成,没有任何错误
  • 您正在继续并将TaskContinuationOptions设置为TaskContinuationOptions.OnlyOnFaulted
  • 由于原始任务的执行没有错误,您会得到一个AggregateException:一个任务被取消。因为延续没有执行,它被取消了

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

你可以强制同步执行,

例如

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

关于c# - .Wait() 导致 TaskCanceledException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40446298/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com