【问题标题】:WCF Client freezes when calling method from Service从服务调用方法时 WCF 客户端冻结
【发布时间】:2011-06-01 18:48:22
【问题描述】:

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

话虽如此,控制台客户端运行良好。我想我在这里遗漏了一些简单的东西。感谢您提供的任何帮助。

【问题讨论】:

    标签: wcf wcf-client wcfserviceclient


    【解决方案1】:

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

    [CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]
    

    除此之外,您还可以尝试在两个合同中标记操作

    [OperationContract(IsOneWay=true)]
    

    但是两个操作都必须返回void

    最后,如果这些都不能帮助您尝试使用以下标记您的回调实现:

    [CallbackBehavior(UseSynchronizationContext=false)]
    

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

    编辑:

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

    【讨论】:

    • 感谢 Ladislav 的快速回复。我的回调已经在我的合同中有[OperationContract(IsOneWay = true)]。我尝试将[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)] 添加到我的回调实现中,但客户端仍然会冻结。然后我使用了[CallbackBehavior(UseSynchronizationContext=false)],它成功了!由于它在不同的线程中,我应该注意任何安全问题吗?
    • 我在答案中添加了描述。
    • +1。在尝试了其他一些事情之后,[CallbackBehavior(UseSynchronizationContext=false)] 也解决了我的问题。
    • 有webget操作怎么办? stackoverflow.com/questions/40377659/…
    猜你喜欢
    • 1970-01-01
    • 2014-01-12
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多