[WCF编程]10.操作:事件
一、事件概述
基础的WCF回调机制并不能阐明客户端与服务之间交互的本质。双向回调的规范使用可以通过事件来完成。客户端发生的相关事项都可以通过事件通知客户端或者多个客户端。事件可能源于直接的客户端调用,也可能来源于服务监听器。激活事件的服务称为发布者,而接受事件答得客户端则称为订阅者。如下图所示:
![]()
与回调操作相比,WCF更重视对事件的运作。从本质讲,事件代表了发布者与订阅者之间更加松散的关系,他优于客户端和服务之间的关系。处理事件时,服务通常会为多个订阅客户端发布同样的事件。发布者一般不会考虑订阅者的回调数顺序,也不会考虑订阅者在处理事件时可能出现的错误。所有的发布者都直到它应该将事件传递给订阅者。如果事件出现问题,服务对此也束手无策。此外,服务并不关心订阅者返回的结果。因此,事件处理操作的返回值应该为void,而不需要返回值,因而应该被标记为单向操作。建议将事件分解为单独的回调契约,而不要在相同的契约中将事件和常规的回调混在一起。
public interface IMyEvent
{
[OperationContract(IsOneWay=true)]
void OnEvent1();[OperationContract(IsOneWay</span>=<span style="color: #0000ff">true</span><span style="color: #000000">)]
</span><span style="color: #0000ff">void</span> OnEvent2(<span style="color: #0000ff">int</span><span style="color: #000000"> number); [OperationContract(IsOneWay</span>=<span style="color: #0000ff">true</span><span style="color: #000000">)]
</span><span style="color: #0000ff">void</span> OnEvent3(<span style="color: #0000ff">int</span> number,<span style="color: #0000ff">string</span><span style="color: #000000"> text);
}</span></pre></div>
在订阅端,即使使用了单向回调操作,事件处理方法的实现也应该是执行周期较短的操作。其原因有二:第一,如果需要发布大量的事件,以至于超过了订阅者的能力,且由于队列正在处理前一个事件,无法将回调放入队列中,就会导致发布者被阻塞。阻塞了发布者就会阻止事件到达其它的订阅者;第二,如果存在大量的事件订阅者,每个订阅者所累加起来的处理事件就会操作发布者的超时值。
发布者可以为它的契约添加专门的操作,允许客户端显式地订阅事件或取消对事件的订阅。如果发布者支持多个事件类型,也可以允许订阅者选择它们希望订阅或取消订阅的事件。
服务如何从内部管理订阅者列表及选择它们的参数,完全属于服务端的实现细节,不会影响到客户端。发布者可以使用.NET委托管理订阅者列表和发布者自身的行为,也可以使用泛型进行管理。
[Flags]
public enum EvenType
{
Event1 = 1,
Event2 = 2,
Event3 = 4,
AllEvents = Event1 | Event2 | Event3
}[ServiceContract(CallbackContract </span>= <span style="color: #0000ff">typeof</span><span style="color: #000000">(IMyEventsCallback))]
</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span><span style="color: #000000"> IMyContract
{
[OperationContract]
</span><span style="color: #0000ff">void</span><span style="color: #000000"> DoSomething(); [OperationContract]
</span><span style="color: #0000ff">void</span><span style="color: #000000"> Subscribe(EvenType mask); [OperationContract]
</span><span style="color: #0000ff">void</span><span style="color: #000000"> UnSubscribe(EvenType mask);
} [ServiceBehavior(InstanceContextMode</span>=<span style="color: #000000">InstanceContextMode.PerCall)]
</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span><span style="color: #000000"> MyPublisher : IMyContract
{
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> Action m_Event1 = <span style="color: #0000ff">delegate</span><span style="color: #000000"> { };
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> Action<<span style="color: #0000ff">int</span>> m_Event2 = <span style="color: #0000ff">delegate</span><span style="color: #000000"> { };
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> Action<<span style="color: #0000ff">int</span>, <span style="color: #0000ff">string</span>> m_Event3 = <span style="color: #0000ff">delegate</span><span style="color: #000000"> { }; </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> Subscribe(EvenType mask)
{
IMyEventsCallback subscriber </span>= OperationContext.Current.GetCallbackChannel<IMyEventsCallback><span style="color: #000000">();
</span><span style="color: #0000ff">if</span> ((mask & EvenType.Event1) ==<span style="color: #000000"> EvenType.Event1)
{
m_Event1 </span>+=<span style="color: #000000"> subscriber.OnEvent1;
}
</span><span style="color: #0000ff">if</span> ((mask & EvenType.Event2) ==<span style="color: #000000"> EvenType.Event2)
{
m_Event2 </span>+=<span style="color: #000000"> subscriber.OnEvent2;
}
</span><span style="color: #0000ff">if</span> ((mask & EvenType.Event3) ==<span style="color: #000000"> EvenType.Event3)
{
m_Event3 </span>+=<span style="color: #000000"> subscriber.OnEvent3;
}
} </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> UnSubscribe(EvenType mask)
{
IMyEventsCallback subscriber </span>= OperationContext.Current.GetCallbackChannel<IMyEventsCallback><span style="color: #000000">();
</span><span style="color: #0000ff">if</span> ((mask & EvenType.Event1) ==<span style="color: #000000"> EvenType.Event1)
{
m_Event1 </span>-=<span style="color: #000000"> subscriber.OnEvent1;
}
</span><span style="color: #0000ff">if</span> ((mask & EvenType.Event2) ==<span style="color: #000000"> EvenType.Event2)
{
m_Event2 </span>-=<span style="color: #000000"> subscriber.OnEvent2;
}
</span><span style="color: #0000ff">if</span> ((mask & EvenType.Event3) ==<span style="color: #000000"> EvenType.Event3)
{
m_Event3 </span>-=<span style="color: #000000"> subscriber.OnEvent3;
}
} </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> FireEvent(EvenType eventType)
{
</span><span style="color: #0000ff">switch</span><span style="color: #000000"> (eventType)
{
</span><span style="color: #0000ff">case</span><span style="color: #000000"> EvenType.Event1:
{
m_Event1();
</span><span style="color: #0000ff">return</span><span style="color: #000000">;
}
</span><span style="color: #0000ff">case</span><span style="color: #000000"> EvenType.Event2:
{
m_Event2(</span><span style="color: #800080">42</span><span style="color: #000000">);
</span><span style="color: #0000ff">return</span><span style="color: #000000">;
}
</span><span style="color: #0000ff">case</span><span style="color: #000000"> EvenType.Event3:
{
m_Event3(</span><span style="color: #800080">42</span>, <span style="color: #800000">"</span><span style="color: #800000">Hello</span><span style="color: #800000">"</span><span style="color: #000000">);
</span><span style="color: #0000ff">return</span><span style="color: #000000">;
}
</span><span style="color: #0000ff">default</span><span style="color: #000000">:
{
</span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> InvalidOperationException(<span style="color: #800000">"</span><span style="color: #800000">Unkown event type</span><span style="color: #800000">"</span><span style="color: #000000">);
}
}
} </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> DoSomething()
{
</span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span><span style="color: #000000"> NotImplementedException();
}
}</span></pre></div>
服务契约IMyContract定义了Subscribe()和UnSubscribe()方法。这些方法接受一个枚举类型EventType,枚举类型的字段均被设置为2的指数。这就能使订阅客户端通过枚举值掩码标识事件类型是订阅还是取消订阅。例如,订阅Event1和Event3,但不订阅Event2订阅者会调用如下的Subsctibe()方法:
class Program
{
static void Main(string[] args)
{
IMyEventCallback subscriber = new MySubscriber();
InstanceContext context = new InstanceContext(subscriber);
MyContractClient proxy = new MyContractClient(context);
proxy.Subscribe(Service.EvenType.Event1 | Service.EvenType.Event3);
proxy.DoSomething();
proxy.Close();
Console.Read();}
} </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span><span style="color: #000000"> MySubscriber : IMyEventCallback
{
</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> OnEvent1()
{
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000">OnEvent1 Action</span><span style="color: #800000">"</span><span style="color: #000000">);
} </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> OnEvent2(<span style="color: #0000ff">int</span><span style="color: #000000"> number)
{
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000">OnEvent2 Action,number={0}</span><span style="color: #800000">"</span><span style="color: #000000">,number);
} </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> OnEvent3(<span style="color: #0000ff">int</span> number, <span style="color: #0000ff">string</span><span style="color: #000000"> text)
{
Console.WriteLine(</span><span style="color: #800000">"</span><span style="color: #800000">OnEvent3 Action,number={0},text={1}</span><span style="color: #800000">"</span><span style="color: #000000">, number,text);
}
}</span></pre></div>
MyPublisher内部维持了三个静态委托,每一个委托对应一个事件类型。
Subscribe()与UnSubscribe()方法都检查;额传入参数EventType值,从对应的委托中添加或移除订阅者的回调。为了触发事件,MyPublisher提供了静态方法FireEvent()。他根据EventType值判断应该触发哪一个事件,然后调用对应的委托。
示例代码:下载
[WCF编程]10.操作:事件的更多相关文章
- [WCF编程]10.操作:流操作
一.流操作概述 在默认情况下,当客户端调用服务时,服务只有在接收到完整的消息后才会被调用,同样,客户端只有在包含了调用结果的返回消息被完整接受时,才会解除对它的阻塞. 对于数据量小的消息,这种交换模式 ...
- [WCF编程]10.操作:回调操作
一.回调操作概述 WCF支持服务将调用返回给它的客户端.在回调期间,许多方面都将颠倒过来:服务将成为客户端,客户端将编程服务.回调操作可以用在各种场景和应用程序中,但在涉及事件或者服务发生时间需要通知 ...
- [WCF编程]10.操作:请求/应答操作
一.调用操作概述 WCF除了支持经典的服务端-客户端的请求/应答操作外,还提供了对其他操作类型的内建支持,包括:即发即弃的单向调用:允许服务将调用返回给客户端的双向回调:允许客户端或服务器处理大量负荷 ...
- [WCF编程]10.操作:单向操作
一.单向操作概述 WCF提供了单向操作,一旦客户端调用,WCF会生成一个请求,但没有相关的应答信息返回给客户端.所以,单向操作是不能有返回值,服务抛出的任何异常都不会传递给客户端. 理想情况下,一旦客 ...
- jquery css事件编程 位置 操作
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Windows 10开发基础——指针事件和操作事件(一)
主要内容: 1.指针事件 2.操作事件 1.指针事件 指针事件由各种活动输入源引发,包括触摸.触摸板.笔和鼠标(它们替代传统的鼠标事件).指针事件基于单一输入点(手指.笔尖.鼠标光标),但不支持基于速 ...
- .Net-WCF-图书:《WCF编程》
ylbtech-.Net-WCF-图书:<WCF编程> <WCF编程>是2008年1月机械工业出版社出版的图书,作者是Juval Lowy.Clemens Vasters. 1 ...
- WCF初探-10:WCF客户端调用服务
创建WCF 服务客户端应用程序需要执行下列步骤: 获取服务终结点的服务协定.绑定以及地址信息 使用该信息创建 WCF 客户端 调用操作 关闭该 WCF 客户端对象 WCF客户端调用服务存在以下特点: ...
- WCF编程系列(五)元数据
WCF编程系列(五)元数据 示例一中我们使用了scvutil命令自动生成了服务的客户端代理类: svcutil http://localhost:8000/?wsdl /o:FirstServic ...
随机推荐
- Android安全开发之浅谈密钥硬编码
Android安全开发之浅谈密钥硬编码 作者:伊樵.呆狐@阿里聚安全 1 简介 在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码.文件中,这样做会引起很大风 ...
- 剑指Offer面试题:31.两个链表的第一个公共节点
一.题目:两个链表的第一个公共节点 题目:输入两个链表,找出它们的第一个公共结点. 链表结点定义如下,这里使用C#语言描述: public class Node { public int key; p ...
- 《Entity Framework 6 Recipes》中文翻译系列 (15) -----第三章 查询之与列表值比较和过滤关联实体
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-8与列表值比较 问题 你想查询一个实体,条件是给定的列表中包含指定属性的值. 解 ...
- [Linux] linux下安装配置 zookeeper/redis/solr/tomcat/IK分词器 详细实例.
今天 不知自己装的centos 出现了什么问题, 一直卡在 启动界面, 找了半天没找见原因(最后时刻还是发现原因, 只因自己手欠一怒之下将centos删除了, 而且选择的是在本地磁盘也删除. ..让我 ...
- LR中的时间戳函数web_save_timestamp_param
以前真没注意过后面看某个群有人说到这个函数一查,还真有,那么处理时间戳就简单很多了,我们经常在各种网站上看到类似于这样的时间戳 51Testing软件测试网"d bLq!uR&am ...
- 有关binlog的那点事(mysql5.7.13)
binlog作为mysql中最重要的日志之一,能实现异常恢复以及主从复制. 我们主要讨论的是主从复制中的binlog,这里将以mysql5.7.13的源码为主要依据来分析binlog. 在主从复制中, ...
- MVC4做网站后台:模块管理1、修改模块信息
网站可能会包含一些模块:像文章.产品.图片.留言等. 栏目模块主要实现功能,启用或禁用模块,模块权限设置,模块上传设置等. 权限设置和上传设置以后专门考虑,先来显示或禁用模块. 1.在顶部导航栏添加管 ...
- mysql数据库学习目录
前面的话 对于前端工程师来说,数据库并不是主要技能点,但是基本的增删改查操作还是需要了解的.小火柴将mysql数据库的学习记录整理如下 目录 前端学数据库之基础操作 前端学数据库之数据类型 前端学数 ...
- 创建第二个 vlan network "vlan101" - 每天5分钟玩转 OpenStack(96)
前面我们创建了 vlan100,并部署了 instance,今天将继续创建第二个 vlan network "vlan101". subnet IP 地址为 172.16.101. ...
- Linux异常表
一.为什么需要异常表? 处于内核态的程序有下面四种情况会产生缺页异常: 1.内核试图访问属于进程地址空间的页,但是,该页对应的页框不存在或者内核试图去访问一个只读的页,分别对应“请求调页”和“写时复制 ...