My named pipe works fine after first connection but later I get System.ObjectDisposedException: Cannot access a closed pipe

171 Views Asked by At

For bidirectional data exchange between my C# applications I use named pipe. App-1 is the pipe server, App-2 is the client. When a button is clicked in App-1 the pipe_server method is executed and and App-1,as server is waiting for connection from App-2. After clicking the button for the first time, everything works as expected. App-2 connects and sends data to App-1.

After each data transfer I am disposing the pipe server.I want that for every new button click a new pipe stream is generated, and the data transfer runs from beginnng as before. But after second click of the button I always get "System.ObjectDisposedException: Cannot access a closed pipe". on the server side. I think I make something wrong when disposing the pipestream on the server side.

Server side (App-1)

    public string test = "";
    public StreamReader sr ;
    public StreamWriter sw ;
    public NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 20, 20);


    public void pipe_server  // executed on button click
    {
    CancellationTokenSource source = new CancellationTokenSource();            
    server_named_pipe(source.Token);
    }

    protected async Task server_named_pipe(CancellationToken stoppingToken)
    {
        PipeSecurity ps = new PipeSecurity();
        System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);
        PipeAccessRule par = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
        ps.AddAccessRule(par);

          sr = new StreamReader(pipeServer);
          sw = new StreamWriter(pipeServer);
        
            try
            {                 

                var asyncResult = pipeServer.BeginWaitForConnection(PipeConnected, this);

                if (asyncResult.AsyncWaitHandle.WaitOne(5000))
                {
                    pipeServer.EndWaitForConnection(asyncResult);
                    // ...
                }
               
            }

            catch (Exception ex) 
            {
                //throw ex; 
                pipeServer.WaitForPipeDrain();
                if (pipeServer.IsConnected) 
                { 
                pipeServer.Disconnect(); 
                }
            }
            finally 
            {
                if (sw != null) sw.Dispose();
                if (sr != null) sr.Dispose();
                pipeServer.Dispose();
            }               
        } 
    }


    public void PipeConnected(IAsyncResult e)
    {
        sw.WriteLine("Waiting");
        sw.Flush();
        pipeServer.WaitForPipeDrain();
        test = sr.ReadLine();
        using (StreamWriter sw2 = File.AppendText(CommonClass.error_path))
        {
            sw2.WriteLine("Named_Pipe_message: " + "  " + test + Convert.ToString(DateTime.Now) + "   ");

        }            
    }
1

There are 1 best solutions below

2
Guru Stron On BEST ANSWER

After each data transfer I am disposing the pipe server.

Than you should recreate the server. You can't (usually) use disposed resources. You need to recreate the NamedPipeServerStream after disposal (as you do with StreamReader/StreamWriter). For example:

public NamedPipeServerStream pipeServer;

protected async Task server_named_pipe(CancellationToken stoppingToken)
{
    pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 20, 20);
    sr = new StreamReader(pipeServer);
    sw = new StreamWriter(pipeServer);
    // ...
}

Personally you would remove the pipeServer, sr and sr fields and moved all the handling inside the server_named_pipe method.