2013-04-08 4 views
5

Die SmtpClient Class besagt, dass Instanzmitglieder nicht Thread sicher sind. Dies ist zu sehen, wenn gleichzeitige Anrufe an Send oder SendAsync getätigt werden. Beide Methoden werden eine InvalidOperationException für den zweiten Aufruf auslösen, wenn der erste noch nicht abgeschlossen ist.Sind die SmtpClient.SendMailAsync-Methoden Thread Safe?

Die in .NET 4.5 eingeführte Methode SendMailAsync listet InvalidOperationException nicht als ausgelöste Ausnahme auf. Implementieren die neuen .NET 4.5-Methoden eine Art von Warteschlangen? Reflector ist nicht in der Lage, die Implementierungsdetails dieser Klasse zu beleuchten, also nehme ich an, dass dies in nativen Methoden implementiert wurde.

Können mehrere Threads die SendMessageAsync-Methode für eine freigegebene Instanz des SMTP-Clients sicher aufrufen?

+1

Methoden, die nicht threadsicher sind, müssen keine Ausnahme auslösen, wenn Sie über mehrere Threads darauf zugreifen. – svick

Antwort

10

Ich weiß nicht, warum die Verwendung von Reflector nicht für Sie funktioniert hat. Wenn ich es dekompilieren, ich den folgenden Code sehen:

[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; 
} 

Wie Sie sehen können, ist es ein einfacher TAP-Wrapper für SendAsync(). Und wenn SendAsync() eine Ausnahme auslöst, wird SendMailAsync() es einfach erneut ausgetüftelt.

So ist die Schlussfolgerung, dass SendMailAsync() nicht Thread-sicher ist und dass seine Ausnahmen nicht dokumentiert sind.

+0

Ich denke, ich stecke fest, meinen eigenen Warteschlangenmechanismus dann zu implementieren. Danke für die Antwort. – brianfeucht

+0

@brianfeucht Warum verwenden Sie nicht mehrere Instanzen von 'SmtpClient' (eine für jeden Thread)? – svick

+0

Das ist der Plan. Erstellen Sie einen Pool von SmtpClients, damit ich steuern kann, wie viele Verbindungen ein Computer herstellt. Wenn ein Client verfügbar ist, wird er geteilt. Wenn der Pool vollständig verwendet wird, wird die Anfrage für den nächsten verfügbaren Client in die Warteschlange gestellt. – brianfeucht

2

Als Anmerkung (da ich nicht genug Punkte zum Kommentieren habe), war die traditionelle Art, eine asynchrone Operation zu schreiben, das Asynchronous Programming Model (APM), aber heute verwenden wir normalerweise das Task-basierte asynchrone Muster (TAP) mit seinen async/await-Schlüsselwörtern. Und obwohl es nicht ungewöhnlich ist, TAP-Wrapper um APM-Methoden zu sehen, ist es auch möglich, APM-Wrapper um TAP-Methoden herum zu sehen.