[C#.NET][WCF] 實作 雙向 MSMQ @self-host for NetMsmqBinding
MSMQ 基本上是屬於單相通訊,在合約裡面必須要定義 IsOneWay 且 不能返回資料,若要實現雙向通訊就得經過一些技巧處理
實作架構如下圖所示:
簡單來講 Service 和 Client 都有自己的 ServiceHost
Service 監聽自己的 MSMQ
internal class service { public const String QueueName = @".\private$\Two-way/request"; private static void Main(string[] args) { // Get MSMQ queue name from app settings in configuration // Create the transacted MSMQ queue if necessary. if (!MessageQueue.Exists(QueueName)) MessageQueue.Create(QueueName, true); string hostName = Dns.GetHostName(); var serviceBinding = new NetMsmqBinding() { Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None }, }; ServiceHost serviceHost = null; try { // Create a ServiceHost for the OrderProcessorService type. serviceHost = new ServiceHost(typeof(RequestService)); serviceHost.AddServiceEndpoint(typeof(IRequestService), serviceBinding, "net.msmq://" + hostName + "/private/Two-way/request"); // Open the ServiceHost to create listeners and start listening for messages. serviceHost.Open(); // The service can now be accessed. Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); } finally { if (serviceHost != null) { serviceHost.Close(); } } } }
Client 監聽自己 MSMQ,並調用 Service 的 SendUser 方法
internal class client { //public const String QueueName = @".\private$\serviceQueue"; public const String QueueName = @".\private$\Two-way/response"; private static void Main(string[] args) { // Get MSMQ queue name from app settings in configuration // Create the transacted MSMQ queue if necessary. if (!MessageQueue.Exists(QueueName)) MessageQueue.Create(QueueName, true); string hostName = Dns.GetHostName(); var serviceBinding = new NetMsmqBinding() { Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None }, }; ServiceHost serviceHost = null; var responseName = "net.msmq://" + hostName + "/private/Two-way/response"; try { serviceHost = new ServiceHost(typeof(ResponseService)); serviceHost.AddServiceEndpoint(typeof(IResponseService), serviceBinding, responseName); // Open the ServiceHost to create listeners and start listening for messages. serviceHost.Open(); ChannelFactory<IRequestService> proxy = new ChannelFactory<IRequestService>( new NetMsmqBinding() { Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None }, }, new EndpointAddress("net.msmq://" + hostName + "/private/Two-way/request")); proxy.Open(); IRequestService channel = proxy.CreateChannel(); using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) { channel.SendUser(new User() { Name = "yy", Age = 12, ID = Guid.NewGuid() }, responseName); proxy.Close(); // Complete the transaction. scope.Complete(); } Console.WriteLine(); Console.WriteLine("Press <ENTER> to terminate client."); Console.ReadLine(); } finally { if (serviceHost != null) { serviceHost.Close(); } } } }
當 Service 收到 Client 調用 SendUser 方法時,則再送資料給 Client 的 MSMQ
internal class RequestService : IRequestService { [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void SendUser(User user, string returnAddress) { Console.WriteLine("接收用戶端訊息 : " + user); var serviceBinding = new NetMsmqBinding() { Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None }, }; ChannelFactory<IResponseService> proxy = new ChannelFactory<IResponseService>(serviceBinding, returnAddress); proxy.Open(); IResponseService channel = proxy.CreateChannel(); using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) { channel.SendUserResult(user.ID); scope.Complete(); } proxy.Close(); } }
Note.本篇範例全部採用 hard code來處理 binding / endpoint,所以看起來程式碼很多,相對的也比較沒彈性,也就是說該範例只能在本機執行,無法使用兩台不同的電腦測試..
運行結果如下:
本文出自:http://www.dotblogs.com.tw/yc421206/archive/2013/10/24/125435.aspx
飯粒下載:https://dotblogsfile.blob.core.windows.net/user/yc421206/1310/2013102414642430.zip
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET