从 .Net 核心 Web 服务发送不等待的异步电子邮件
Sending an async email without await from a .Net core web service
我有一个网络服务 .Net core2,它具有某些发送电子邮件的方法。我使用 smtpclient.sendemailasync
.
它工作正常
public async Task<bool> SendEmailAsync(MailMessage email)
{
try
{
if (string.IsNullOrWhiteSpace(emailFrom)) email.From = new MailAddress(emailFrom);
using (SmtpClient client = getSMTPClientInstance())
{
await client.SendMailAsync(email);
}
return true;
}
catch (Exception ex)
{
Log.Error(ex, "Error sending email in EmailService.SendEmailAsync");
return false;
}
}
唯一的问题是某些 SMTP 服务器的响应时间有点太长。我想设置电子邮件,将其排队并 return 而无需等待结果。
仅使用未等待的异步有两个原因;
在 asp
中继续请求上下文之外的方法是不可靠的
我需要访问我的 entity framework 的数据库上下文来写日志
我必须允许外部或内部 SMTP(我的客户指定),所以集合文件夹是不可能的 - 至少在没有管理它的服务的情况下是不可能的。
我怎样才能做到这一点?我是否需要编写管理此服务的服务?如果是这样,我将如何在我的 .Net Core 应用程序中执行此操作,请记住该服务还需要访问 EF 上下文以写入日志
更新
.NetCore DI 中有专门用于此的管道。请参阅下面我的附加答案。使用 IServiceScopeFactory
您可以调用 Page 对象的 RegisterAsyncTask
方法。这将向 ASP.NET 运行时发出信号,以确保在终止请求上下文之前完成这些操作:
示例:
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");
var clientlocation = Client.DownloadStringTaskAsync("api/location");
await Task.WhenAll(clientcontacts, clienttemperature, clientlocation);
var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await clientcontacts);
var location = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clientlocation);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clienttemperature);
listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature;
Location.Text = location;
}
因此,虽然我已经标记了一个答案,但对于我的具体示例,有几个选项是更好的解决方案。首先是使用像 hangfire 这样的库来安排任务的选项——尽管从技术上讲这不是问题的答案。
.net core 中更好的解决方案是使用 IServiceScopeFactory
使用 IServiceScopeFactory,您可以重新确定任务的范围,以便在请求完成时它不会超出范围。我直接在控制器中执行了以下操作(后来我转而使用 hangfire 方法,但这很有效)。如您所见,在控制器代码继续执行的同时,异步任务在一个新的未等待线程中被触发。
var task = Task.Run(async () =>
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<ApprovalService>();
await service.sendResponseEmailAsync(approvalInfo.ApprovalId, userID, approvalInfo.emailTo, approvalInfo.ccTo);
}
});
我有一个网络服务 .Net core2,它具有某些发送电子邮件的方法。我使用 smtpclient.sendemailasync
.
public async Task<bool> SendEmailAsync(MailMessage email)
{
try
{
if (string.IsNullOrWhiteSpace(emailFrom)) email.From = new MailAddress(emailFrom);
using (SmtpClient client = getSMTPClientInstance())
{
await client.SendMailAsync(email);
}
return true;
}
catch (Exception ex)
{
Log.Error(ex, "Error sending email in EmailService.SendEmailAsync");
return false;
}
}
唯一的问题是某些 SMTP 服务器的响应时间有点太长。我想设置电子邮件,将其排队并 return 而无需等待结果。
仅使用未等待的异步有两个原因;
在 asp
中继续请求上下文之外的方法是不可靠的
我需要访问我的 entity framework 的数据库上下文来写日志
我必须允许外部或内部 SMTP(我的客户指定),所以集合文件夹是不可能的 - 至少在没有管理它的服务的情况下是不可能的。
我怎样才能做到这一点?我是否需要编写管理此服务的服务?如果是这样,我将如何在我的 .Net Core 应用程序中执行此操作,请记住该服务还需要访问 EF 上下文以写入日志
更新
.NetCore DI 中有专门用于此的管道。请参阅下面我的附加答案。使用 IServiceScopeFactory
您可以调用 Page 对象的 RegisterAsyncTask
方法。这将向 ASP.NET 运行时发出信号,以确保在终止请求上下文之前完成这些操作:
示例:
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");
var clientlocation = Client.DownloadStringTaskAsync("api/location");
await Task.WhenAll(clientcontacts, clienttemperature, clientlocation);
var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await clientcontacts);
var location = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clientlocation);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clienttemperature);
listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature;
Location.Text = location;
}
因此,虽然我已经标记了一个答案,但对于我的具体示例,有几个选项是更好的解决方案。首先是使用像 hangfire 这样的库来安排任务的选项——尽管从技术上讲这不是问题的答案。
.net core 中更好的解决方案是使用 IServiceScopeFactory
使用 IServiceScopeFactory,您可以重新确定任务的范围,以便在请求完成时它不会超出范围。我直接在控制器中执行了以下操作(后来我转而使用 hangfire 方法,但这很有效)。如您所见,在控制器代码继续执行的同时,异步任务在一个新的未等待线程中被触发。
var task = Task.Run(async () =>
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<ApprovalService>();
await service.sendResponseEmailAsync(approvalInfo.ApprovalId, userID, approvalInfo.emailTo, approvalInfo.ccTo);
}
});