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