WCF中使用观察者模式实现事件通知

    技术2026-01-10  1

     1.定义接口

    [ServiceContract(SessionMode  =  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()方法。写日志的功能和事件的订阅功能是分开的。     2.服务实现

    [ServiceBehavior(             IncludeExceptionDetailInFaults  =   true ,             InstanceContextMode  =  InstanceContextMode.Single,             ConcurrencyMode  =  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移除。代码很简单,就不多说了。     3.客户端访问     定义回调的客户端: class  LogClient:IWriteLogCallback     {          #region  IWriteLogCallback 成员          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();         } 需要注意的问题: A. 因为客户也要监听端口,所以确保防火墙没有对它进行阻止。 B. 这里使用的是单实例的服务,所以需要进行多进程访问的保护,才能实际使用。
    最新回复(0)