65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 客户端服务器推送( 使用 MSMQ)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (6投票s)

2011 年 2 月 6 日

CPOL

3分钟阅读

viewsIcon

60331

downloadIcon

2268

使用 MSMQ 和 WCF 的客户端服务器内部推送技术

引言

寻找一个使用 WCF 的简单服务器推送技术解决方案曾经很麻烦。

我有一些要求

  1. 必须使用 WCF
  2. 当消息被传输时,服务器和客户端应用程序不必运行
  3. 服务器端所有客户端的公共队列
  4. 需要服务器推送 - 不能使用轮询

IIS Web服务是一个选项,但用一个公共客户端队列实现起来很复杂。

使用 Microsoft 消息队列系统找到了一个解决方案。 客户端和服务器都有一个消息框用于通信。这两个应用程序在向对方发送消息时不必运行。

注意

本项目的目的不是为了解释绑定、契约和服务。 而是为了提供一个简单的服务器推送设计概述。

要求

  1. 安装 MSMQ (服务器和客户端) - 转到“控制面板” -> “添加删除程序” -> “添加 Windows 组件”,然后选择“消息队列”
  2. 以管理员身份运行 Visual Studio。
  3. 客户端和服务器必须能够互相看到(使用 IP 或主机名相互 ping)。 如果您需要外部通信支持 - 请参阅“公共通信的修改”部分。

概述

公共通信的修改

如果需要 Web服务 - 用于外部互联网通信,可以创建一个包装器,提供一个 Web服务 端点并创建一个内部队列消息。 这将消除客户端和服务器相互看到彼此消息队列的要求。

Using the Code

流程如下

客户端通过向服务器提供其自己的 MSMQ 地址来注册自己。

RegisterClientServiceClient registerClientServiceClient = 
		new RegisterClientServiceClient("RegisterClientEndPoint");

using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
	ClientInfo clientInfo = new ClientInfo();

	clientInfo.GroupName = ConfigurationManager.AppSettings["GroupName"];
	clientInfo.ClientName = System.Net.Dns.GetHostName();

	// ClientName can be changed to ip address
	clientInfo.PushMessageBoxAddress = "net.msmq://" + 
		clientInfo.ClientName + "/private/WcfServerPush/ClientMessageBox";

	registerClientServiceClient.RegisterClient(clientInfo);
				
	scope.Complete();
}   

RegisterClientServiceClient 类派生自 RegisterClientIService 并使用 ClientBase 模板。 这是常规的 WCF 实现。

 public class RegisterClientServiceClient : 
	ClientBase<RegisterClientIService>, RegisterClientIService
{
	public RegisterClientServiceClient(string endpointConfigurationName) :
		base(endpointConfigurationName)
	{
	}

	public void RegisterClient(ClientInfo clientInfo)
	{
		base.Channel.RegisterClient(clientInfo);
	}
}  

在服务器端,RegisterClient 实现为一个常规操作,它派生自相同的接口服务 RegisterClientIService

public class RegisterClientService : RegisterClientIService
{
	[OperationBehavior(TransactionScopeRequired = 
			true, TransactionAutoComplete = true)]
	public void RegisterClient(ClientInfo clientInfo)
	{
		WcfServerPushServerBO.Instance.RegisterClient(clientInfo);
	}
}

在服务器端创建 MSMQ ServiceHost 很容易

 if (!MessageQueue.Exists(registerClientMSMQName))
{
	MessageQueue versionManagerQueue = 
		MessageQueue.Create(registerClientMSMQName, true);
	versionManagerQueue.SetPermissions
		(@"Everyone", MessageQueueAccessRights.FullControl);

	versionManagerQueue.SetPermissions(@"ANONYMOUS LOGON",
		MessageQueueAccessRights.ReceiveMessage |
		MessageQueueAccessRights.PeekMessage |
		MessageQueueAccessRights.WriteMessage);
}   

客户端几乎与服务器端相同,但有一个小的修改。 因为我们希望 WPF 能够使用 ServiceHost 注册一个事件 - 每当收到新消息时,我们需要创建实际的服务并将其实例提供给 ServiceHost。 每当我们向 ServiceHost 提供服务的实例时,我们必须向行为添加 InstanceConextMode.Single

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PushMessageService : MessageBoxIService, INotifyPropertyChanged 

最后,我们需要修改 *App.Config* 来定义服务。 我们还可以为端点提供 http 绑定(不仅仅是 netMsmqBinding) - 如果将来我们想提供元数据交换能力。

 <service name="WcfServerPushServer.RegisterClientService" 
	behaviorConfiguration="WcfServerPushServer.RegisterClientServiceBehavior">
  <host>
	  <baseAddresses>
	  <add baseAddress="https://:8001/WcfServerPush/
				RegisterClientServiceHttp/" />
	  </baseAddresses>
  </host>

  <endpoint address="net.msmq:///private/WcfServerPush/RegisterClientService"
			  binding="netMsmqBinding"
			  bindingConfiguration="srmpBinding"
			  contract="WcfServerPushIServices.RegisterClientIService">
  </endpoint>
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service> 

客户端需要按如下方式识别端点

<client>
	<endpoint name="RegisterClientEndPoint" 
	address="net.msmq:///private/WcfServerPush/RegisterClientService" 
	binding="netMsmqBinding" bindingConfiguration="netMsmqBindingConfig" 
	contract="WcfServerPushIServices.RegisterClientIService"/>
</client> 

解决方案架构

  • WcfServerPush - 一个 WPF 项目,既充当客户端应用程序,又充当服务器应用程序。 您可以在任何一侧安装该应用程序,并自行决定运行什么。 WPF 项目还负责在未找到时创建消息队列并启动服务主机。 在实际的开发项目中 - 将视图与启动程序分离非常重要。
  • WcfServerPushServer - 服务器端服务和业务对象,包括客户端的队列
  • WcfServerPushClient - 客户端服务
  • WcfServerPushIServices - 消息框服务接口和注册客户端服务接口。 服务器端和客户端的公共项目。

历史

  • 2011年2月6日:首次发布
© . All rights reserved.