3

この奇妙な問題があり、クライアントが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();と、サービスはコマンドを正常に実行しますが、何らかの理由でクライアントがここでスタックし、実行を続行しません。クライアントは例外を与えず、スタックトレースは[外部コード]を示します。

そうは言っても、コンソールクライアントは完全に実行されます。私はここで簡単な何かが欠けていると思います。私はあなたが提供できるどんな助けにも感謝します。

4

1 に答える 1

15

サービスがクライアントから直接コールバックし、DCCInitialize操作とコールバック操作の両方が一方向としてマークされていない場合、アプリケーションはデッドロックします。この属性でコールバック実装をマークしてみてください:

[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]

これの代わりに、両方の契約で操作をマークすることもできます

[OperationContract(IsOneWay=true)]

ただし、両方の操作を返す必要がありますvoid

最後に、これらのどちらもコールバックの実装を次のようにマークするのに役立たない場合:

[CallbackBehavior(UseSynchronizationContext=false)]

ただし、この場合、コールバック操作は別のスレッドで実行され、UIコントロールで直接操作することはできません。

編集:

UIスレッドでホストされている場合、WCFの動作は異なります。このようなシナリオでは、すべてのリクエストが標準のWindowsメッセージループで順番に処理されるため、サービスを呼び出すと、現在のスレッドをブロックしましたが、サービスはクライアントをコールバックし、メッセージの処理を待機しますが、スレッドがによってブロックされているため、処理できません。最初の呼び出し=最初の要求がタイムアウトするまでデッドロック。最後に述べた動作を使用することにより、WCFはWindowsメッセージループに参加せず、代わりに通常どおり別々のスレッドでメッセージを処理するように指示します。他のスレッドで実行されているメソッドからUIコントロールにアクセスできないという事実を除いて、これにはセキュリティ上の問題はありません。WinFormsとWPFの両方に、他のスレッドからコマンドを渡すアプローチがあります。

于 2011-06-01T18:59:19.943 に答える