【问题标题】:Sending an async email without await from a .Net core web service从 .Net 核心 Web 服务发送异步电子邮件而无需等待
【发布时间】:2018-03-13 07:52:36
【问题描述】:

我有一个网络服务 .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 服务器响应时间过长。我想设置电子邮件,将其排队并返回而不等待结果。

仅使用未等待的异步有两个原因;

  1. 在asp中继续请求上下文之外的方法是不可靠的

  2. 我需要访问我的实体框架的数据库上下文来编写日志

我必须允许外部或内部 SMTP(我的客户指定),因此不可能使用集合文件夹 - 至少在没有管理它的服务的情况下是不可能的。

我怎样才能做到这一点?我需要编写一个管理这个的服务吗?如果是这样,我将如何在我的 .Net Core 应用程序中执行此操作,请记住该服务还需要访问 EF 上下文以写入日志

更新

.NetCore DI 中提供了专门用于此的管道。请参阅下面我的附加答案。使用 IServiceScopeFactory

【问题讨论】:

    标签: entity-framework async-await asp.net-core-webapi


    【解决方案1】:

    因此,虽然我已经标记了答案,但对于我的具体示例,有几个选项是更好的解决方案。首先是使用 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);
                }
            });
    

    【讨论】:

      【解决方案2】:

      您可以在 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;
      }
      

      https://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-02
        • 2022-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多