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

发布于 2024-11-10 15:53:41 字数 2958 浏览 0 评论 0原文

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

话虽如此,控制台客户端运行完美。我想我在这里缺少一些简单的东西。我感谢您能提供的任何帮助。

I have this strange problem where my client will hang when it calls a method from my WCF Service. Now the real strange thing is that this does not happen when the Client is a Console Application. It does happen when the client is a WinForm or WPF application.

I created a Client Library that a WCF Client can use to connect to the Service, seen here:

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));
        }
    }
}

Here is the code for the working WCF Console Client:

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;
            }
        }
    }
}

And here is the code for the WPF Client that freezes (see comment)

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);
            }
        }

I stepped into the code DCCClient.Proxy.DCCInitialize(); and the service executes the commands successfully, however, for some reason the client gets stuck here and does not continue executing. The client gives no exception, and the stack trace says [external code].

That being said, the Console Client runs perfectly. I think I am missing something simple here. I appreciate any help you can provide.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心病无药医 2024-11-17 15:53:42

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

[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]

您也可以尝试使用以下属性标记两个合约中的操作,

[OperationContract(IsOneWay=true)]

但两个操作都必须返回 void

最后,如果这些操作都无法帮助尝试标记您的回调实现with:

[CallbackBehavior(UseSynchronizationContext=false)]

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

编辑:

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

In case that your service call backs the client directly from DCCInitialize and both operation and callback operation are not marked as one-way your application will deadlock. Try marking your callback implementation with this attribute:

[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]

Instead of this you can also try to mark operations in both contracts with

[OperationContract(IsOneWay=true)]

But both operations must return void

For the last if neither of these helps try to mark your callback implementation with:

[CallbackBehavior(UseSynchronizationContext=false)]

but in this case your callback operation will run in another thread and it will not be able to manipulate with UI controls directly.

Edit:

WCF behaves differently when hosted in UI thread. In such scenario all request are processed in sequential order in standard windows message loop so if you call the service you blocked your current thread but the service calls back your client and it waits to process the message but it can't because thread is blocked by the initial call = deadlock until initial request timenouts. By using last mentioned behavior you will say WCF to not join windows message loop and instead process messages in separate threads as usual. There is no security issue with this except the fact that you cannot access UI control from methods running in other threads - both WinForms and WPF has approaches to pass commands from other thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文