【问题标题】:System.ObjectDisposedException while sending email using smtpclient (fluent-email)使用 smtpclient (fluent-email) 发送电子邮件时出现 System.ObjectDisposedException
【发布时间】:2022-06-13 14:18:09
【问题描述】:

当我尝试使用 fluent-email 库在 .NET core 6.0 项目中发送电子邮件时,我收到了 System.ObjectDisposedException

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Mail.SmtpClient'.
   at System.Net.Mail.SmtpClient.SendAsync(MailMessage message, Object userToken)
   at FluentEmail.Smtp.SendMailEx.SendMailExImplAsync(SmtpClient client, MailMessage message, CancellationToken token)

我曾尝试注入 smtpclient transientscoped 并作为 singleton,但没有一个选项可以解决此问题。

DI 代码:

  var smtpClient = new SmtpClient(smtpSenderOptions.Host, smtpSenderOptions.Port)
                {
                    EnableSsl = smtpSenderOptions.EnableSsl
                };

                services.AddSingleton(instance => smtpClient);

用法(来自 fluent-email 库 (https://github.com/lukencode/FluentEmail)):

    
    // Taken from https://stackoverflow.com/questions/28333396/smtpclient-sendmailasync-causes-deadlock-when-throwing-a-specific-exception/28445791#28445791
    // SmtpClient causes deadlock when throwing exceptions. This fixes that.
    public static class SendMailEx
    {
        public static Task SendMailExAsync(
            this SmtpClient @this,
            MailMessage message,
            CancellationToken token = default(CancellationToken))
        {
            // use Task.Run to negate SynchronizationContext
            return Task.Run(() => SendMailExImplAsync(@this, message, token));
        }

        private static async Task SendMailExImplAsync(
            SmtpClient client,
            MailMessage message,
            CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            var tcs = new TaskCompletionSource<bool>();
            SendCompletedEventHandler handler = null;
            Action unsubscribe = () => client.SendCompleted -= handler;

            handler = async (_, e) =>
            {
                unsubscribe();

                // a hack to complete the handler asynchronously
                await Task.Yield();

                if (e.UserState != tcs)
                    tcs.TrySetException(new InvalidOperationException("Unexpected UserState"));
                else if (e.Cancelled)
                    tcs.TrySetCanceled();
                else if (e.Error != null)
                    tcs.TrySetException(e.Error);
                else
                    tcs.TrySetResult(true);
            };

            client.SendCompleted += handler;
            try
            {
                client.SendAsync(message, tcs);
                using (token.Register(() =>
                {
                    client.SendAsyncCancel();
                }, useSynchronizationContext: false))
                {
                    await tcs.Task;
                }
            }
            finally
            {
                unsubscribe();
            }
        }
    }

我的代码调用库:

  var response = await _fluentEmail
                .Subject(emailContents.Subject)
                .To(emailContents.To)
                .Attach(attachments)
                .UsingTemplate(template, emailContents)
                .SendAsync(cancellationToken);

【问题讨论】:

  • 您需要包含如何使用它的代码。
  • 由于大部分魔法都发生在 fluentemail 项目中,我想我可能对所有异步内容都做错了。
  • 看起来您有两个客户。您还需要在每条消息之前为客户端调用构造函数。您不能重复使用客户端。
  • ASP.NET Core 不使用同步上下文,SMTPClient 不会死锁,不需要实现。
  • I have tried to inject the smtpclient transient, scoped and as a singleton but neither one of the options fixed this issue. => 好吧,当然不是,你总是返回同一个实例,一旦处理它就不能再使用了。

标签: c# .net-core smtpclient


【解决方案1】:

fluent-email 提供的扩展确实将这些类作为单例注入,我确实使用了另一个生命周期,因此出现了这个问题。

所以我忘记了使用System.ObjectDisposedException 覆盖所有依赖项的依赖注入容器配置以使用单例,因为我使用的是FluentEmail.Smtp.SendMailEx.SendMailExImplAsync 的自定义实现。

在覆盖 DI 扩展中的其他依赖项后,它起作用了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-15
    • 1970-01-01
    • 2013-02-10
    • 2015-06-11
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    • 2011-07-03
    相关资源
    最近更新 更多