如何使用WCF订阅替换轮训

之前因为某些特定岗位的人不知道是不方便还是什么的原因,所以随便做了个独立于所有系统之外的邮件审批服务,功能是那些人在邮件里给待审批单据发个“同意”就自动审批通过,大致分为3部分:第一部分每隔固定时间去邮件服务器抓一批邮件下来;第二部分分析邮件格式,如果符合就提取必须的邮件内容;第三部分提交审批流驱动进行审批。

我一直想做个移动端APP然后废掉它算了,不过似乎领导觉得这个东西还能撑下去,总之就一时半会是不可能干掉了。

所以,游戏之做还是得优化一下,这里就说说第一部分:

每隔固定时间抓取然后执行存在的问题,比如说现在是每隔十分钟抓一次,处理不怎么及时,而且即使没有新邮件也会去抓一次,另外还有一个隐藏的问题,就是为什么设置10分钟,主要是邮件服务器那边还有其他的处理,需要一个回执,但是这是个单线程的服务(因为用的人很少)所以担心设置的时间短了这一批抓取的还没处理完,这里有一些无关的事都耦合上了。

解决办法:不再去抓邮件,而是如果邮件审批服务空闲了,就去邮件服务器上注册一下,如果有了新邮件,就由邮件服务器发布任务,这样以后用的人多了还可以做分布式处理(当然,我还是倾向于不用这种方式了,因为各种客户端发出来的邮件千奇百怪,解析难保正确)。

本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/net/

这里就使用WCF的订阅发布来做了,其实我觉得在没什么压力的情况下,有些消息队列也可以用这种方法简化

下面是测试代码:

首先是配置文件

<service name="HotelService.PublishService">
        <endpoint address="" binding="wsDualHttpBinding" contract="HotelService.IPublishService" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>

服务和回调契约:

[ServiceContract(CallbackContract = typeof(ISubscribeCallback), Namespace = "http://www.justonlyatest.com")]
    public interface IPublishService
    {
        [OperationContract(IsOneWay = true)]
        void DoWork();

        [OperationContract(IsOneWay = true)]
        void Subscribe(string id);

        [OperationContract(IsOneWay = true)]
        void UnSubscribe(string id);
    }

    public interface ISubscribeCallback
    {
        [OperationContract]//(IsOneWay = true)
        void CallbackWork(string workState);
    }

服务实现,注释里简单交代了下实例模型下的效果

// InstanceContextMode.Single 同步通知所有订阅的客户端,可将服务作为版本服务器的客户端,同步分布式服务的版本信息
    // InstanceContextMode.PerSession 同步同一Session下的所有订阅,本例中单个客户端实例的所有订阅
    // InstanceContextMode.PerCall 由于所有请求都是独立服务实例,所以无法实现订阅
    // ConcurrencyMode.Single 回调必须是IsOneWay
    // 回调是IsOneWay时可同步通知所有订阅方,否则只能顺序通知
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public class PublishService : IPublishService
    {
        Subscribers subscribers = new Subscribers();
        public void DoWork()
        {
            string workState = "完成";
            //ISubscribeCallback callback = OperationContext.Current.GetCallbackChannel<ISubscribeCallback>();
            //callback.CallbackWork(workState);

            Dictionary<string, ISubscribeCallback> subscribes = subscribers.Subscribes;
            foreach (var key in subscribes.Keys)
            {
                subscribes[key].CallbackWork(key + ":" + workState);
            }
        }

        public void Subscribe(string id)
        {
            ISubscribeCallback callback = OperationContext.Current.GetCallbackChannel<ISubscribeCallback>();
            subscribers.AddSubscriber(id, callback);
        }

        public void UnSubscribe(string id)
        {
            ISubscribeCallback callback = OperationContext.Current.GetCallbackChannel<ISubscribeCallback>();
            subscribers.RemoveSubscriber(id, callback);
        }
    }
public class Subscribers
    {
        public Dictionary<string, ISubscribeCallback> Subscribes { get; set; }

        public Subscribers()
        {
            Subscribes = new Dictionary<string, ISubscribeCallback>();
        }

        public void AddSubscriber(string id,ISubscribeCallback callback)
        {
            if (!Subscribes.Keys.Contains(id))
            {
                Subscribes.Add(id, callback);
            }
        }

        public void RemoveSubscriber(string id, ISubscribeCallback callback)
        {
            if (Subscribes.Keys.Contains(id))
            {
                Subscribes.Remove(id);
            }
        }
    }

客户端测试

PublishService.PublishServiceClient client;
        string clientID;

        public TestSubscribe()
        {
            InstanceContext context = new InstanceContext(new CallbackSubscribe());
            client = new PublishService.PublishServiceClient(context);

            clientID = Guid.NewGuid().ToString();
        }

        private void btnTest_Click(object sender, EventArgs e)
        {
            client.DoWork();
        }

        private void btnRegist_Click(object sender, EventArgs e)
        {
            client.Subscribe(clientID);
        }

        private void btnCancellation_Click(object sender, EventArgs e)
        {
            client.UnSubscribe(clientID);
        }

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索string
, 邮件
, callback
, 邮件服务器
, public
, IsOneWay
, subscribe
void
wcf 订阅发布、使用wcf的三级联动、wcf使用、wcf nettcp 无法使用、wcf使用tcp传输文件,以便于您获取更多的相关知识。

时间: 2024-12-30 14:43:54

如何使用WCF订阅替换轮训的相关文章

《微软云计算Windows Azure开发与部署权威指南》——6.5 AppFabric服务总线基础概念

6.5 AppFabric服务总线基础概念 在大型分布式应用程序中最常见的需求之一就是连通性,而应用程序的整合通常也是IT领域中花费最高.最麻烦的.目前大多数组织机构都采用企业服务总线(ESB)这一解决方案. 作为Windows Azure平台的一部分,服务总线让ESB模式在整个Internet领域中成为现实.服务总线提供了很多可以在典型的ESB解决方案中看到的体系结构特点,包括身份认证和访问控制.命名.服务注册.公共消息池等.对于AppFabric服务总线,这些组件必须设计为能够在云端操作,面

在 WCF 中使用高效的 BinaryFormatter 序列化

本文将定义一个 WCF 终结点行为扩展,以在 WCF 中使用更高效的 BinaryFormatter 进行二进制序列化,并实现对是否使用传统二进制序列化功能的可配置. 介绍 实现步骤 使用方法 效果   介绍 在 OEA 框架中,是使用 WCF 作为数据传输框架.但是使用 WCF 内部的二进制序列化,序列化后的数据大小,要比使用传统的 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 类进行序列化后的数据大小要大得多.作

ASP.NET实例教程:订阅 GeoRSS 订阅源

在此练习中,您将在 ASP.NET Web 应用程序中实现 HTTP 处理程序以返回 GeoRSS 订阅源.GeoRSS 是在 RSS 订阅源中包含地理空间数据时所用的一个标准,它定义了一种名为 GeoRSS GML 的特定格式,用来在订阅源中包含 GML 格式的数据.客户端应用程序可以订阅 GeoRSS 订阅源,订阅方式与订阅常规 RSS 订阅源相同.可以轻松地将 GeoRSS 格式的数据导入 Microsoft Virtual Earth VEMap 控件中. 注意:您可以从 C:\SQLH

Silverlight3系列(一)Silverlight配合WCF进行数据库操作

1.环境配置 本文的Silverlight版本为Silverlight3,具体的配置过程可以参考:http://www.cnblogs.com/psunny/archive/2009/08/31/1556976.html或者http://www.cnblogs.com/wheeloffate/archive/2009/08/25/1553973.html 如果希望破解expression studio 3的话,可以在google中搜索[expression studio 3 破解],也就是将下载

WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用

如果一个类型,不一定是数据契约,和给定的数据契约具有很大的差异,而我们要将该类型的对象序列化成基于数据契约对应的XML.反之,对于一段给定的基于数据契约的XML,要通过反序列化生成该类型的对象,我们该如何实现这样的场景? 比如下面定义了两个类型Contact和Customer,其中Customer是数据契约,Contact的Sex属性相当于Customer的Gender属性,而Contact的FullName可以看成是Customer的FirstName和LastName的组合.现在我们要做的是

WCF从理论到实践(17):OO大背离

概述 上文说到了WCF和传统面向对象编程中不太一致的地方之一:操作重载(Operation Overload),本文讲述WCF 另外一个不太符合OO之处:服务契约和数据契约的继承关系.在面向对象的大原则中有下面两个原则 1) 依赖倒置原则 2) Liskov替换原则 依赖倒置原则强调的是实现依赖于抽象,抽象不依赖于实现 ,而Liskov原则强调的是子类必须可以替换其基类,这在anytao大作<<你必须知道的.Net>>中都有详细的阐述.本文无意阐述这两个原则的细节,想了解OO原则的

WCF学习(五):数据契约之已知类型

准备技术: 1.C#基础知识 2.了解WCF基础知识 在正常的c#开发中我们是允许用子类去替换基类的,这也是所谓的替换原则.但是我们在WCF中确不能用数据契约的子类来替换父类的,因为这中间存在一个序列化的问题.举个例子: 我们有数据契约: [DataContract] class Employee{...} 服务契约中: [ServiceContract] interface IEmployeeManager { [OperationContract] void AddEmployee(Empl

WCF后续之旅(9):通过WCF的双向通信实现Session管理[Part I]

我们都知道,WCF支持Duplex的消息交换模式,它允许在service的执行过程中实现对client的回调.WCF这种双向通信的方式是我们可以以Event Broker或者订阅/发布的方式来定义和调用WCF Service.今天我们就给大家一个具体的例子:通过WCF的duplex communication方式现在Session管理. 1.Session 管理提供的具体功能 我们的例子实现了下面一些Session Management相关的功能: Start/End Session:可以调用s

WCF分布式开发步步为赢(6):WCF服务契约继承与分解设计

上一节我们学习了WCF分布式开发步步为赢(5)服务契约与操作重载部分.今天我们来继续学习WCF服务契约继承和服务分解设计相关的知识点.WCF服务契约继承有何优势和缺点?实际项目里契约设计有什么原则和依据?面向对象的设计经验有何值得借鉴的地方?这里我们会一一给出详细的介绍.本文首先介绍的是WCF服务中契约继承的一些概念.例子代码分析,其次来讲解服务契约的设计问题.首先介绍的也是进行服务设计的必要性,服务设计的原则,示例代码分析.最后是全文的总结部分.结构如下:[1]OO面向对象设计原则,[2]服务