WCF中使用观察者模式实现事件通知
2008-04-25 17:28
661 查看
看了一些WCF的例子,实现事件通知使用的是多播委托的特性,有点复杂,操作起来也不是很直观,看到一堆委托和事件我一般头就晕了。下面介绍一种使用观察者模式实现事件通知的简单方法。没别的,就是简单,简单最美。
工程代码如下:http://files.cnblogs.com/dyj057/WcfEvent.rar
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. 这里使用的是单实例的服务,所以需要进行多进程访问的保护,才能实际使用。
工程代码如下:http://files.cnblogs.com/dyj057/WcfEvent.rar
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. 这里使用的是单实例的服务,所以需要进行多进程访问的保护,才能实际使用。
相关文章推荐
- WCF中使用观察者模式实现事件通知
- 设计模式(二):自己动手使用“观察者模式”实现通知机制
- C#中使用委托和事件实现观察者模式(observer pattern)
- 使用UnrealScript实现基于观察者模式的事件系统
- C#中使用委托和事件实现观察者模式(observer pattern)
- 使用委托和事件实现观察者模式(Observer Pattern)
- 如何使用委托与事件来实现观察者模式
- 委托、Lambda表达式、事件系列06,使用Action实现观察者模式,体验委托和事件的区别
- 使用委托和事件实现观察者模式(Observer Pattern)
- 多线程异步编程(2):创建多个线程执行任务,同时更新进度条,使用观察者模式,利用事件通知界面更新。移除对Form的引用,彻底解除界面与逻辑的耦合
- 《Effective C#》读书笔记——条目25:用事件模式实现通知<使用C#表达设计>
- 实现一个简单的事件订阅通知机制(Observer模式实现)
- Java使用观察者模式实现气象局高温预警功能示例
- 使用javascript模拟观察者模式和事件监听广播机制
- 使用 Java8 实现观察者模式的方法(下)
- 如何使用 Java8 实现观察者模式?(上)
- 使用java提供的Observable,实现观察者模式
- JTABLE 一个小格子添加2个按钮实现国际化 使用观察者设计模式
- 委托、事件、Observer观察者模式的使用解析一
- 利用观察者模式实现通知