WCF订阅替换轮训

使用WCF订阅替换轮训

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

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

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

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

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

  这里就使用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);
        }
复制代码
 
 
分类: 架构相关
原文地址:https://www.cnblogs.com/Leo_wl/p/3644123.html