Entity framework 从.Net核心web服务发送异步电子邮件而不等待
我有一个webservice.NETCore2,它有一些发送电子邮件的方法。我使用smtpclient.sendemailasync可以很好地工作 唯一的问题是,一些SMTP服务器的响应时间有点太长。我想设置电子邮件,排队并返回,而不必等待结果 仅仅使用一个未等待的异步是出于两个原因 在asp中,在请求上下文之外继续方法是不可靠的 我需要访问实体框架的数据库上下文才能编写日志 我必须允许客户端指定外部或内部SMTP,因此不可能创建集合文件夹-至少在没有管理它的服务的情况下是这样 我怎样才能做到这一点?我需要写一个服务来管理这个吗?如果是这样的话,我将如何在我的.Net核心应用程序中做到这一点,请记住该服务还需要访问EF上下文才能编写日志 更新 NetCore DI中有管道可供使用,尤其适用于此。请参阅下面我的补充答案。使用IServiceScopeFactory您可以调用页面对象上的RegisterAsyncTask方法。这将向ASP.NET运行时发出信号,表明您希望在终止请求上下文之前确保这些操作已完成: 例如:Entity framework 从.Net核心web服务发送异步电子邮件而不等待,entity-framework,async-await,asp.net-core-webapi,Entity Framework,Async Await,Asp.net Core Webapi,我有一个webservice.NETCore2,它有一些发送电子邮件的方法。我使用smtpclient.sendemailasync可以很好地工作 唯一的问题是,一些SMTP服务器的响应时间有点太长。我想设置电子邮件,排队并返回,而不必等待结果 仅仅使用一个未等待的异步是出于两个原因 在asp中,在请求上下文之外继续方法是不可靠的 我需要访问实体框架的数据库上下文才能编写日志 我必须允许客户端指定外部或内部SMTP,因此不可能创建集合文件夹-至少在没有管理它的服务的情况下是这样 我怎样才能做到这
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;
}
您可以在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内核中更好的解决方案是使用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);
}
});
因此,虽然我已经给出了答案,但对于我的具体示例,有几个选项是更好的解决方案。第一个选项是使用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);
}
});