[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