1

私は1つのexeを持っています。このexeで。私はサービスを開始し、それをserviceManagerと呼び、次に別のサービスを開始し、それをserviceChildと呼びます。

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

最後に、テスト:

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

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

1 に答える 1

4

私は、WCF ソリューションを次のように構成するのが好きです。

コントラクト(クラス ライブラリ)
すべてのサービス、操作、フォールト、およびデータ コントラクトが含まれています。純粋な .NET-to-.NET シナリオでサーバーとクライアント間で共有可能

サービスの実装(クラス ライブラリ)
サービスを実装するためのコードと、これを実現するために必要なサポート/ヘルパー メソッドが含まれています。他には何もありません。

サービス ホスト (オプション - Winforms、コンソール アプリ、NT サービス
のいずれか) デバッグ/テスト用、または場合によっては運用用のサービス ホストが含まれます。

これにより、基本的にサーバー側のことがわかります。

クライアント側:

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

1 ~ n 個の実際のクライアント(任意の種類のアプリ)
通常、クライアント プロキシ アセンブリのみを参照するか、共有されている場合はコントラクト アセンブリも参照します。これには、ASP.NET、WPF、Winforms、コンソール アプリ、その他のサービスなど、名前を付けることができます。

そのように; 私はきれいできれいなレイアウトを持っており、それを一貫して何度も使用しています。これにより、コードがよりきれいになり、保守が容易になったと本当に思います.

これは、DotNet Rocks TV での Miguel Castro のExtreme WCF スクリーン キャスト(Carl Franklin とのスクリーン キャストを強くお勧めします)に触発されました。

于 2012-05-09T06:48:41.597 に答える