簡體   English   中英

我如何調整此代碼以使用單個實例而不是創建服務的多個實例?

[英]How can I adapt this code to use a single instance instead of creating multiple instances of a service?

我正在編寫一個發送電子郵件的服務,我想同時發送多個 email 通知。 我目前擁有的是:

    private void SendInstantMailNotification(string notificationId)
    {
        MailMessage? message = null;
        var notifications = _dbContext
                .Notifications
                .Where(x => x.Id.Equals(notificationId))
                .ToList();

        var notification = notifications.First();

       message = notification.Content;

       Smtp.SendMailSync(message, SmtpConfiguration, Smtp.MailTypeEnum.HTML);
    }

代碼的最后一行創建了“SMTP”服務的一個實例。 每次我想發送 email 時,都會創建一個新實例。 如何在不使系統過載的情況下實現僅創建一個實例並多次調用?

這是構造函數:

    private readonly NotificationQueueContext _dbContext;

    protected NotificationQueueService(NotificationQueueContext dbContext)
    {
        _dbContext = dbContext;
    }

據我了解,您需要一種機制來順序運行某些任務。 所以我創建了一個后台服務,它創建了一個SMTP client一次和一個ConcurrentQueue來保存郵件請求並一個一個地運行它們。

該服務將在您的應用程序的整個過程中處於活動狀態,因此其中包含while(TRUE) 在每個 email 發送后等待500毫秒。

如果你想從其他服務發送郵件,你只需要調用RegisterMailRequest來排隊郵件請求。

您應該將此服務定義為HostedService ,如下所示: services.AddHostedService<SequentialJobHandler>();

using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using MailKit.Net.Smtp;
using Microsoft.Extensions.Hosting;
using MimeKit;

namespace Sample
{
    public class SequentialJobHandler : BackgroundService
    {
        private readonly string MailServerAddress;
        private readonly int MailServerPort;
        private readonly string AdminEmailAccount;
        private readonly string AdminEmailAccountPass;
        private readonly string MailUser;
        private readonly string MailTitle;
        private ConcurrentQueue<MailRequest> queue = new ConcurrentQueue<MailRequest>();


        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            using (var client = new SmtpClient())
            {
                // For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                await client.ConnectAsync(MailServerAddress, MailServerPort, MailKit.Security.SecureSocketOptions.Auto);

                // Note: only needed if the SMTP server requires authentication
                await client.AuthenticateAsync(MailUser, AdminEmailAccountPass);


                while (true)
                {
                    MailRequest localValue = null;
                    if (queue.TryDequeue(out localValue))
                    {
                        if (localValue != null)
                        {
                            SendMail(localValue, client);    
                        }
                    }
                    Thread.Sleep(500);
                }
                //await client.DisconnectAsync(true);
            }
        }


        private async Task SendMail(MailRequest request, SmtpClient client)
        {
            var message = new MimeMessage();
            message.From.Add(new MailboxAddress(MailTitle, AdminEmailAccount));
            message.To.Add(new MailboxAddress(request.toUsername,  request.toEmail));
            message.Subject = request.subject;

            message.Body = new TextPart("html")
            {
                Text = request.body
            };
            
            await client.SendAsync(message);
        }


        public void RegisterMailRequest(MailRequest request)
        {
            queue.Enqueue(request);
        }
        
        public class MailRequest
        {
            public string toUsername, toEmail, subject, body;
        }
    }
}

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM