[WCF]两个服务在同一个进程中

时间:2012-05-09 04:26:14

标签: c# .net wcf named-pipes

我有一个exe。 在这个exe中。 我启动一项服务,称之为serviceManager 然后,启动另一个服务,将其命名为serviceChild。

当我使用serviceChild创建一个带有serviceManager的通道时, 调用serviceManager的回调。 它会freez。

所有服务绑定都是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();
    }

1 个答案:

答案 0 :(得分:4)

我喜欢这样构建我的WCF解决方案:

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

服务实施(类库)
包含实现服务的代码,以及实现此目的所需的任何支持/帮助程序方法。没别了。

服务主机(可选 - 可以是Winforms,Console App,NT Service)
包含用于调试/测试的服务主机,或者也可能用于生产。

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

在客户端:

客户端代理(类库)
我喜欢将我的客户端代理打包到一个单独的类库中,以便它们可以被多个实际的客户端应用程序重用。这可以使用svcutil或&#34;添加服务参考&#34;并手动调整生成的可怕app.config,或者使用ClientBase<T>ChannelFactory<T>构造手动实现客户端代理(共享契约程序集时)。

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

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

这是受到Miguel Castro的Extreme WCF screen cast在DotNet Rocks电视上与Carl Franklin的启发 - 强烈推荐的屏幕演员!