一、事件概述
基础的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值判断应该触发哪一个事件,然后调用对应的委托。
示例代码:下载
- 相关阅读:
带色彩恢复的多尺度视网膜增强算法(MSRCR)的原理、实现及应用。
索引图像的那些事啊
调整图像 自动对比度、自动色阶算法
图像处理界双线性插值算法的优化
共享收集的图像处理方面的一些资源和网站。
Wellner 自适应阈值二值化算法
基于灰度世界、完美反射、动态阈值等图像自动白平衡算法的原理、实现及效果
VB6.0用GDI+保存图像为BMP\JPG\PNG\GIF格式终结版。
关于.net中获取图像缩略图的函数GetThumbnailImage的一些认识。
限制对比度自适应直方图均衡化算法原理、实现及效果
- 原文地址:https://www.cnblogs.com/zxj159/p/3993090.html
- 最新文章
将一个字符串分成多列
统计文章各种分类总数
图片裁剪 PhotoCropper
统计交叉相等两列元祖的次数 去掉重复
用PARSENAME函数拆分字符串
SQL 快速生成测试数据
多行合并2列并去掉重复列
小计 合计 统计
班级考试人数大于10、班级最低分在50分以上、计算机学院、班级平均分从高到低前10名
Unsharp Mask(USM)锐化算法的的原理及其实现。
- 热门文章
颜色空间系列3: RGB和YCbCr颜色空间的转换及优化算法
简单而又快速的获取一副真彩色图像实际使用的颜色数。
访问图像像素信息方式的优化
收集的网络上大型的开源图像处理软件代码(提供下载链接)
从GIMP的Retinex算法里发现了一种高斯模糊的快速实现方法【开发记录】。
将图像转换为JPG或GIF字节流。
颜色空间系列4: RGB和YDbDr颜色空间的转换及优化算法
C#调用GDI+1.1中的函数实现高斯模糊、USM锐化等经典效果。
颜色空间系列1: RGB和CIEXYZ颜色空间的转换及相关优化
基于色彩恒常( color constancy)特性的FrankleMcCann Retinex图像增强。