Welcome

首页 / 软件开发 / WCF / 如何使用WCF订阅替换轮训

如何使用WCF订阅替换轮训2015-12-17 cnblogs 起名什么的...之前因为某些特定岗位的人不知道是不方便还是什么的原因,所以随便做了个独立于所有系统之外的邮件审批服务,功能是那些人在邮件里给待审批单据发个“同意”就自动审批通过,大致分为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);}