2013-04-08 15 views
5

The SmtpClient Class stwierdza, że ​​członkowie instancji nie są bezpieczni dla wątków. Można to zobaczyć, jeśli połączenia są nawiązywane z numerami Send lub SendAsync. Obie metody wywołają wyjątek InvalidOperationException w drugim wywołaniu, jeśli pierwszy jeszcze nie został ukończony.Czy metody SmtpClient.SendMailAsync są bezpieczne dla wątków?

Metoda SendMailAsync, wprowadzona w .NET 4.5, nie wyświetla wyjątku InvalidOperationException jako wyjątku. Czy nowe metody .NET 4.5 implementują jakieś kolejkowanie? Reflector nie jest w stanie rzucić żadnego światła na szczegóły implementacji tej klasy, więc zakładam, że zostało to zaimplementowane w natywnych metodach.

Czy wiele wątków może bezpiecznie wywoływać metodę SendMessageAsync we współużytkowanej instancji klienta SMTP?

+1

Metody, które nie są wątkowo bezpieczne, nie muszą zgłaszać wyjątku, jeśli uzyskasz do nich dostęp z wielu wątków. – svick

Odpowiedz

10

Nie jestem pewien, dlaczego użycie reflektora nie zadziałało. Gdybym dekompilować go, widzę następujący kod:

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

Jak widać, jest to prosty wrapper dla SendAsync() TAP. A jeśli SendAsync() zgłasza wyjątek, SendMailAsync() ponownie go rzuca.

Wniosek jest taki, że SendMailAsync() nie jest bezpieczny dla wątków i że jego wyjątki są niedostatecznie udokumentowane.

+0

Sądzę, że utknąłem, wdrażając własny mechanizm kolejkowania. Dzięki za odpowiedzi. – brianfeucht

+0

@brianfeucht Dlaczego zamiast tego użyć wielu instancji 'SmtpClient' (po jednym dla każdego wątku)? – svick

+0

Taki jest plan. Utwórz pulę SmtpClients, aby móc kontrolować, ile połączeń wykonuje maszyna. Jeśli klient jest dostępny, zostanie udostępniony. Jeśli pula zostanie całkowicie wykorzystana, żądanie zostanie umieszczone w kolejce dla następnego dostępnego klienta. – brianfeucht

2

Jako uwaga (ponieważ nie mam wystarczającej liczby punktów do komentarza), tradycyjnym sposobem napisania operacji asynchronicznej było użycie Asynchronous Programming Model (APM), ale dzisiaj zazwyczaj używamy Asynchronicznego Patternu opartego na zadaniach. (TAP) z jego asynchronicznymi/oczekiwanymi słowami kluczowymi. I chociaż nie jest niczym niezwykłym owijanie TAP wokół metod APM, można również zobaczyć wrappery APM wokół metod TAP.

Powiązane problemy