我正在开发一个应用程序,其中用户点击/按下窗口中某个按钮的输入,应用程序执行一些检查并确定是否发送几封电子邮件,然后显示另一个带有消息的窗口。
我的问题是,发送2封电子邮件会显着减慢这个过程,并且在某些(约8)秒内,第一个窗口会在发送时冻结。
我有什么方法可以在后台发送这些电子邮件并立即显示下一个窗口?
请不要使用“使用X类”或“仅使用X方法”来限制您的答案,因为我还不太熟悉该语言,并且会非常感谢更多信息。
感谢。
答案 0 :(得分:68)
从.NET 4.5开始,SmtpClient实现异步等待方法
SendMailAsync
。
因此,异步发送电子邮件如下:
public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
var message = new MailMessage();
message.To.Add(toEmailAddress);
message.Subject = emailSubject;
message.Body = emailMessage;
using (var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAsync(message);
}
}
答案 1 :(得分:24)
由于它是一个小工作单元,您应该使用ThreadPool.QueueUserWorkItem来处理它的线程方面。如果您使用SmtpClient课程发送邮件,则可以处理SendCompleted事件以向用户提供反馈。
ThreadPool.QueueUserWorkItem(t =>
{
SmtpClient client = new SmtpClient("MyMailServer");
MailAddress from = new MailAddress("me@mydomain.com", "My Name", System.Text.Encoding.UTF8);
MailAddress to = new MailAddress("someone@theirdomain.com");
MailMessage message = new MailMessage(from, to);
message.Body = "The message I want to send.";
message.BodyEncoding = System.Text.Encoding.UTF8;
message.Subject = "The subject of the email";
message.SubjectEncoding = System.Text.Encoding.UTF8;
// Set the method that is called back when the send operation ends.
client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
// The userState can be any object that allows your callback
// method to identify this send operation.
// For this example, I am passing the message itself
client.SendAsync(message, message);
});
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Get the message we sent
MailMessage msg = (MailMessage)e.UserState;
if (e.Cancelled)
{
// prompt user with "send cancelled" message
}
if (e.Error != null)
{
// prompt user with error message
}
else
{
// prompt user with message sent!
// as we have the message object we can also display who the message
// was sent to etc
}
// finally dispose of the message
if (msg != null)
msg.Dispose();
}
通过每次创建一个新的SMTP客户端,您可以同时发送电子邮件。
答案 2 :(得分:11)
简单地在单独的线程上发送消息并不复杂:
using System.Net.Mail;
Smtp.SendAsync(message);
或者,如果你想在单独的线程上构造整个消息而不是仅仅异步发送它:
using System.Threading;
using System.Net.Mail;
var sendMailThread = new Thread(() => {
var message=new MailMessage();
message.From="from e-mail";
message.To="to e-mail";
message.Subject="Message Subject";
message.Body="Message Body";
SmtpMail.SmtpServer="SMTP Server Address";
SmtpMail.Send(message);
});
sendMailThread.Start();
答案 3 :(得分:8)
样品
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.ComponentModel;
namespace Examples.SmptExamples.Async
{
public class SimpleAsynchronousExample
{
static bool mailSent = false;
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Get the unique identifier for this asynchronous operation.
String token = (string) e.UserState;
if (e.Cancelled)
{
Console.WriteLine("[{0}] Send canceled.", token);
}
if (e.Error != null)
{
Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
} else
{
Console.WriteLine("Message sent.");
}
mailSent = true;
}
public static void Main(string[] args)
{
// Command line argument must the the SMTP host.
SmtpClient client = new SmtpClient(args[0]);
// Specify the e-mail sender.
// Create a mailing address that includes a UTF8 character
// in the display name.
MailAddress from = new MailAddress("jane@contoso.com",
"Jane " + (char)0xD8+ " Clayton",
System.Text.Encoding.UTF8);
// Set destinations for the e-mail message.
MailAddress to = new MailAddress("ben@contoso.com");
// Specify the message content.
MailMessage message = new MailMessage(from, to);
message.Body = "This is a test e-mail message sent by an application. ";
// Include some non-ASCII characters in body and subject.
string someArrows = new string(new char[] {'\u2190', '\u2191', '\u2192', '\u2193'});
message.Body += Environment.NewLine + someArrows;
message.BodyEncoding = System.Text.Encoding.UTF8;
message.Subject = "test message 1" + someArrows;
message.SubjectEncoding = System.Text.Encoding.UTF8;
// Set the method that is called back when the send operation ends.
client.SendCompleted += new
SendCompletedEventHandler(SendCompletedCallback);
// The userState can be any object that allows your callback
// method to identify this send operation.
// For this example, the userToken is a string constant.
string userState = "test message1";
client.SendAsync(message, userState);
Console.WriteLine("Sending message... press c to cancel mail. Press any other key to exit.");
string answer = Console.ReadLine();
// If the user canceled the send, and mail hasn't been sent yet,
// then cancel the pending operation.
if (answer.StartsWith("c") && mailSent == false)
{
client.SendAsyncCancel();
}
// Clean up.
message.Dispose();
Console.WriteLine("Goodbye.");
}
}
}
答案 4 :(得分:5)
仅仅因为这有点模糊......我会简短......
在c#/ .net等中有很多方法可以进行异步或并行工作。
执行所需操作的最快方法是使用后台工作线程,这样可以避免锁定UI。
有后台工作线程的提示:你不能直接从它们更新UI(线程亲和力和编组只是你学会处理的东西......)
另一件需要考虑的事情......如果你使用标准的System.Net.Mail类型的东西来发送电子邮件......要小心你如何制作你的逻辑。如果你在某种方法中将它全部隔离并反复调用它,那么每次都可能必须拆除并重建与邮件服务器的连接,并且认证等中涉及的延迟仍然会使整个事情不必要地减慢。在可能的情况下,通过单个打开的连接向邮件服务器发送多封电子邮件。
答案 5 :(得分:5)
以下是使用.Net 4.5.2 +的 fire and forget方法和async :
BackgroundTaskRunner.FireAndForgetTaskAsync(async () =>
{
SmtpClient smtpClient = new SmtpClient(); // using configuration file settings
MailMessage message = new MailMessage(); // TODO: Initialize appropriately
await smtpClient.SendMailAsync(message);
});
BackgroundTaskRunner是:
public static class BackgroundTaskRunner
{
public static void FireAndForgetTask(Action action)
{
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => // .Net 4.5.2+ required
{
try
{
action();
}
catch (Exception e)
{
// TODO: handle exception
}
});
}
/// <summary>
/// Using async
/// </summary>
public static void FireAndForgetTaskAsync(Func<Task> action)
{
HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => // .Net 4.5.2+ required
{
try
{
await action();
}
catch (Exception e)
{
// TODO: handle exception
}
});
}
}
就像Azure App Services上的魅力一样。
答案 6 :(得分:4)
试试这个:
var client = new System.Net.Mail.SmtpClient("smtp.server");
var message = new System.Net.Mail.MailMessage() { /* provide its properties */ };
client.SendAsync(message, null);
答案 7 :(得分:2)
使用SmtpClient类并使用System.Net.Mail命名空间中的方法SendAsync。
答案 8 :(得分:1)
您要做的是在单独的线程上运行电子邮件任务,以便主代码可以继续处理,而另一个线程可以处理电子邮件。
这是一个如何做到这一点的教程: Threading Tutorial C#
答案 9 :(得分:1)
使用.NET 4.0中的Task Parallel Library,您可以执行以下操作:
Parllel.Invoke(() => { YourSendMailMethod(); });
另外,请参阅有关Parallel.Invoke()与显式任务管理的cristina manu's博文。