SmtpClient.SendMailAsync causes deadlock when throwing a specific exception

后端 未结 1 1706
感情败类
感情败类 2020-12-09 17:36

I\'m trying to setup email confirmation for an ASP.NET MVC5 website, based on the example AccountController from the VS2013 project template. I\'ve implemented the IId

相关标签:
1条回答
  • 2020-12-09 17:41

    Try this implementation, just use client.SendMailExAsync instead of client.SendMailAsync. Let us know if it makes any difference:

    public static class SendMailEx
    {
        public static Task SendMailExAsync(
            this System.Net.Mail.SmtpClient @this,
            System.Net.Mail.MailMessage message,
            CancellationToken token = default(CancellationToken))
        {
            // use Task.Run to negate SynchronizationContext
            return Task.Run(() => SendMailExImplAsync(@this, message, token));
        }
    
        private static async Task SendMailExImplAsync(
            System.Net.Mail.SmtpClient client, 
            System.Net.Mail.MailMessage message, 
            CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
    
            var tcs = new TaskCompletionSource<bool>();
            System.Net.Mail.SendCompletedEventHandler handler = null;
            Action unsubscribe = () => client.SendCompleted -= handler;
    
            handler = async (s, e) =>
            {
                unsubscribe();
    
                // a hack to complete the handler asynchronously
                await Task.Yield(); 
    
                if (e.UserState != tcs)
                    tcs.TrySetException(new InvalidOperationException("Unexpected UserState"));
                else if (e.Cancelled)
                    tcs.TrySetCanceled();
                else if (e.Error != null)
                    tcs.TrySetException(e.Error);
                else
                    tcs.TrySetResult(true);
            };
    
            client.SendCompleted += handler;
            try
            {
                client.SendAsync(message, tcs);
                using (token.Register(() => client.SendAsyncCancel(), useSynchronizationContext: false))
                {
                    await tcs.Task;
                }
            }
            finally
            {
                unsubscribe();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题