2011-08-04 3 views
23

차단 비동기 메서드를 사용하면 내 메서드 인 SendAsync가 즉시 반환되고 RedirectToAction이 호출됩니다. 그러나 응답 (이 경우 리디렉션)은 client_SendCompleted가 완료 될 때까지 ASP.NET에서 보내지 않습니다.SmtpClient.SendAsync 내가 간단한 이메일을 보내는 작업을 내 ASP.NET MVC 요청

비주얼 스튜디오 디버거의 실행을보고는가 SendAsync 즉시 (그리고 RedirectToAction이라고합니다) 반환하지만 아무것도 브라우저에서 발생하지 않습니다 이메일이 전송 될 때까지 : 여기

내가 이해하려고 노력 중이 야 무슨 일이야?

client_SendCompleted 안에 중단 점을 넣으면 클라이언트가 디버깅 할 때까지 F5를 누르기 전까지로드가 유지됩니다.

답변

27

이것은 의도적으로 설계된에 버그를 보냈다. ASP.NET은 비동기 작업이 시작되어 SynchronizationContext으로 호출되는 방식으로 요청이 완료되기 전에 요청을 완료하기 전에 자동으로 대기중인 비동기 작업이 완료 될 때까지 대기합니다. 이는 비동기 작업이 HttpContext, HttpResponse 등과 상호 작용하려고 시도하는 경우에도 여전히 작동 할 수 있도록하기위한 것입니다.

사실을 알리고 &을 잊고 싶다면 ThreadPool.QueueUserWorkItem으로 전화를해야합니다. 이렇게하면 SynchronizationContext을 거치지 않고 새로운 스레드 풀 스레드에서 실행되므로 요청이 행복하게 반환됩니다.

그러나 보내기가 진행되는 동안 앱 도메인이 다운 된 경우 (예 : web.config 파일을 변경 한 경우 새 파일을 bin, 응용 프로그램 풀을 재활용 한 경우 등) .) 비동기 전송이 갑작스럽게 중단됩니다. 그 점을 염두에 둔다면 Phil Haacks WebBackgrounderASP.NET으로 가져 가세요. 이메일을 보내는 등의 백그라운드 작업을 큐에 넣고 실행하여 앱 도메인이 정상적으로 종료되도록합니다. 닥쳐.

+2

Task.Factory.StartNew (() => SendEmail(), TaskCreationOptions.LongRunning) 동일한 문제가 생깁니 까? –

+0

[절대로 HostingEnvironment.UnregisterObject를 호출해야합니까?] (http://stackoverflow.com/questions/16096378/should-i-never-call-hostingenvironment-unregisterobject) – horgh

6

이것은 흥미로운 것입니다. 예기치 않은 행동을 재현 해 냈지만 설명 할 수는 없습니다. 나는 파기를 계속할 것이다.

어쨌든 솔루션은 SendAsync을 사용하는 목적을 무효로하는 백그라운드 스레드를 대기열로 만드는 것으로 보입니다. 이와 끝까지 :

MailMessage mailMessage = new MailMessage(...); 
SmtpClient client = new SmtpClient(...); 
client.SendCompleted += (s, e) => 
          { 
           client.Dispose(); 
           mailMessage.Dispose(); 
          }; 

ThreadPool.QueueUserWorkItem(o => 
    client.SendAsync(mailMessage, Tuple.Create(client, mailMessage))); 

도 될 수있다 :

ThreadPool.QueueUserWorkItem(o => { 
    using (SmtpClient client = new SmtpClient(...)) 
    { 
     using (MailMessage mailMessage = new MailMessage(...)) 
     { 
      client.Send(mailMessage, Tuple.Create(client, mailMessage)); 
     } 
    } 
}); 
+0

http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx HTTPS "나는 너무 재현 할 수있는"에 클릭 : //connect.microsoft.com/VisualStudio/feedback/details/688210/smtpclient-sendasync-blocking-my-asp-net-mvc-request –

+1

'ThreadPool.QueueUserWorkItem' 내 문제를 해결합니다. 감사합니다 –

0
+0

이것이 apropo인지 모르겠지만 내 MVC 3 요청을 차단하는 SendAsync와 관련된 문제도 있습니다. 어쩌면 코드를 제대로 구성하지 못했을 수 있습니까? 인터넷 검색, Jeff Widmer의 블로그에서 비동기식으로 보내기를 보여줍니다. 그의 예는 훌륭한 출발점이며, 나를 위해 SendAsync와 씨름하는 것보다 간단합니다. http://weblogs.asp.net/jeffwids/archive/2009/10/12/asynchronously-sending-a-system-net-mail-mailmessage-in-c.aspx?CommentPosted=true#commentmessage – Arnold

+0

그가하는 일 비동기를 수행하는 일반적인 접근 방식입니다. 핵심은 SendAsync 메서드가 요청을 차단하는 이유입니다. 프레임 워크의 어떤 부분이 어색하다 –

+1

적어도 프레임 워크에서는 뭔가 어긋나지 않을 수 없다. 그러나 나는 그 문제를 보지 못했다. 전자 메일은 보내지지만 내 컨트롤러 작업의 리디렉션은 무시됩니다. 아직 SendAsync()의 전체 예제를 보지 못했습니다. 일반 접근법을 사용하고 WaitOne() 및 Dispose()를 필수적으로 지정하면 문제가 발생하지 않습니다. SendAsync()에 구성 문제가 있으면 놀라지 않을 것입니다. 감사. – Arnold

1

.Net 4.5.2, 당신은 ActionMailer.Net하여이 작업을 수행 할 수 있습니다

 var mailer = new MailController(); 
     var msg = mailer.SomeMailAction(recipient); 

     var tcs = new TaskCompletionSource<MailMessage>(); 
     mailer.OnMailSentCallback = tcs.SetResult; 
     HostingEnvironment.QueueBackgroundWorkItem(async ct => 
     { 
      msg.DeliverAsync(); 
      await tcs.Task; 
      Trace.TraceInformation("Mail sent to " + recipient); 
     }); 

읽어 보시기 바랍니다이 첫 번째 : 나는 어쩌면 당신이 투표에 의해 도움 수, 마이크로 소프트 연결에 버그를 보내

관련 문제