[c#] .NET 4.0에서 SmtpClient, SendAsync 및 Dispose를 사용하는 모범 사례는 무엇입니까?

특히 SendAsync를 사용하여 호출하는 경우 일회용이므로 SmtpClient를 관리하는 방법에 대해 약간 당황합니다. 아마도 SendAsync가 완료 될 때까지 Dispose를 호출해서는 안됩니다. 그러나 나는 그것을 호출해야한다 (예 : “사용”사용). 시나리오는 호출이 이루어질 때 주기적으로 이메일을 발송하는 WCF 서비스입니다. 대부분의 계산은 빠르지 만 이메일 전송에는 1 초 정도 걸릴 수 있으므로 Async가 더 좋습니다.

메일을 보낼 때마다 새 SmtpClient를 만들어야합니까? 전체 WCF에 대해 하나를 만들어야합니까? 도움!

업데이트 차이가있을 경우 각 이메일은 항상 사용자에게 맞춤 설정됩니다. WCF는 Azure에서 호스팅되고 Gmail은 메일러로 사용됩니다.



답변

참고 : .NET 4.5 SmtpClient는 async awaitablemethod SendMailAsync. 낮은 버전의 경우 SendAsync아래 설명 된대로 사용하십시오.


항상 IDisposable가능한 한 빨리 인스턴스를 폐기해야합니다 . 비동기 호출의 경우 메시지가 전송 된 후 콜백에 있습니다.

var message = new MailMessage("from", "to", "subject", "body"))
var client = new SmtpClient("host");
client.SendCompleted += (s, e) => {
                           client.Dispose();
                           message.Dispose();
                        };
client.SendAsync(message, null);

SendAsync콜백을 수락하지 않는 것이 약간 짜증납니다 .


답변

원래 질문은 .NET 4에 대해 요청되었지만 .NET 4.5에서 도움이된다면 SmtpClient는 비동기 대기 가능 메서드를 구현
SendMailAsync합니다.

결과적으로 이메일을 비동기 적으로 보내는 것은 다음과 같습니다.

public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
    using (var message = new MailMessage())
    {
        message.To.Add(toEmailAddress);

        message.Subject = emailSubject;
        message.Body = emailMessage;

        using (var smtpClient = new SmtpClient())
        {
            await smtpClient.SendMailAsync(message);
        }
    }
}

SendAsync 메서드를 사용하지 않는 것이 좋습니다.


답변

일반적으로 IDisposable 개체는 가능한 한 빨리 처리해야합니다. 개체에 IDisposable을 구현하는 것은 해당 클래스가 결정적으로 해제되어야하는 값 비싼 리소스를 보유하고 있다는 사실을 전달하기위한 것입니다. 그러나 이러한 리소스를 만드는 데 비용이 많이 들고 이러한 개체를 많이 생성해야하는 경우 하나의 인스턴스를 메모리에 유지하고 다시 사용하는 것이 더 나을 수 있습니다 (성능 측면). 그것이 차이를 만드는지 알 수있는 유일한 방법은 프로파일 링입니다!

Re : 폐기 및 비동기 : using분명히 사용할 수 없습니다 . 대신 일반적으로 SendCompleted 이벤트에서 개체를 삭제합니다.

var smtpClient = new SmtpClient();
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose();
smtpClient.SendAsync(...);


답변

좋아, 내가 아는 오래된 질문. 그러나 비슷한 것을 구현해야 할 때 직접 이것을 발견했습니다. 코드를 공유하고 싶었습니다.

여러 SmtpClient를 반복하여 여러 메일을 비동기 적으로 보냅니다. 내 솔루션은 TheCodeKing과 유사하지만 대신 콜백 개체를 처리하고 있습니다. 또한 MailMessage를 userToken으로 전달하여 SendCompleted 이벤트에서 가져 와서 dispose를 호출 할 수도 있습니다. 이렇게 :

foreach (Customer customer in Customers)
{
    SmtpClient smtpClient = new SmtpClient(); //SmtpClient configuration out of this scope
    MailMessage message = new MailMessage(); //MailMessage configuration out of this scope

    smtpClient.SendCompleted += (s, e) =>
    {
        SmtpClient callbackClient = s as SmtpClient;
        MailMessage callbackMailMessage = e.UserState as MailMessage;
        callbackClient.Dispose();
        callbackMailMessage.Dispose();
    };

    smtpClient.SendAsync(message, message);
}


답변

다음 주석을 통해 SmtpClient를 폐기하는 것이 특히 중요한 이유를 알 수 있습니다.

public class SmtpClient : IDisposable
   // Summary:
    //     Sends a QUIT message to the SMTP server, gracefully ends the TCP connection,
    //     and releases all resources used by the current instance of the System.Net.Mail.SmtpClient
    //     class.
    public void Dispose();

클라이언트를 삭제하지 않고 Gmail을 사용하여 여러 메일을 보내는 시나리오에서 다음을 얻었습니다.

메시지 : 서비스를 사용할 수 없습니다. 전송 채널을 닫습니다. 서버 응답 : 4.7.0 일시적인 시스템 문제. 나중에 다시 시도하십시오 (WS). oo3sm17830090pdb.64-gsmtp


답변