WCF客户端在从服务调用方法时冻结



我遇到了一个奇怪的问题,当我的客户端从我的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();,服务成功地执行了命令,但是,由于某种原因,客户端被困在这里,无法继续执行。客户端没有异常,堆栈跟踪显示[外部代码]。

也就是说,控制台客户端运行完美。我想我错过了一些简单的东西。我感谢你能提供的任何帮助。

如果您的服务直接从DCCInitialize调用客户端,并且操作和回调操作都没有标记为单向,那么您的应用程序将死锁。尝试使用以下属性标记回调实现:

[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]

相反,你也可以尝试在的两份合同中标记操作

[OperationContract(IsOneWay=true)]

但两个操作都必须返回void

最后,如果这两者都没有帮助,请尝试用标记回调实现

[CallbackBehavior(UseSynchronizationContext=false)]

但在这种情况下,回调操作将在另一个线程中运行,并且无法直接使用UI控件进行操作。

编辑:

WCF在UI线程中托管时表现不同。在这种情况下,所有请求都会在标准的windows消息循环中按顺序处理,因此,如果您调用服务,您会阻止当前线程,但该服务会回调您的客户端,并等待处理消息,但它无法处理,因为线程被初始调用阻塞=死锁,直到初始请求超时。通过使用最后提到的行为,您将说WCF不加入windows消息循环,而是像往常一样在单独的线程中处理消息。除了不能从其他线程中运行的方法访问UI控件之外,这没有任何安全问题——WinForms和WPF都有从其他线程传递命令的方法。

最新更新