为什么即使我的服务调用和回调成功,我也会获得WCF超时?

时间:2012-08-01 03:47:48

标签: c# wcf

我正在玩游戏控制台连接到WCF接口,因此外部应用程序可以发送控制台命令并接收控制台输出。为此,我创建了以下服务合同:

public interface IConsoleNetworkCallbacks
{
    [OperationContract(IsOneWay = true)]
    void NewOutput(IEnumerable<string> text, string category);
}

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IConsoleNetworkCallbacks))]
public interface IConsoleInterface
{
    [OperationContract]
    void ProcessInput(string input);

    [OperationContract]
    void ChangeCategory(string category);
}

在服务器上我实现了它:

public class ConsoleNetworkInterface : IConsoleInterface, IDisposable
{
    public ConsoleNetworkInterface()
    {
        ConsoleManager.Instance.RegisterOutputUpdateHandler(OutputHandler);
    }

    public void Dispose()
    {
        ConsoleManager.Instance.UnregisterOutputHandler(OutputHandler);
    }

    public void ProcessInput(string input)
    {
        ConsoleManager.Instance.ProcessInput(input);
    }

    public void ChangeCategory(string category)
    {
        ConsoleManager.Instance.UnregisterOutputHandler(OutputHandler);
        ConsoleManager.Instance.RegisterOutputUpdateHandler(OutputHandler, category);
    }

    protected void OutputHandler(IEnumerable<string> text, string category)
    {
        var callbacks = OperationContext.Current.GetCallbackChannel<IConsoleNetworkCallbacks>();
        callbacks.NewOutput(text, category);
    }
}

在客户端,我用以下方法实现了回调:

public class Callbacks : IConsoleNetworkCallbacks
{
    public void NewOutput(IEnumerable<string> text, string category)
    {
        MessageBox.Show(string.Format("{0} lines received for '{1}' category", text.Count(), category));
    }
}

最后,我使用以下类建立服务主机:

public class ConsoleServiceHost : IDisposable
{
    protected ServiceHost _host;

    public ConsoleServiceHost()
    {
        _host = new ServiceHost(typeof(ConsoleNetworkInterface), new Uri[] { new Uri("net.pipe://localhost") });
        _host.AddServiceEndpoint(typeof(IConsoleInterface), new NetNamedPipeBinding(), "FrbConsolePipe");

        _host.Open();
    }

    public void Dispose()
    {
        _host.Close();
    }
}

并在我的客户端上使用以下代码建立连接:

    protected Callbacks _callbacks;
    protected IConsoleInterface _proxy;

    protected void ConnectToConsoleServer()
    {
        _callbacks = new Callbacks();
        var factory = new DuplexChannelFactory<IConsoleInterface>(_callbacks,
            new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/FrbConsolePipe"));
        _proxy = factory.CreateChannel();
        _proxy.ProcessInput("Connected");
    }

所以会发生什么事情,我的ConnectToConsoleServer()被调用,然后它一直到_proxy.ProcessInput("Connected");。在我的游戏中(在服务器上),我立即看到ProcessInput通话导致的输出,但客户端仍然在_proxy.ProcessInput()通话中停滞。

一分钟后,我的客户端在出现MessageBox消息的同时获得JIT TimeoutException

所以显然不仅我的命令被立即发送,我的回调被正确调用。那么为什么我会收到超时异常?

注意:即使删除MessageBox调用,我仍然遇到此问题,因此不存在阻止回调响应的GUI问题。

2 个答案:

答案 0 :(得分:4)

您需要为实现Callback接口的客户端类指定CallbackBehavior [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,UseSynchronizationContext = false)]

有关更好的说明,请参阅以下内容 http://www.switchonthecode.com/tutorials/wcf-callbacks-hanging-wpf-applications

答案 1 :(得分:2)

可能是你的_proxy.ProcessInput("Connected")正在阻止呼叫 - 这与你的超时体验一致,因为服务器立即发送响应,但客户端无法接收它,因为它停留在“ProcessInput”上。当您的呼叫最终超时时,阻塞呼叫将终止,此时回叫将完成。

要验证这一点,您可以尝试使用此(非阻塞)调用来调用吗?

((Action)(() => _proxy.ProcessInput("Connected"))).BeginInvoke(null, null);