Додання фонового відправлення для е-мейлів
##Введення
У своєму попередньому пості я описав, як надсилати електронні листи за допомогою FluentEmail і SMTP Client. Однак, однією з проблем з цим є затримка надсилання електронних листів . Сервери SMTP мають тенденцію бути повільними і можуть зайняти деякий час, щоб надіслати електронні листи МSK2 Це може бути неприємно для користувачів та відчувати себе як логам у вашій програміM SK3
Один із способів подолати це - надсилати електронні листи у фоні.. Таким чином пользователь може продовжувати використовувати додаток, не мусив чекати, поки його відправлять.
Опції в основі ASP.NET
В ASP.NET Core ви маєте дві головні варіанти ( окрім більш заawansованих варіантів, таких як Hangfire / QuartzM SK3
- IHostedService - ця опція дає вам базове управління життєвим циклом для ваших фонових задач . Ви можете запустити і зупинити службу, і вона буде працювати в фоні
- IHostedLifetime - ця опція дає вам більше контролю над життєвим циклом ваших задач у фоні . Ви також можете запустити і зупинити службу, і вона буде працювати в фоні, але ви маєте більше контролю, коли запускаєш МSK2 зупиняєшся МСК3 запускає М СК4 зупинює і т.д.
У цьому прикладі я' використаю просту IHostedService, щоб надсилати електронні листи у фоні
Источник
Полне джерело для цього є внизу.
Background Email Service
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();
}
}
}
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();
Ми також створили нову задачу для доставки електронних листів у фоні. і CancellationTokenSource, щоб скасувати задачу граційно, коли ми хочемо зупинити службу.
Потім ми запускаємо HostedService з StartAsync і забезпечуємо вхідним пунктом для інших послуг, щоб відправити електронну пошту.
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 і розпочати ХостингСервіс .
services.AddSingleton<EmailSenderHostedService>();
services.AddHostedService(provider => provider.GetRequiredService<EmailSenderHostedService>());
Тепер ми можемо надсилати електронні листи в фоні, використовуючи метод SendEmailAsync на EmailSenderHostedService. e.gM SK1 для контактного бланка ми робимо це
var contactModel = new ContactEmailModel()
{
SenderEmail = user.email,
SenderName =user.name,
Comment = commentHtml,
};
await sender.SendEmailAsync(contactModel);
В коді вище це додає це повідомлення до нашого BufferBlock<BaseEmailModel> _mailMessages і фонова задача візьмуть його і відправлять повідомлення.
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");
}
Це буде повторюватися, доки ми не зупинимо службу і не продолжимо перевіряти BufferBlock для нових повідомлень.