WCF实现事件通知是一个比较容易掌握的知识点,不过在实现的过程中,我们还是需要注意一些事项,以保证功能的完善性。
WCF中有一些方法的应用对于初学者来说还是比较容易应用。只要熟练的联系这些方法操作,一般都能牢固的掌握。看了一些WCF的例子,实现事件通知使用的是多播委托的特性,有点复杂,操作起来也不是很直观,看到一堆委托和事件我一般头就晕了。
下面介绍一种使用观察者模式WCF实现事件通知的简单方法。没别的,就是简单,简单最美。
工程代码如下:
WCF实现事件通知1.定义接口
[ServiceContract(SessionModeSessionMode = SessionMode.Required, CallbackContract = typeof(IWriteLogCallback))] public interface ILogService { [OperationContract(IsInitiating = true, IsTerminating = false)] void Write(string logMsg); [OperationContract(IsInitiating = true, IsTerminating = false)] void RegisterListener(); [OperationContract(IsInitiating = false, IsTerminating = false)] void UnregisterListener(); } [ServiceContract] public interface IWriteLogCallback { [OperationContract(IsOneWay = true)] void OnWriteLog(string logMsg); }
为了简单举了一个写日志的例子, Write(string logMsg)就是写入日志的方法,参数logMsg是需要写入的日志信息。当客户单没有调用RegisterListener()订阅事件的时候,是不会收到写日志的事件通知的,相应的要获得写日志的事件通知,就需要调用RegisterListener()方法。如果要取消订阅就调用UnregisterListener()方法。写日志的功能和事件的订阅功能是分开的。
WCF实现事件通知2.服务实现
[ServiceBehavior( IncludeExceptionDetailInFaults = true, InstanceContextModeInstanceContextMode = InstanceContextMode.Single, ConcurrencyModeConcurrencyMode = ConcurrencyMode.Multiple)] class LogService:ILogService { public LogService() { Trace.WriteLine("Create LogService Instance."); } Dictionary<string, OperationContext> listeners = new Dictionary<string, OperationContext>(); private void BroadCast(string logMsg) { List<string> errorClints = new List<string>(); foreach (KeyValuePair<string, OperationContext> listener in listeners) { try { listener.Value.GetCallbackChannel <IWriteLogCallback>().OnWriteLog(logMsg); } catch (System.Exception e) { errorClints.Add(listener.Key); Trace.WriteLine("BROAD EVENT ERROR:" + e.Message); } } foreach (string id in errorClints) { listeners.Remove(id); } } #region ILogService 成员 public void Write(string logMsg) { Trace.WriteLine("Write LOG:"+logMsg); BroadCast(logMsg); } public void RegisterListener() { listeners.Add(OperationContext.Current. SessionId, OperationContext.Current); Trace.WriteLine("SessionID:" + OperationContext.Current.SessionId); Trace.WriteLine("Register listener. Client Count:" + listeners.Count.ToString()); } public void UnregisterListener() { listeners.Remove(OperationContext .Current.SessionId); Trace.WriteLine("SessionID:" + OperationContext.Current.SessionId); Trace.WriteLine("Unregister listener. Client Count:" + listeners.Count.ToString()); } #endregion } Dictionary<string, OperationContext>
listeners包含了所有的事件订阅者。发布事件的时候,如果调用订阅者的回调函数失败,就把该订阅者从listeners移除。代码很简单,就不多说了。
WCF实现事件通知3.客户端访问
定义回调的客户端:
class LogClient:IWrite LogCallback { #region IWriteLog Callback 成员 public void OnWriteLog (string logMsg) { Trace.WriteLine("RECV LOG EVENT:" + logMsg); } #endregion }
然后在程序中使用它:
class Program { static void Main(string[] args) { Trace.Listeners.Add(new ConsoleTraceListener()); LogClient client = new LogClient(); ILogService service = DuplexChannelFactory<ILogService>. CreateChannel(client, new WSDualHttpBinding(), new EndpointAddress("http: //localhost:8888/log")); //订阅消息 service.RegisterListener(); service.Write("Client start"); Console.WriteLine("Press enter key to exit."); Console.ReadLine(); service.UnregisterListener(); }
WCF实现事件通知需要注意的问题:
A. 因为客户也要监听端口,所以确保防火墙没有对它进行阻止。
B. 这里使用的是单实例的服务,所以需要进行多进程访问的保护,才能实际使用。