最近工作中遇到这样一个WCF问题,宿主程序加载WCF服务后需要得到服务的反馈消息。
问题:宿主启动后与服务是分离状态,如何及时得到服务的反馈消息?如果是在winform中我们可以直接通过事件取得,这于WCF的实现有所不同。
处理方式:
参用WCF实现订阅/发布方式实现服务消息向订阅者发布
具体代码:
参考:WCF 事件 Events ,Oreilly.Programming.WCF.Services.3rd.Edition.Aug.2010.pdf
契约
using System;
using System.ServiceModel;
namespace ConsoleServer
{
[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); }
}
服务
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.Collections.Generic;
namespace ConsoleServer
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class LogService:ILogService
{
Dictionary<string, OperationContext> listeners = new Dictionary<string, OperationContext>();
public LogService()
{
Trace.WriteLine("Create LogService Instance.");
}
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
}
}
调用
using System;
using System.ServiceModel;
namespace ConsoleServer
{
class Program
{
static void Main(string[] args)
{
try
{
using (ServiceHost host = new ServiceHost(typeof(LogService)))
{
host.AddServiceEndpoint(typeof(ILogService), new NetNamedPipeBinding(),
"net.pipe://localhost/LogService");
host.Opened += (sender, e) =>
{
Console.WriteLine("service is start");
LogClient client = new LogClient();
ILogService service = DuplexChannelFactory<ILogService>.CreateChannel
(client, new NetNamedPipeBinding(),
new EndpointAddress("net.pipe://localhost/LogService"));
service.RegisterListener();
service.Write("client start");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("press any key exits");
Console.ReadLine();
service.UnregisterListener();
};
host.Open();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
public class LogClient : IWriteLogCallback
{
#region IWriteLogCallback Members
public void OnWriteLog(string logMsg)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(logMsg);
}
#endregion
}
}