Back to "Hintergrund hinzufügen Senden nach E-Mails"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET

Hintergrund hinzufügen Senden nach E-Mails

Wednesday, 07 August 2024

Einleitung

In meinem vorherigen Beitrag habe ich detailliert, wie E-Mails mit FluentEmail und dem SMTP Client zu senden ist jedoch ein Problem mit diesem ist die Verzögerung beim Senden von E-Mail-Adressen sind eher langsam und kann eine Weile dauern, um E-mails zu senden.

Eine Möglichkeit, um dies herum zu bekommen ist es, E-Mails im Hintergrund zu senden - . - Auf diese Weise kann der Benutzer die Anwendung weiter verwenden, ohne warten zu müssen, bis die E-Mail gesendet wird -. - Dies ist ein gängiges Muster in Webanwendungen und kann mit einem Hintergrundjob erreicht werden

Hintergrund-Optionen im ASP-.-NET-Kern

Im ASPA.-NET Core haben Sie zwei Hauptoptionen, neben fortgeschritteneren Optionen wie Hangfire und Quartz.).

  • IHostedService Diese Option gibt Ihnen grundlegendes Lifecycle Management für Ihre Hintergrundaufgaben. Sie können den Dienst starten und stoppen und er wird im Hintergrund ausgeführt.
  • IHostedLifetime Diese Option gibt Ihnen mehr Kontrolle über den Lebenszyklus Ihrer Hintergrundaufgaben. Sie können auch starten und stoppen Sie den Service, und es wird im Hintergrund laufen, aber Sie haben mehr Steuerung arudn starting...

In diesem Beispiel verwendet I'-ll einen einfachen IHostedService, um E-Mails im Hintergrund zu senden.

Quellencode

Die vollständige Quelle dafür ist unten.

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();
        }
    }
}
Hier sehen Sie, wie wir mit dem Start des Dienstes umgehen und einen neuen BufferBlock einrichten, um die E-Mails zu halten.
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();

Wir haben auch eine neue Aufgabe eingerichtet, um die E-Mails im Hintergrund zu liefern. und eine CancellationTokenSource, um die Aufgabe anmutig zu stornieren, wenn wir den Service beenden möchten.

Wir starten dann den HostedService mit StartAsync und stellen die Einstiegsstelle für andere Dienste zur Verfügung, um eine E-Mail zu senden.

 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;
        }

In unserer Setup-Klasse müssen wir jetzt den Service mit dem DI Container registrieren und den HostedService starten

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

Jetzt können wir E-Mails im Hintergrund senden, indem wir die SendEmailAsync-Methode auf dem EmailSenderHosteredService Rufen. für das Kontaktformular, das wir dies tun

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

Im obigen Code fügt dies diese Botschaft zu unserer BufferBlock<BaseEmailModel> _mailNachrichte und die Hintergrundaufgabe wird es abholen und senden Sie die e-Mail.

   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");
        }

Dies wird dann Schleife, bis wir den Service zu stoppen und weiterhin die BufferBlock für neue E-Mails zu send.

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.