对等传输信道允许开发人员通过确定一个自定义对等网解析器来实现他们自己的对等解决方案。有很多理由让你实现自己的对等网络解析器而不是使用默认的PNRP协议解析器。PNRP要求使用IPv6并需要为Windows XP SP2和Vista客户端下载额外补丁以使其可以一起使用。在这些情况下实现一个自定义对等网络解析器可以最大化使用现有的IPv4网络而且易于部署。有很多实现一个自定义对等网络解析器的例子。Windows SDK 显示了一个使用WCF服务的方案。我们将给出一个类似的使用一个服务的自定义对等网络解析器,但是需要有一个SQL Server 2005数据库支持。很多应用程序可以使用这个实现来在一个网络中获得一系列协作计算机。
为了创建一个新的对等网络解析器,你必须继承抽象基类PeerResolver.这个类有很多允许一个客户端从一个网状网络注册、更新和反注册的方法。它也有一个解析网状网络中其他计算机的方法。列表12.7显示了SqlPeerResolver类以及与其关联的配置类。
列表12.7 SqlPeerResolver
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.PeerResolvers;
using System.ServiceModel.Configuration;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
namespace EssentialWCF.PeerNetworking
{
public class SqlPeerResolver : PeerResolver
{
private static object dalLock = new object();
private static SqlPeerResolverDatabase dal;
private static SqlPeerResolverDatabase DAL
{
get
{
if(dal == null)
{
lock (dalLock)
{
if (dal == null)
{
dal = new SqlPeerResolverDatabase();
}
}
}
return dal;
}
}
public override bool CanShareReferrals
{
get { return true; }
}
public override object Register(string meshId, PeerNodeAddress nodeAddress, TimeSpan timeout)
{
MaskScopeId(nodeAddress.IPAddresses);
int registrationId = DAL.Register(meshId, nodeAddress);
return registrationId;
}
public override ReadOnlyCollection<PeerNodeAddress> Resolve(string meshId, int maxAddresses, TimeSpan timeout)
{
PeerNodeAddress[] addresses = null;
addresses = DAL.Resolve(meshId, maxAddresses);
if (addresses == null)
{
addresses = new PeerNodeAddress[0];
}
return new ReadOnlyCollection<PeerNodeAddress>(addresses);
}
public override void Unregister(object registrationId, TimeSpan timeout)
{
DAL.Unregister((int)registrationId);
}
public override void Update(object registrationId, PeerNodeAddress updatedNodeAddress, TimeSpan timeout)
{
MaskScopeId(updatedNodeAddress.IPAddresses);
DAL.Update((int)registrationId, updatedNodeAddress);
}
void MaskScopeId(ReadOnlyCollection<IPAddress> ipAddresses)
{
foreach (IPAddress address in ipAddresses)
{
if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
address.ScopeId = 0;
}
}
}
}
public class SqlPeerResolverBindingElement : PeerResolverBindingElement
{
PeerReferralPolicy peerReferralPolicy = PeerReferralPolicy.Share;
static SqlPeerResolver resolverClient = new SqlPeerResolver();
public SqlPeerResolverBindingElement() { }
protected SqlPeerResolverBindingElement(SqlPeerResolverBindingElement other) : base(other) { }
public override PeerReferralPolicy ReferralPolicy
{
get
{
return peerReferralPolicy;
}
set
{
peerReferralPolicy = value;
}
}
public override BindingElement Clone()
{
return new SqlPeerResolverBindingElement(this);
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.BuildInnerChannelFactory<TChannel>();
}
public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelFactory<TChannel>();
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.BuildInnerChannelListener<TChannel>();
}
public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelListener<TChannel>();
}
public override PeerResolver CreatePeerResolver()
{
return resolverClient;
}
public override T GetProperty<T>(BindingContext context)
{
return context.GetInnerProperty<T>();
}
}
public class SqlPeerResolverConfigurationBindingElement : BindingElementExtensionElement
{
public override Type BindingElementType
{
get { return typeof(SqlPeerResolverBindingElement); }
}
protected override BindingElement CreateBindingElement()
{
return new SqlPeerResolverBindingElement();
}
}
}