7

SmtpClient 类声明实例成员不是线程安全的。如果对SendSendAsync进行并发调用,则可以看到这一点。如果第一次调用尚未完成,这两种方法都将在第二次调用时抛出 InvalidOperationException。

.NET 4.5 中引入的方法SendMailAsync没有将 InvalidOperationException 列为抛出的异常。新的 .NET 4.5 方法是否实现了某种排队?Reflector 无法阐明此类的实现细节,因此我假设这已在本机方法中实现。

多个线程能否安全地调用 SMTP 客户端共享实例上的 SendMessageAsync 方法?

4

2 回答 2

13

我不确定为什么使用 Reflector 对您不起作用。如果我反编译它,我会看到以下代码:

[HostProtection(SecurityAction.LinkDemand, ExternalThreading=true)]
public Task SendMailAsync(MailMessage message)
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    SendCompletedEventHandler handler = null;
    handler = delegate (object sender, AsyncCompletedEventArgs e) {
        this.HandleCompletion(tcs, e, handler);
    };
    this.SendCompleted += handler;
    try
    {
        this.SendAsync(message, tcs);
    }
    catch
    {
        this.SendCompleted -= handler;
        throw;
    }
    return tcs.Task;
}

如您所见,它是一个简单的 TAP 包装器,用于SendAsync(). 如果SendAsync()抛出异常,SendMailAsync()只需重新抛出它。

因此,结论是它SendMailAsync()不是线程安全的,并且它的异常没有被充分记录。

于 2013-04-08T21:09:06.240 回答
2

作为注释(因为我没有足够的评论),编写异步操作的传统方法是使用异步编程模型(APM),但今天我们通常使用基于任务的异步模式(TAP)和它的 async/await 关键字。尽管在 APM 方法周围看到 TAP 包装器并不罕见,但也可以在 TAP 方法周围看到 APM 包装器。

于 2014-07-31T09:34:28.693 回答