我遇到这个奇怪的问题,我的客户端在从我的WCF服务调用方法时会挂起。现在真正奇怪的是,当客户端是控制台应用程序时,这不会发生。当客户端是WinForm或WPF应用程序时,它确实发生。
我创建了一个客户端库,WCF客户端可以使用它连接到服务,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel; //needed for WCF communication
namespace DCC_Client
{
public class DCCClient
{
private DuplexChannelFactory<ServiceReference1.IDCCService> dualFactory;
public ServiceReference1.IDCCService Proxy;
public DCCClient()
{
//Setup the duplex channel to the service...
NetNamedPipeBinding binding = new NetNamedPipeBinding();
dualFactory = new DuplexChannelFactory<ServiceReference1.IDCCService>(new Callbacks(), binding, new EndpointAddress("net.pipe://localhost/DCCService"));
}
public void Open()
{
Proxy = dualFactory.CreateChannel();
}
public void Close()
{
dualFactory.Close();
}
}
public class Callbacks : ServiceReference1.IDCCServiceCallback
{
void ServiceReference1.IDCCServiceCallback.OnCallback(string id, string message, Guid key)
{
Console.WriteLine(string.Format("{0}: {1}", id, message));
}
}
}
以下是正常工作 WCF控制台客户端的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DCC_Client;
namespace Client_Console_Test
{
class Program
{
private static DCCClient DCCClient;
static void Main(string[] args)
{
try
{
DCCClient = new DCCClient();
DCCClient.Open();
DCCClient.Proxy.DCCInitialize(); //returns fine from here
Console.ReadLine();
DCCClient.Proxy.DCCUninitialize();
DCCClient.Close();
}
catch (Exception e)
{
throw;
}
}
}
}
以下是冻结的WPF客户端代码(请参阅评论)
using System; //etc
using DCC_Client; //Used for connection to DCC Service
namespace Client_WPF_Test
{
public partial class Main : Window
{
private static DCCClient DCCClient;
public Main()
{
InitializeComponent();
DCCClient = new DCCClient();
DCCClient.Open();
}
private void Connect_btn_event() {
try
{
DCCClient.Proxy.DCCInitialize(); //**never returns from this**
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
我进入代码DCCClient.Proxy.DCCInitialize();
并且服务成功执行命令,但是,由于某种原因,客户端卡在这里并且不继续执行。客户端没有异常,堆栈跟踪显示[外部代码]。
话虽如此,控制台客户端运行完美。我想我在这里缺少一些简单的东西。感谢您提供的任何帮助。
答案 0 :(得分:13)
如果您的服务直接从DCCInitialize
回调客户端,并且操作和回调操作都没有标记为单向,那么您的应用程序将会死锁。尝试使用以下属性标记回调实现:
[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]
除此之外,您还可以尝试使用
标记两个合同中的操作[OperationContract(IsOneWay=true)]
但两个操作都必须返回void
对于最后一个,如果这些都没有帮助尝试使用以下标记回调实现:
[CallbackBehavior(UseSynchronizationContext=false)]
但在这种情况下,您的回调操作将在另一个线程中运行,并且无法直接使用UI控件进行操作。
编辑:
在UI线程中托管时,WCF的行为有所不同。在这种情况下,所有请求都在标准的Windows消息循环中按顺序处理,所以如果你调用服务,你阻止了当前的线程,但服务回调你的客户端,它等待处理消息,但它不能,因为线程被阻止初始调用=死锁直到初始请求timenouts。通过使用上次提到的行为,您将说WCF不加入Windows消息循环,而是像往常一样在单独的线程中处理消息。除了无法从其他线程中运行的方法访问UI控件这一事实外,没有任何安全问题 - WinForms和WPF都有从其他线程传递命令的方法。