我想制作一个 WCF 计时器服务,客户端可以在其中注册,以便在经过一定时间后从服务中回调。问题是客户端没有被回调。不抛出异常。
回调接口为:
[ServiceContract]
public interface ITimerCallbackTarget
{
[OperationContract(IsOneWay = true)]
void OnTimeElapsed(int someInfo);
}
该服务如下所示:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Single)]
public class TimerService : ITimerService
private readonly Timer _timer = new Timer(2000); //System.Timers.Timer
public void Subscribe()
{
ITimerCallbackTarget listener =
OperationContext.Current.GetCallbackChannel<ITimerCallbackTarget>();
_timer.Elapsed += (p1, p2) =>
{
listener.OnTimeElapsed(999);
};
_timer.Start();
}
客户端使用的回调方法是:
private class TimerCallbackTarget : ITimerCallbackTarget
{
public void OnTimeElapsed(int someInfo)
{
Console.WriteLine(someInfo);
}
}
客户端注册如下:
private static void TestTimerService()
{
InstanceContext callbackInstance = new InstanceContext(new TimerCallbackTarget());
using (DuplexChannelFactory<ITimerService> dcf =
new DuplexChannelFactory<ITimerService>(callbackInstance,
"TimerService_SecureTcpEndpoint"))
{
ITimerService timerProxy = dcf.CreateChannel();
timerProxy.Subscribe();
}
}
如果我在没有Timer的 subscribe 方法中使用不同的线程,它可以工作:
ThreadPool.QueueUserWorkItem(p =>
{
listener.OnTimeElapsed(999);
});
如果我将Thread.Sleep(3000)放在 subscribe 方法的末尾,它甚至可以与Timer一起使用(三秒钟) ,所以我的猜测是,回调对象的通道可能在 subscribe 方法完成后关闭。对通过OperationContext.Current.GetCallbackChannel()检索到的回调对象使用类范围变量;而不是方法范围变量没有帮助。
以前我尝试在计时器服务的计时器的经过事件处理程序中创建新线程以使其更快。引发ObjectDisposedException并显示以下消息:“无法访问已处置的对象。对象名称:'System.ServiceModel.Channels.ServiceChannel”。然后我尝试简化我的服务,发现即使只使用Timer也会导致所描述的问题,但我猜这个异常表明与客户端回调对象的连接在某个地方丢失了。奇怪的是,如果我不在Timer线程中创建新线程,没有异常。只是没有调用回调方法。