回复: 实现一个.NET Web Services服务注册中心
Service的实现类直接使用数据访问层(ServiceRegistryRepository 类)来执行服务。当收到一个特定请求时,服务的实现调用 ServiceRegistryRepository 的一个对应方法来进行数据库操作并返回数据集。
对服务消费者的支持服务注册中心的主要使用者是访问业务服务的服务消费者。服务注册中心的引入强化了在服务消费者实现中的依赖注入模式【3,4】——服务消费者依赖于一个特定的接口(这种方法完全对消费者隐藏了服务的WSDL/XSD。尽管它们在服务设计时非常重要,但消费者的实现只依赖于服务接口,因此完全隐藏了所有的分布和访问机制),而具体的实现(和绑定)在运行时通过对注册中心的访问而被动态注入,这些逻辑作为整体实现的一部分被封装在了一个代理构建器的类中。
为了提高性能,服务消费者缓存了端点的信息。目前我们使用的是基于时间(时间长度可以配置)的缓存策略;一个更高级的发布–订阅缓存策略将会在以后的某个版本中引入。一个客户实现可以通过以下的一个方法为一个给定的接口动态创建一个代理:
public static Interface getProxy<Interface>
(string sName, string sVersion, string sConsumer, string callBackCl)
这个方法接收服务名称,版本,消费类型(一般的QoS参数)和回调接口名称(可选的参数),并为一个给定的接口类型创建一个服务代理。这个方法首先尝试在本地缓存中解析所需的代理(见上),如果找到就立刻将之返还给调用者。否则,就会调用注册中心服务根据提供的参数查找服务信息。使用一个全限定接口名称作为一个额外的查找参数,这样可以用来保证一个指向的接口服务实现的引用满足客户要求
1。
如前面讲到的,我们通过使用.NET 3.0 提供的
ChannelFactory<Interface> 实现代理的创建。这个类可以通过服务注册中心提供的接口,端点地址和绑定信息创建一个服务代理。一旦代理创建完成,它就会被存储在缓存中并返还给使用者2。除了使用 WCF 连接服务,这个实现还能够支持“本地”绑定——直接从客户可以访问的程序集(assembly)中定位服务的实现。这个程序集或者已被客户程序加载或在GAC中。ProxyBuilder 使用的简化我们可以通过将服务参数从代码移到一个配置文件中(见表1的例子)进一步简化ProxyBuilder的使用。这个方法参考了SCA的配置【5】,可以进一步简化服务消费者的维护。
<configSections>
<section
name="composite" type="ProxyBuilder.CompositeSectionHandler,
ProxyBuilder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</configSections>
<composite>
<reference
Name = "Calculator"> <Service
Name = "TestService" Version = "02" ConsumerType = ""></Service>
<Callback
Name = "Test.test"></Callback>
</reference>
</composite>
表1 引用配置另外,注册中心本身的位置也可以移到配置文件中(表2)。
<registry>
<runtime
Location ="http://localhost:58934/WCFServiceRegistry.Host/ServiceRegistry.svc"/></registry>
表2 注册中心位置的配置维护服务注册中心的应用这是一个独立的应用,用来维护服务注册中心的信息。它支持以下主要的功能:
- 服务信息的查找和查看
- 服务信息的更改
- 服务信息的添加
- 服务信息的删除
这个应用采用一个Master-Details模式,其中master是基本的服务信息和绑定类型(在一个service表中),details包括服务使用的绑定类型的详细信息(图9)。这些详细信息和接下去的界面都基于绑定类型。
主界面的实现基于一个DataGridView控件,它本身提供了大部分所需的功能,包括显示,修改现有的记录和添加删除记录。绑定的详细信息被实现为一个自定义用户控件。因为不同的绑定类型有不同的详细信息,我们为各种绑定类型实现了不同的窗体。我们使用工厂模式(见附注)为某个绑定类型创建窗体并产生绑定详细信息。

附件:
您所在的用户组无法下载或查看附件 图9 服务维护界面附注:使用C#泛型实现工厂模式
工厂模式是根据不同类型创建多态对象的一个常见方法。使用C#泛型则可以大大简化这个实现(表3)。
namespace RegistryMaintanence.controls
{ public interface IControlsFactoryInterface
{ UserControl createControl(Service service, ServiceMaintanence parent, bool update);
}
public class ControlsFactory<T> : IControlsFactoryInterface
where T : UserControl, InitializableControl, new()
{
#region IControlsFactoryInterface Members
public UserControl createControl(Service service, ServiceMaintanence parent, bool update)
{
T t = new T();
t.initialize(service, parent, update);
return t;
}
#endregion
}
public class ControlsFactory{
private static Dictionary<BindingTypeEnum, IControlsFactoryInterface> factories = null;
private ControlsFactory(){}
private static Dictionary<BindingTypeEnum, IControlsFactoryInterface> getFactories(){
if(factories == null){
factories = new Dictionary<BindingTypeEnum,IControlsFactoryInterface>();
factories.Add(BindingTypeEnum.basicHTTPBinding,
new ControlsFactory<BasicHTTPBinding>());
factories.Add(BindingTypeEnum.netMsmqBinding,
new ControlsFactory<netMsmqBinding>());
factories.Add(BindingTypeEnum.netNamedPipeBinding,
new ControlsFactory<netNamedPipeBinding>());
factories.Add(BindingTypeEnum.netPeerTcpBinding,
new ControlsFactory<netPeerTcpBinding>());
factories.Add(BindingTypeEnum.netTcpBinding,
new ControlsFactory<NetTcpBinding>());
factories.Add(BindingTypeEnum.wsDualHttpBinding,
new ControlsFactory<WSDualHttpBinding>());
factories.Add(BindingTypeEnum.wsFederationHttpBinding,
new ControlsFactory<WSHTTPBinding>());
factories.Add(BindingTypeEnum.wsHTTPBinding,
new ControlsFactory<WSHTTPBinding>());
}
return factories;
}
public static UserControl createControl(BindingTypeEnum type ,Service service,
ServiceMaintanence parent, bool update)
{
Dictionary<BindingTypeEnum, IControlsFactoryInterface> builders = getFactories();
IControlsFactoryInterface builder = builders[type];
return builder.createControl(service, parent, update);
}
}
}
表3 使用泛型实现工厂模式
在这个实现中,IControlsFactoryInterface 接口类定义了被具体工厂支持的接口。所有的具体工厂都由泛型类 —— ControlsFactory<T> 实现。这个类依赖C#泛型对约束的支持[7],这种支持允许定义一种客户类型必须遵守的约束。这样可以使一个具体的工厂调用定义在基类的方法。
最后,泛型工厂的实现基于一个dictionary,这样可以从一个绑定类型找到对应工厂的。