我有一个WebService .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服务器需要太长的时间来响应。我想设置电子邮件,排队并返回而不等待结果。
仅使用未知的async出现两个原因;
在ASP
中继续使用请求上下文之外的方法是不可靠的。我需要访问我实体框架的数据库上下文来编写日志
我必须允许外部或内部SMTP(我的客户指定),因此收集文件夹不是可能性 - 至少不是没有管理它的服务。
我该如何实现?我需要写一个管理此服务的服务吗?如果是这样,我将如何在.NET Core应用程序中执行此操作,请记住,该服务还需要访问EF上下文以编写日志
update
.netcore di中有管道可用,尤其是为此。请参阅下面的其他答案。使用IservicesCopeFactory
您可以在页面对象上调用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;
}
https://www.hanselman.com/blog/themagicofusingasynchronousmethodsinaspnet45plusanimportantgotcha.aspx
因此,虽然我标记了答案,但对于我的特定示例来说,有一些选择是更好的解决方案。首先是使用诸如hangfire之类的库来安排任务的选项 - 尽管从技术上讲这不是问题的答案。
.net核心中更好的解决方案是使用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);
}
});