我正在玩游戏控制台连接到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问题。
答案 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);