发送电子邮件后代码挂起,但电子邮件发送正常(静态异步任务)



我正在编写一些C#代码来发送电子邮件(通过Mailjet/Azure(。它确实发送电子邮件,但由于某种原因,在单步执行代码时,我从未跳过这行代码......

MailjetResponse response = await client.PostAsync(request);

它只是挂在那个点上。知道为什么吗?同样,电子邮件正在正常发送!

public static async Task<bool> SendEmailWithAttachment(string toAddress, string subject, string messageBody, bool sendBCCYesNo, bool sendFromInfoAddressYesNo, MemoryStream attachment = null, string attachmentFilename = null)
{
bool successYesNo = true;
try
{
MailjetClient client = new MailjetClient("xxxxxx", "xxxxx")
{
Version = ApiVersion.V3_1,
};
MailjetRequest request = new MailjetRequest
{
Resource = Send.Resource,
}
.Property(Send.Messages, new JArray {
new JObject {
{"From", new JObject {
{"Email", "xxxxx@xxxxx.com"},
{"Name", "xxxxx"}
}},
{"To", new JArray {
new JObject {
{"Email", toAddress},
{"Name", toAddress}
}
}},
{"Subject", subject},
{"TextPart", messageBody},
{"HTMLPart", messageBody}
}
});
MailjetResponse response = await client.PostAsync(request);
if (response.IsSuccessStatusCode) // I never get to this point
{
:

我正在使用这个调用代码....

if (Utility.SendEmailWithAttachment("xxxxx@xxxxx.com", "Test Email", "Test Body", false, false,
po, "AAA.pdf").Result == false)
{
lblStatus.Text = "Email send failure. Please contact support.";
return false;
}

有趣的是,当我运行 mailjet 提供的示例代码时,电子邮件发送正常,并且我确实到达了 PostAsync 之后的行。据我所知,唯一的主要区别是我使用的是返回布尔值的任务,而不仅仅是任务。这是 mailjet 提供的代码,可以正常工作....

static void Main(string[] args)
{
RunAsync().Wait();
}
static async Task RunAsync()
{
MailjetClient client = new MailjetClient("xxxx", "xxxx")
{
Version = ApiVersion.V3_1,
};
MailjetRequest request = new MailjetRequest
{
Resource = Send.Resource,
}
.Property(Send.Messages, new JArray {
new JObject {
{"From", new JObject {
{"Email", "xxxx@xxxx.com"},
{"Name", "xxxx"}
}},
{"To", new JArray {
new JObject {
{"Email", "xxxx@xxxx.com"},
{"Name", "xxxx"}
}
}},
{"Subject", "Your email flight plan!"},
{"TextPart", "Dear passenger 1, welcome to Mailjet! May the delivery force be with you!"},
{"HTMLPart", "<h3>Dear passenger 1, welcome to <a href='https://www.mailjet.com/'>Mailjet</a>!</h3><br />May the delivery force be with you!"}
}
});
MailjetResponse response = await client.PostAsync(request);
if (response.IsSuccessStatusCode) // this line is reached!
{

提前感谢!

试试下面的代码。一个好的经验法则是不要使用 *。结果,除非先等待。

if ((await Utility.SendEmailWithAttachment("xxxxx@xxxxx.com", "Test Email", "Test Body", false, false,
po, "AAA.pdf")) == false)
{
lblStatus.Text = "Email send failure. Please contact support.";
return false;
}

在方法中

public static async Task<bool> SendEmailWithAttachment(string toAddress, string subject, string messageBody, bool sendBCCYesNo, bool sendFromInfoAddressYesNo, MemoryStream attachment = null, string attachmentFilename = null)

将以下行从:

MailjetResponse response = await client.PostAsync(request);

自:

MailjetResponse response = await client.PostAsync(request).ConfigureAwait(false);

请阅读这篇关于异步方法中死锁的精彩文章

该问题是由对.Result的调用引起的 - 这是一个阻塞调用。如果在 UI 线程中调用,它将阻止线程。这意味着应用程序通常无法响应并显得冻结,这相当丑陋。

这也意味着任何尝试在 UI 线程上恢复的await调用,例如

MailjetResponse response = await client.PostAsync(request);

不会。我将重复一遍 - 如果await client.PostAsync(request);似乎没有恢复,那是因为某些东西阻塞了 UI 线程。

await不会使任何内容异步运行,也不会启动任何线程。它等待已经运行的异步操作而不会阻塞。完成这些操作后,它将在原始同步上下文中恢复 - 在桌面应用程序中,这意味着在 UI 线程上恢复。这就是允许await后的任何代码修改 UI 的原因。

解决方案是 删除.Result.没有它,无论如何使用异步调用都是没有意义的 - 整个应用程序都会挂起,那么等待的意义何在?

假设该方法是在事件处理程序中调用的,则事件处理程序本身应变为异步。代码应该清理一下。这不会影响异步行为,但使其更易于读取和调试:

private async void button1_Click(...)
{
var ok=await Utility.SendEmailWithAttachment("xxxxx@xxxxx.com", "Test Email", "Test Body", 
false, false,po, "AAA.pdf");
if (!ok)
{
lblStatus.Text = "Email send failure. Please contact support.";
}
}

如果该方法不是事件处理程序,则应更改为异步方法。它的调用者也应该成为一个异步方法,一直到顶部 - 大多数时候,这是一个事件处理程序:

private async Task<bool> TrySend()
{
var ok=await Utility.SendEmailWithAttachment("xxxxx@xxxxx.com", "Test Email", "Test Body", 
false, false,po, "AAA.pdf");
if (!ok)
{
lblStatus.Text = "Email send failure. Please contact support.";
return false;
}
else
{
.....
return true;
}
}
private async void button1_Click(...)
{
var ok=await TrySend();
...
}

SendEmailWithAttachment本身不会尝试修改 UI,因此不需要在 UI 线程上恢复。添加ConfigureAwait(false)将允许代码在线程池线程上恢复,并让调用方决定是否在 UI 上恢复。这主要是此时的优化,但它也消除了原始死锁中的辅助阻塞点。如果有人错误地重新添加.Result,它将"仅"冻结 UI:

MailjetResponse response = await client.PostAsync(request).ConfigureAwait(false);

相关内容

  • 没有找到相关文章

最新更新