技术开发 频道

WPF中的发布-订阅服务(下)


    GetTransientList()根据指定的操作查找临时存储的所有订阅者,然后以数组形式返回。GetPersistentList()面临更大的挑战:框架没有现成的持久订阅者的代理列表;我们所能获知的只是它们的地址。因此,GetPersistentList()需要实例化持久订阅者的代理,如例B-7所示。

    例B-7 创建持久订阅者的代理列表
public abstract class SubscriptionManager<T> where T : class
{
internal static T[] GetPersistentList(string eventOperation)
{
string[] addresses = GetSubscribersToContractEventOperation(
typeof(T).ToString( ),eventOperation);

List<T> subscribers = new List<T>(addresses.Length);

foreach(string address in addresses)
{
Binding binding = GetBindingFromAddress(address);
T proxy = ChannelFactory<T>.CreateChannel(binding,
new EndpointAddress(address));
subscribers.Add(proxy);
}
return subscribers.ToArray( );
}
static string[] GetSubscribersToContractEventOperation(string eventsContract,
string eventOperation)
{
//使用ADO.NET在SQL Server中查询事件的订阅者
}
static Binding GetBindingFromAddress(string address)
{
if(address.StartsWith("http:") || address.StartsWith("https:"))
{
WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message,true);
binding.ReliableSession.Enabled = true;
binding.TransactionFlow = true;
return binding;
}
if(address.StartsWith("net.tcp:"))
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message,true);
binding.ReliableSession.Enabled = true;
binding.TransactionFlow = true;
return binding;
}
/* 命名管道绑定与MSMQ绑定与上面的代码相似*/
Debug.Assert(false,"Unsupported protocol specified");
return null;
}
//更多成员
}
    若要为每个订阅者创建代理,GetPersistentList()方法需要订阅者的地址、绑定和契约。当然,契约正好就是SubscriptionManager<T>的类型参数。为获取地址,GetPersistentList()方法调用了GetSubscribersToContractEventOperation()查询数据库,然后返回那些订阅了特定事件的持久订阅者的所有地址的数组。现在,GetPersistentList()方法所需要的就是每个订阅者的绑定。为此,GetPersistentList()调用了辅助方法GetBindingFromAddress(),它可以根据地址样式推断出使用的绑定。GetBindingFromAddress()将所有的HTTP地址当作WSHttpBinding。此外,GetBindingFromAddress()还为每个绑定实现了可靠性以及事务传播。如果没有使用单向操作,则允许在发布者的事务中包含事件,例如这样的事件契约:

[ServiceContract] 
interface IMyEvents
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void OnEvent1( );

[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void OnEvent2(int number);

[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void OnEvent3(int number,string text);
}
0
相关文章