17

I have a windows service and a GUI that need to communicate with each other. Either can send messages at any time.

I'm looking at using NamedPipes, but it seems that you cant read & write to the stream at the same time (or at least I cant find any examples that cover this case).

Is it possible to do this kind of two-way communication via a single NamedPipe? Or do I need to open two pipes (one from GUI->service and one from service->GUI)?

steve cook
  • 3,116
  • 3
  • 30
  • 51
  • 2
    You could use WCF Duplex NamedPipes, I use this method for my Service/App communications, There is a nice example here that may help.http://tech.pro/tutorial/855/wcf-tutorial-basic-interprocess-communication – sa_ddam213 May 08 '13 at 04:51

3 Answers3

27

Using WCF you can use duplex named pipes

// Create a contract that can be used as a callback
public interface IMyCallbackService
{
    [OperationContract(IsOneWay = true)]
    void NotifyClient();
}

// Define your service contract and specify the callback contract
[ServiceContract(CallbackContract = typeof(IMyCallbackService))]
public interface ISimpleService
{
    [OperationContract]
    string ProcessData();
}

Implement the Service

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class SimpleService : ISimpleService
{
    public string ProcessData()
    {
        // Get a handle to the call back channel
        var callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();

        callback.NotifyClient();
        return DateTime.Now.ToString();
    }
}

Host the Service

class Server
{
    static void Main(string[] args)
    {
        // Create a service host with an named pipe endpoint
        using (var host = new ServiceHost(typeof(SimpleService), new Uri("net.pipe://localhost")))
        {
            host.AddServiceEndpoint(typeof(ISimpleService), new NetNamedPipeBinding(), "SimpleService");
            host.Open();

            Console.WriteLine("Simple Service Running...");
            Console.ReadLine();

            host.Close();
        }
    }
}

Create the client application, in this example the Client class implements the call back contract.

class Client : IMyCallbackService
{
    static void Main(string[] args)
    {
        new Client().Run();
    }

    public void Run()
    {
        // Consume the service
        var factory = new DuplexChannelFactory<ISimpleService>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/SimpleService"));
        var proxy = factory.CreateChannel();

        Console.WriteLine(proxy.ProcessData());
    }

    public void NotifyClient()
    {
        Console.WriteLine("Notification from Server");
    }
}
Rohan West
  • 9,262
  • 3
  • 37
  • 64
  • Thanks for the detailed response. I've gone with this method, as it seems simpler than using 2 named pipes. – steve cook May 08 '13 at 08:59
  • Any ideas I can get the windows service running fine but cannot find the service when trying to add service reference I get 'net.pipe://localhost/service1'. There was an error reading from the pipe: The pipe has been ended. (109, 0x6d). – Lawrence Thurman Jul 29 '14 at 00:51
3

Your named pipe stream classes (server or client) have to be constructed with a PipeDirection of InOut. You need one NamedPipeServerStream, probably in your service, which can be shared by an arbitrary number of NamedPipeClientStream objects. Construct the NamedPipeServerStream with the name of the pipe and the direction, and the NamedPipeClientStream with the name of the pipe, the name of the server, and the PipeDirection, and you should be good to go.

Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
Ben Brammer
  • 988
  • 4
  • 11
3

Using a single point to accumulate messages (a single pipe in this case) forces you to handle direction of the message yourself too (in addition to that you have to use a system-wide lock for the pipe).

So use 2 pipes with opposite directions.

(Another option would be using 2 MSMQ queues).

Kaveh Shahbazian
  • 13,088
  • 13
  • 80
  • 139