Я разрабатываю приложение, где пользователь, щелчки/нажатия вводят в определенную кнопку в окне, приложение, делает некоторые проверки и определяет, послать ли несколько электронных писем или нет, затем покажите другое окно с сообщением.
Моя проблема, посылание этих 2 электронных писем замедляет процесс заметно, и приблизительно для (~8) секунды первое окно выглядит замороженным, в то время как это делает отправку.
Есть ли какой-либо способ, которым мне можно было отправить эти электронные письма на фоне и отобразить следующее окно сразу же?
Не ограничивайте свой ответ с "использованием, X классов" или "просто используют X методов", поскольку я еще слишком не ознакомлен с языком, и еще некоторая информация высоко ценилась бы.
Спасибо.
Поскольку это небольшая единица работы, вы должны использовать 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-клиент каждый раз, вы сможете одновременно отправлять электронные письма.
Нет ничего сложного в том, чтобы просто отправить сообщение в отдельном потоке:
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();
Пример
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.");
}
}
}
Попробуйте следующее:
var client = new System.Net.Mail.SmtpClient("smtp.server");
var message = new System.Net.Mail.MailMessage() { /* provide its properties */ };
client.SendAsync(message, null);
Что вы хотите сделать, так это запустить задачу электронной почты в отдельном потоке, чтобы основной код мог продолжить обработку, в то время как другой поток выполняет работу с электронной почтой.
Вот инструкция, как это сделать: Учебник по многопоточности C #
Используя Task Parallel Library в .NET 4.0, вы можете:
Parllel.Invoke(() => { YourSendMailMethod(); });
Также см. cristina manu's Сообщение в блоге о Parallel.Invoke () и явном управлении задачами.
Просто потому что это немного туманно... я буду краток...
Есть много способов сделать асинхронную или параллельную работу в c#/.net и т.д.
Самый быстрый способ сделать то, что вы хотите - использовать фоновый рабочий поток, который позволит избежать блокировки вашего пользовательского интерфейса.
Совет по поводу фоновых рабочих потоков: вы не можете напрямую обновлять пользовательский интерфейс из них (сродство потоков и Marshalling - это то, с чем вы научитесь справляться...)
Еще одна вещь, которую нужно учесть... если вы используете стандартный System.Net.Mail для отправки писем... будьте осторожны с логикой. Если вы изолируете все это в каком-то методе и будете вызывать его снова и снова, ему, скорее всего, придется каждый раз разрывать и восстанавливать соединение с почтовым сервером, а задержки, связанные с аутентификацией и т.д., будут излишне замедлять работу. По возможности отправляйте несколько электронных писем через одно открытое соединение с почтовым сервером.
Используйте класс SmtpClient и используйте метод SendAsync в пространстве имен System.Net.Mail.