Do tnet core SmtpClient - вставлять данные в БД на SendCompletedEventHandler - PullRequest
1 голос
/ 19 апреля 2020

У меня есть приложение. NET Core 3.1. Приложение должно отправлять электронные письма и регистрироваться, когда электронное письмо успешно отправлено (или нет) в SQL Серверную базу данных.

Я зарегистрировал базу данных в Startup.cs:

services.AddDbContext<DataBaseAppContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

И я зарегистрировал своего отправителя электронной почты в том же файле, как этот:

services.AddTransient<IEmailSender, EmailSender>();

Это реализация EmailSender:

public class EmailSender : IEmailSender
{
   private readonly DataBaseAppContext _context;

   public EmailSender(DataBaseAppContext context)
   {
      _context = context;
   }

   public Task SendEmailAsync(string subject, string message, string email)
   {
       return Execute(subject, message, email);
   }

    public Task Execute(string subject, string message, string email)
    {
        try
        {
            MailAddress fromAddress = new MailAddress(...);

            SmtpClient smtp = new SmtpClient
            {
                Host = ...,
                Port = ...,
                ...
            };                

            MailMessage md = new MailMessage
            {
                From = ...,
                IsBodyHtml = true,
                Subject = subject,
                Body = message,
                To = ...
            };

            smtp.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);

            void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
            {
                if (e.Cancelled)
                {
                    //Want to use this statement as well, to log errors
                }
                if (e.Error != null)
                {
                    //Want to use this statement as well, to log errors
                }
                else
                {
                    try
                    {
                         //Object that should be saved in DB
                         EmailLogger emailLogger = new EmailLogger()
                         {
                             Email = email,
                             Subject = subject,
                             Message = message,
                             DateTime = DateTime.Now
                         };
                        _context.EmailLogger.Add(emailLogger);
                        _context.SaveChanges();
                    }
                    catch(Exception ex)
                    {
                        //Here I got an error - the *error below
                    }
                }
            }

            return smtp.SendMailAsync(md);

        }
        catch (Exception e)
        {
            throw e;
        }
    }
}

Всякий раз, когда я вызываю EmailSender.SendEmailAsync, я получаю следующая ошибка:

Невозможно получить доступ к удаленному объекту. Распространенной причиной этой ошибки является удаление контекста, который был разрешен путем внедрения зависимости, а затем попытка использовать тот же экземпляр контекста в другом месте вашего приложения. Это может произойти, если вы вызываете Dispose () для контекста или заключаете контекст в оператор using. Если вы используете внедрение зависимости, вы должны позволить контейнеру ввода зависимости позаботиться об удалении экземпляров контекста.

Я понимаю, что это вызвано тем, что служба зарегистрирована как AddTransient, а _context уже утилизируется, когда происходит обратный вызов.

Не уверен, что это лучший способ решить эту проблему, попытался изменить AddTransient на AddScoped или AddSingleton просто чтобы посмотреть, что произойдет, но затем получил ошибка в Program.cs.

1 Ответ

0 голосов
/ 19 апреля 2020

Можете ли вы использовать метод SendMailAsync? - https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient.sendmailasync?view=netcore-3.1 Этот метод можно ожидать, и контейнер не должен утилизировать ваш контекст.

Полагаю, если вы настаиваете на использовании метода обратного вызова, вы можете ввести фабрику, которая будет создайте контекст для вас, когда вам это нужно (в обратном вызове), и вы можете сами распоряжаться контекстом в методе обратного вызова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...