2012-05-09 17 views
1

私は1つのexeを持っています。このexeの 私はサービスを開始し、それをserviceManager と呼んで、別のサービスを開始します。それをserviceChildと呼んでください。[WCF]同じプロセスで2つのサービス

serviceChildを使用してserviceManagerでチャネルを作成すると、 がserviceManagerのコールバックを呼び出します。 それはフリーズします。

すべてのサービスバインドは、netnamedpipebindingです。

私は何が起こっているのか教えていただけますか?

と私のコード: インタフェース:

[ServiceContract] 
internal interface IChild 
{ 
    [OperationContract] 
    CommunicationState GetState(); 
} 

[ServiceContract] 
public interface IManager 
{ 
    [OperationContract] 
    CommunicationState GetState(); 
} 

と:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.Single)] 
public class Child : IChild 
{ 
    private readonly Guid _address = Guid.NewGuid(); 
    private readonly ServiceHost _host; 

    public Guid Address 
    { 
     get { return _address; } 
    } 

    public Child() 
    { 
     _host = new ServiceHost(this); 

     var binding = new NetNamedPipeBinding(); 
     var clientAddress = Helper.GetClientAddress(_address); 
     _host.AddServiceEndpoint((typeof(IChild)), binding, clientAddress); 

     _host.Description.Behaviors.Add(new ServiceDiscoveryBehavior()); 
     _host.AddServiceEndpoint(new UdpDiscoveryEndpoint()); 

     _host.Open(); 
    } 

    public void Open() 
    { 
     if(!Manager.IsRunning()){Manager.Start();} 

     var binding = new NetNamedPipeBinding(); 
     var endpoint = new EndpointAddress(Constants.ADDRESS_PIPE_SERVER); 
     using (var factory = new ChannelFactory<IManager>(binding, endpoint)) 
     { 
      IManager managerChannel = null; 
      try 
      { 
       managerChannel = factory.CreateChannel(); 
       **managerChannel.GetState();**// BUG:<----- 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show("ex " + ex); 
      } 
      finally 
      { 
       Helper.CloseChannel((ICommunicationObject)managerChannel); 
      } 
     } 
    } 

    public CommunicationState GetState() 
    { 
     return _host.State; 
    } 
} 

マネージャー:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.Single)] 
public class Manager : IManager 
{ 
    private static ServiceHost _host; 

    private static Manager _instance; 

    private static Manager Instance 
    { 
     get { return _instance ?? (_instance = new Manager()); } 
    } 

    #region IManager Members 

    public CommunicationState GetState() 
    { 
     return _host.State; 
    } 

    #endregion 

    public static void Start() 
    { 
     if (_host != null 
      && (_host.State == CommunicationState.Created 
       || _host.State == CommunicationState.Opening 
       || _host.State == CommunicationState.Opened)) 
     { 
      return; 
     } 


     _host = new ServiceHost(Instance); 

     var binding = new NetNamedPipeBinding(); 
     var endpoint = Constants.ADDRESS_PIPE_SERVER; 
     _host.AddServiceEndpoint((typeof (IManager)), binding, endpoint); 
     _host.Open(); 
    } 

    public static bool IsRunning() 
    { 
     var binding = new NetNamedPipeBinding(); 
     var endpointAddress = new EndpointAddress(Constants.ADDRESS_PIPE_SERVER); 
     var factory = new ChannelFactory<IManager>(binding, endpointAddress); 
     IManager managerChannel = null; 
     try 
     { 
      managerChannel = factory.CreateChannel(); 
      // wait for server to respond 
      if (_host != null && _host.State == CommunicationState.Opened) 
      { 
       var contextChannel = managerChannel as IClientChannel; 
       if (contextChannel != null) contextChannel.OperationTimeout = TimeSpan.FromMilliseconds(1000); 
      } 
      try 
      { 
       managerChannel.GetState(); 
      } 
      catch (Exception) 
      { 
       return false; 
      } 
      return true; 
     } 
     catch (EndpointNotFoundException e) 
     { 
      return false; 
     } 
     finally 
     { 
      Helper.CloseChannel((ICommunicationObject) managerChannel); 
     } 
    } 

その他:

internal static class Helper 
{ 
    public static void CloseChannel(ICommunicationObject channel) 
    { 
     try 
     { 
      if (channel.State == CommunicationState.Opened) channel.Close(); 
     } 
     catch (Exception ex) 
     { 
      Debug.WriteLine(ex); 
     } 
     finally 
     { 
      channel.Abort(); 
     } 
    } 

    public static string GetClientAddress(object serviceAddress) 
    { 
     return string.Format(Constants.ADDRESS_PIPE_CLIENT_FORMAT, serviceAddress); 
    } 
} 


internal static class Constants 
{ 
    internal static string ADDRESS_PIPE_SERVER = @"net.pipe://localhost/Server"; 
    internal static string ADDRESS_PIPE_CLIENT_FORMAT = @"net.pipe://localhost/Client_{0}"; 
} 
最後の10

、テスト:私はこのように私のWCFソリューションを構築したいと

private void ActionLoaded(object sender, RoutedEventArgs e) 
    { 
     Manager.Start(); 
    } 

    private void ActionConnectedSelf(object sender, RoutedEventArgs e) 
    { 
     var client = new Child(); 
     client.Open(); 
    } 
+1

**いくつかのコードを表示できますか?**例えば。あなたのサービス契約、サービスの実装、関連cofing等 –

+0

はい、私の質問を更新します。 – GeminiYellow

+0

私はあなたがWCFサービスを完全に誤解していると思います。**サービスの実装クラス(例えば 'Child')内に' ServiceHost'を作成して開くべきではありません** 。サービスホストは着信要求を処理し、それらの要求を処理するサービスクラスをインスタンス化します。 –

答えて

4

契約(クラスライブラリ)
は、すべてのサービス、オペレーション、障害、およびデータが含まれています契約。

サービス実装(クラスライブラリ)の純粋な.NETツー.NETシナリオでは、サーバとクライアントの間で共有することができ
サービスを実装するためのコード、およびこれを達成するために必要な任意のサポート/ヘルパーメソッドが含まれています。他に何もない。

サービスホスト(複数可)(オプション - Winformsの、コンソールアプリケーション、NTサービスすることができます)
は、生産のための可能性、サービスのデバッグ/テスト用のホスト(複数可)、またはが含まれています。

これは基本的に私に物事のサーバー側を与えます。クライアント側では

クライアントプロキシ(クラスライブラリ)
私は、彼らは、複数の実際のクライアントアプリケーションで再利用できるように、別のクラスライブラリに私のクライアントプロキシをパッケージ化したいです。これは、svcutilまたは「サービスリファレンスの追加」を使用して、恐ろしいapp.configの結果を手動で調整するか、ClientBase<T>またはChannelFactory<T>構造を使用してクライアントプロキシを手動で実装することによって(契約アセンブリを共有する場合)行うことができます。

1-nは、実際それが共有されていた場合、クライアント(アプリのいずれかのタイプ)
は、典型的に、あまりにも、クライアントプロキシのアセンブリを参照するか、あるいは契約アセンブリます。これは、ASP.NET、WPF、Winforms、コンソールアプリケーション、その他のサービスにすることができます - 名前を付けます。

そうです。私は素敵できれいなレイアウトを持っています。私はそれを何度も何度も繰り返し使用しています。これは私のコードをよりきれいにして維持しやすくしたと思います。

これは、Miguel CastroのExtreme WCF screen cast(DotNet Rocks TV、Carl Franklin)のインスピレーションを受けました。

+0

あなたの助けに感謝します。 私の醜い構造を残念に思っています。 私が必要なのはそれです: サーバー。 すべてのクライアントが登録されます。 n個のクライアント。 サーバーで割り当てタイプを検索できます。 ----------------- クライアントが検索を要求すると、サーバーが起動していない可能性があります。この場合は 、サーバーを起動して、実行中のすべてのクライアントをサーバーが再検出できる可能性があります。他のクライアントを検索することができます。 – GeminiYellow

+1

はい。それはお勧めの方法です。 +1 –

+0

あなたの 'マネージャー:IManager'は再びWCFサービスです - それは自分自身の内部に別のサービスをホストしてはいけません!それは**健全なデザインではありません! 'ServiceHost'クラスとWCFサービス実装クラスを厳密に分離しておく必要があります。 –