我有一个通过命名管道工作的WCF服务,它从ASP.NET MVC应用程序接收数据:
[ServiceContract]
public interface IEmailProcessor
{
[OperationContract(AsyncPattern = true)]
void SendEmails(string subject, string body, string from, string to);
}
服务获取电子邮件的主题,正文,发件人和收件人。然后它将电子邮件放在一起并通过SMTP发送。
客户端(MVC应用程序)一次发送几封电子邮件,所以我希望服务本身异步工作(客户端只调用SendEmails
方法几次,然后WCF服务器负责其余的工作)。但由于新电子邮件地址的灰名单,我的电子邮件服务器有时会拒绝发送电子邮件。这就是为什么我希望WCF服务器也将这些电子邮件排队并尝试逐个发送它们(如果发生错误,请重试几次)。
我已经阅读了有关WCF async和MSMQ方法的几个主题,但在我的情况下,最好的方法是什么?我应该创建两个WCF服务(客户端 - 服务器和服务器 - 服务器)吗?或者也许使用多线程?对我来说,不使用任何内置的SMTP解决方案也很重要,因为我想扩展我的服务以处理其他消息,而不仅仅是电子邮件。
答案 0 :(得分:1)
对于完全相同的要求,我已为自己制作了整个电子邮件解决方案,但我没有使用MSMQ队列。
以下是步骤
创建一个简单的Windows任务计划程序任务,以调用在预定时间段内运行服务以重试发送电子邮件Simple Window Task Schedular
要读取未送达,您的交换帐户中的电子邮件失败我使用第三方服务组件Admin System Software并更新表字段isDelivered = No,ErrorDescription = errorDesc
希望这个解决方案可以帮助你......
答案 1 :(得分:0)
我遵循了zaitsman的建议,并使用ConcurrentQueue
在服务中创建了队列。我还使用了创建新线程的示例:http://msdn.microsoft.com/en-us/library/7a2f3ay4%28v=vs.80%29.aspx
我在我的WCF服务器上添加了新的线程:
var thread = new Thread(EmailThread.Instace.DoWork);
thread.Start();
然后我的服务中的SendEmails方法使用Enqueue
将msg添加到ConcurrentQueue
。
public void SendEmails(string from, string to, string subject, string body)
{
var msg = new MailMessage(from, to, subject, body)
{
IsBodyHtml = true,
BodyEncoding = Encoding.UTF8,
DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
};
EmailThread.Instace.Messages.Enqueue(msg);
}
这是EmailThread类,它正在后台工作(即接受新的电子邮件到队列并顺序出列。
internal class EmailThread
{
//Ensure that only one instance of EmailThread can exist
private static readonly EmailThread Instance = new EmailThread();
public static EmailThread Instace { get { return Instance; } }
//Here is our Queue
public ConcurrentQueue<MailMessage> Messages { get; private set; }
private EmailThread()
{
Messages = new ConcurrentQueue<MailMessage>();
}
// This method is called when the thread is started and repeated once a 10 seconds
public void DoWork()
{
while (!_shouldStop)
{
Console.WriteLine("email sender thread: working...");
if (!Messages.IsEmpty)
{
//define SMTP credentials here
var smtp = new SmtpClient()
var failed = new Queue<MailMessage>();
MailMessage message;
while (Messages.TryDequeue(out message))
{
try
{
smtp.Send(message);
Console.WriteLine("email sender thread: successfully sent email...");
}
catch (SmtpException)
{
//Enqueue again if failed
failed.Enqueue(message);
Console.WriteLine("email sender thread: error sending email, enqueuing...");
}
}
foreach (var mailMessage in failed)
{
Messages.Enqueue(mailMessage);
}
smtp.Dispose();
}
Thread.Sleep(10000);
}
Console.WriteLine("email sender thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}