在一些大型的解决方案中,假设我们的服务没有办法一直在线,或者因为这样那样的原因宕机了,有没有什么办法让客户端的影响最小化呢?答案是可以通过消息队列的方式,哪怕服务是没有在线的,客户端依然可以继续操作。
1. 首先来学习一些消息队列的基础知识
消息队列默认是没有安装的,可以通过下面的方式进行安装
2. 通过一个小程序来演示一下如何发送和接受消息
static void SendMessage() { Message msg = new Message("这是我的一个消息"); string queueName = @".\Private$\SampleQueue"; MessageQueue mq = null; if (!MessageQueue.Exists(queueName)) mq = MessageQueue.Create(queueName); else mq = new MessageQueue(queueName); mq.Formatter = new XmlMessageFormatter(new[] { "System.String" }); mq.Send(msg, "测试消息"); Console.WriteLine("消息发送成功"); }
然后,我们就可以看到这个消息了(通过mmc控制台)
[注意]xp和vista或者win 7都属于桌面操作系统,它们只支持私有队列。如果是服务器操作系统的话,则还支持公共队列。
下面看看如何读取队列中的消息
static void ReadMessage() { string queueName = @".\Private$\SampleQueue"; MessageQueue mq = new MessageQueue(queueName); mq.Formatter = new XmlMessageFormatter(new[] { "System.String" }); Message msg = mq.Receive(); Console.WriteLine(msg.Label); Console.WriteLine(msg.Body.ToString()); }
上面是一个很简单的例子,演示了如何发送和接收消息。
下面用一个例子来讲解WCF中如何利用消息队列来实现异步的服务。
1. 创建契约
using System; using System.ServiceModel; using System.Runtime.Serialization; namespace Contracts { [ServiceContract] public interface IMSMQService { [OperationContract(IsOneWay = true)] void PlaceOrder(OrderEntry entry); } [DataContract] public class OrderEntry { [DataMember] public int OrderID { get; set; } [DataMember] public DateTime OrderDate { get; set; } [DataMember] public int Quantity { get; set; } [DataMember] public int UnitPrice { get; set; } public override string ToString() { return string.Format( "ID:{0}\tDate:{1}\tQuantity:{2}\tUnitPrice:{3}\t", OrderID, OrderDate, Quantity, UnitPrice); } } }
2. 实现服务
using System; namespace Services { public class MSMQOrderService:Contracts.IMSMQService { #region IMSMQService 成员 public void PlaceOrder(Contracts.OrderEntry entry) { Console.WriteLine("收到订单:{0}", entry); } #endregion } }
3. 创建宿主
using System; using System.ServiceModel; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost( typeof(Services.MSMQOrderService), new Uri("net.msmq://localhost/Private/SampleQueue") )) { NetMsmqBinding binding = new NetMsmqBinding(NetMsmqSecurityMode.None); binding.ExactlyOnce = false; binding.Durable = true; host.AddServiceEndpoint( typeof(Contracts.IMSMQService).FullName, binding, ""); host.Open(); Console.WriteLine("服务器已经准备好"); Console.Read(); } } } }
4. 创建客户端
using System; using System.ServiceModel; namespace Client { class Program { static void Main(string[] args) { NetMsmqBinding binding = new NetMsmqBinding(NetMsmqSecurityMode.None); binding.ExactlyOnce = false; binding.Durable = true; ChannelFactory<Contracts.IMSMQService> channel = new ChannelFactory<Contracts.IMSMQService>( binding, new EndpointAddress("net.msmq://localhost/Private/SampleQueue")); Contracts.IMSMQService client = channel.CreateChannel(); client.PlaceOrder( new Contracts.OrderEntry() { OrderID = 1, OrderDate = DateTime.Now, UnitPrice = 10, Quantity = 10 }); Console.WriteLine("发送了一个订单"); Console.Read(); } } }
5. 测试
很好,我们看到消息发送到了服务器端。但,如果仅仅是这样,那么使用消息队列有什么优势呢?
我们现在不启动服务端,而仅仅启动客户端。看看是否可以发出订单
我们发现,虽然服务没有开启来,但是却依然可以发出订单。那么这个订单到哪里去了呢。原来是被存放到了队列中。如下图所示
然后,我们再去开服务宿主程序。
宿主程序会自动读取消息队列中的消息,并自动进行处理。此时再次去查看队列的话,就会发现已经没有消息了