# 添加发送电子邮件的背景信息

<!--category-- ASP.NET -->
<datetime class="hidden">2024-08-07T08:15</datetime>

##_导言

在我前一篇文章中, 我详述了如何使用流利电子邮件和 SMTP 客户端@. 发送邮件。 但其中一个问题是发电邮的延迟速度很慢,

这样用户就可以继续使用此应用程序, 不必等待电子邮件发送@. @这是网络应用中常见的模式,

[TOC]

## ASP.NET 核心中的背景选项

在 ASP.NET 核心中, 您有两个主要选项 {( 除了更高级的选项, 比如杭大火 /Quartz)}

- iHosted Service {-}% 此选项为您提供基本生命周期管理的基本背景任务@. 您可以开始并停止此服务, 它将在背景中运行\.
- Ihosted Lifetime {-}% 此选项使您更能控制您的背景任务的生命周期}. 您也可以开始和停止此服务, 它将在后台运行, 但是您有更大的控制 roundn 启动@,_ stop\, 开始 @,} 停止等+...}

在此例中, I'll 使用简单的 IHOD Service 在背景中发送邮件@ .

## 源代码

此消息的完整来源如下: @.

<details>
<summary>Background Email Service</summary>

```csharp
using System.Threading.Tasks.Dataflow;
using Mostlylucid.Email.Models;

namespace Mostlylucid.Email
{
    public class EmailSenderHostedService(EmailService emailService, ILogger<EmailSenderHostedService> logger)
        : IHostedService, IDisposable
    {
        private readonly BufferBlock<BaseEmailModel> _mailMessages = new();
        private Task _sendTask = Task.CompletedTask;
        private CancellationTokenSource cancellationTokenSource = new();

        public async Task SendEmailAsync(BaseEmailModel message)
        {
            await _mailMessages.SendAsync(message);
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            logger.LogInformation("Starting background e-mail delivery");
            // Start the background task
            _sendTask = DeliverAsync(cancellationTokenSource.Token);
            return Task.CompletedTask;
        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {
            logger.LogInformation("Stopping background e-mail delivery");

            // Cancel the token to signal the background task to stop
            await cancellationTokenSource.CancelAsync();

            // Wait until the background task completes or the cancellation token triggers
            await Task.WhenAny(_sendTask, Task.Delay(Timeout.Infinite, cancellationToken));
        }

        private async Task DeliverAsync(CancellationToken token)
        {
            logger.LogInformation("E-mail background delivery started");

            while (!token.IsCancellationRequested)
            {
                BaseEmailModel? message = null;
                try
                {if(_mailMessages.Count == 0) continue;
                    message = await _mailMessages.ReceiveAsync(token);
                    switch (message)
                    {
                        case ContactEmailModel contactEmailModel:
                            await emailService.SendContactEmail(contactEmailModel);
                            break;
                        case CommentEmailModel commentEmailModel:
                            await emailService.SendCommentEmail(commentEmailModel);
                            break;
                    }
                    logger.LogInformation("Email from {SenderEmail} sent", message.SenderEmail);
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception exc)
                {
                    logger.LogError(exc, "Couldn't send an e-mail from {SenderEmail}", message?.SenderEmail);
                    await Task.Delay(1000, token); // Delay and respect the cancellation token
                    if (message != null)
                    {
                        await _mailMessages.SendAsync(message, token);
                    }
                }
            }

            logger.LogInformation("E-mail background delivery stopped");
        }

        public void Dispose()
        {
            cancellationTokenSource.Cancel();
            cancellationTokenSource.Dispose();
        }
    }
}
```

</details>
您可以在这里看到我们处理服务启动事宜, 并设置一个新的 ButfferBlock 来控制电子邮件@. @ {}

```csharp
public class EmailSenderHostedService(EmailService emailService, ILogger<EmailSenderHostedService> logger)
        : IHostedService, IDisposable
    {
        private readonly BufferBlock<BaseEmailModel> _mailMessages = new();
        private Task _sendTask = Task.CompletedTask;
        private CancellationTokenSource cancellationTokenSource = new();
```

我们也设置了一个新的任务, 在背景中发送电子邮件@. @%
取消源代码, 当我们想停止服务时会优雅地取消任务@. @%

然后我们用StartAsync 启动托管服务,并为其他服务提供切入点,发送电子邮件@.

```csharp
 public async Task SendEmailAsync(BaseEmailModel message)
        {
            await _mailMessages.SendAsync(message);
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            logger.LogInformation("Starting background e-mail delivery");
            // Start the background task
            _sendTask = DeliverAsync(cancellationTokenSource.Token);
            return Task.CompletedTask;
        }
```

在我们的设置类中,我们现在需要 注册服务 在DI集装箱 并启动主机服务

```csharp
       services.AddSingleton<EmailSenderHostedService>();
        services.AddHostedService(provider => provider.GetRequiredService<EmailSenderHostedService>());
```

现在我们可以通过电子邮件SenderHosted Servicice@. 调用发送邮件Async方法,
@ .g., 用于我们做的联系表@.

```csharp
            var contactModel = new ContactEmailModel()
            {
                SenderEmail = user.email,
                SenderName =user.name,
                Comment = commentHtml,
            };
            await sender.SendEmailAsync(contactModel);
```

在上文的代码中,这又增加了这一信息。 `BufferBlock<BaseEmailModel>` _邮件mailMessages 和背景任务将接收并发送电子邮件@. @%

```csharp
   private async Task DeliverAsync(CancellationToken token)
        {
          ...

            while (!token.IsCancellationRequested)
            {
                BaseEmailModel? message = null;
                try
                {if(_mailMessages.Count == 0) continue;
                    message = await _mailMessages.ReceiveAsync(token);
                    switch (message)
                    {
                        case ContactEmailModel contactEmailModel:
                            await emailService.SendContactEmail(contactEmailModel);
                            break;
                        case CommentEmailModel commentEmailModel:
                            await emailService.SendCommentEmail(commentEmailModel);
                            break;
                    }
                    logger.LogInformation("Email from {SenderEmail} sent", message.SenderEmail);
           ...
            }

            logger.LogInformation("E-mail background delivery stopped");
        }
```

这将循环到我们停止服务, 并继续监视缓冲锁以获取发送@.}的新邮件