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 解决方案:

Contracts(类库)
包含所有服务、操作、故障和数据合同。可以在纯 .NET-to-.NET 场景中的服务器和客户端之间共享

服务实现(类库)
包含实现服务的代码,以及实现此功能所需的任何支持/帮助方法。没有其他的。

服务主机(可选 - 可以是 Winforms、控制台应用程序、NT 服务)
包含用于调试/测试或可能还用于生产的服务主机。

这基本上给了我服务器端的东西。

在客户端:

客户端代理(类库)
我喜欢将我的客户端代理打包到一个单独的类库中,以便它们可以被多个实际客户端应用程序重用。这可以使用 svcutil 或“添加服务引用”并手动调整生成的可怕的 app.config 来完成,或者通过使用ClientBase<T>ChannelFactory<T>构造手动实现客户端代理(当共享合同程序集时)。

1-n 个实际客户端(任何类型的应用程序)
通常只会引用客户端代理程序集,或者如果正在共享,也可能引用合约程序集。这可以是 ASP.NET、WPF、Winforms、控制台应用程序、其他服务 - 你可以命名它。

那样; 我有一个漂亮而干净的布局,我一遍又一遍地使用它,我真的认为这让我的代码更干净,更容易维护。

这是由 Miguel Castro 与 Carl Franklin 在 DotNet Rocks TV 上的Extreme WCF 屏幕投射的启发- 强烈推荐的屏幕投射!

于 2012-05-09T06:48:41.597 回答