【发布时间】:2012-06-23 03:28:39
【问题描述】:
我想创建一个 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) 放在订阅方法的末尾,它甚至可以与 Timer(三秒)一起使用,所以我的猜测是订阅方法完成后,回调对象的通道可能会关闭。对使用 OperationContext.Current.GetCallbackChannel(); 检索的回调对象使用类范围变量而不是方法范围变量没有帮助。
以前我尝试在计时器服务的 Timer 的经过事件处理程序中创建新线程以使其更快。 ObjectDisposedException 引发了以下消息:“无法访问已处置的对象。对象名称:'System.ServiceModel.Channels.ServiceChannel”。然后我尝试简化我的服务,发现即使只使用 Timer 也会导致所描述的问题,但我猜这个异常表明与客户端回调对象的连接在某个地方丢失了。奇怪的是,如果我不在 Timer 线程中创建新线程,没有异常。只是没有调用回调方法。
【问题讨论】:
-
您可能需要设置
IsOneWay = false,因为它是一个双工系统,而不是一劳永逸。
标签: c# .net multithreading wcf callback