【问题标题】:Dotnet core SmtpClient - insert data in db on SendCompletedEventHandlerDotnet 核心 SmtpClient - 在 SendCompletedEventHandler 上的数据库中插入数据
【发布时间】:2020-04-19 14:54:14
【问题描述】:

我有一个 .NET Core 3.1 应用程序。应用程序应发送电子邮件,并在电子邮件成功(或未成功)发送到 SQL Server 数据库时记录。

我已经在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 更改为AddScopedAddSingleton 只是为了看看会发生什么,但随后Program.cs 出现错误。

【问题讨论】:

    标签: c# dependency-injection callback smtp dbcontext


    【解决方案1】:

    您可以使用SendMailAsync 方法吗? - https://docs.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient.sendmailasync?view=netcore-3.1 这个方法可以等待,你的上下文不应该被容器释放。

    我想如果你坚持使用回调方法,你可以注入工厂,它会在你需要的时候(在回调中)为你创建上下文,你可以在回调方法中自己处理上下文。

    【讨论】:

      猜你喜欢
      • 2019-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多