title: How to correctly use .NET2.0 serial port .BaseStream for async operation
body: <p>I am attempting to use the .BaseStream property of the .NET2.0 SerialPort to do asynchronous reads and writes (BeginWrite/EndWrite, BeginRead/EndRead).</p>
  
  <p>I am having some success in this, but after a time, I notice (using Process Explorer) a very gradual increase in the Handles the app is using, and occasionally an extra thread, which also increases the Handle count.</p>
  
  <p>The context switch rate also increases each time a new thread appears.</p>
  
  <p>The app constantly sends 3 bytes to a PLC device, and gets 800 or so bytes in return, and does so at a baud rate of 57600.</p>
  
  <p>The initial CSwitch Delta (again, from Process Explorer) is around 2500, which seems very high anyway. Each time a new thread appears, this value increases, and the CPU load increases accordingly.</p>
  
  <p>I'm hoping that somebody might have done something similar, and can help me out, or even say 'In God's name, don't do it that way.'</p>
  
  <p>In the code below, 'this._stream' is obtained from SerialPort.BaseStream, and CommsResponse is a class I use as the IAsyncresult state object.</p>
  
  <p>This code is common to a TCP connection I make as an alternative to using the serial port, (I have a CommsChannel base class, with a serial and TCP channel derived from it) and it has none of these problems so I'm reasonably hopeful that there is nothing wrong with the CommsResponse class.</p>
  
  <p>Any comments gratefully received.</p>
  
  <pre><code>    /// &lt;summary&gt;
      /// Write byte data to the channel.
      /// &lt;/summary&gt;
      /// &lt;param name="bytes"&gt;The byte array to write.&lt;/param&gt;
      private void Write(byte[] bytes)
      {
          try
          {
              // Write the data to the port asynchronously.
              this._stream.BeginWrite(bytes, 0, bytes.Length, new AsyncCallback(this.WriteCallback), null);
          }
          catch (IOException ex)
          {
              // Do stuff.
          }
          catch (ObjectDisposedException ex)
          {
              // Do stuff.
          }
      }
  
      /// &lt;summary&gt;
      /// Asynchronous write callback operation.
      /// &lt;/summary&gt;
      private void WriteCallback(IAsyncResult ar)
      {
          bool writeSuccess = false;
  
          try
          {
              this._stream.EndWrite(ar);
              writeSuccess = true;
          }
          catch (IOException ex)
          {
              // Do stuff.
          }
  
          // If the write operation completed sucessfully, start the read process.
          if (writeSuccess) { this.Read(); }
      }
  
      /// &lt;summary&gt;
      /// Read byte data from the channel.
      /// &lt;/summary&gt;
      private void Read()
      {
          try
          {
              // Create new comms response state object.
              CommsResponse response = new CommsResponse();
  
              // Begin the asynchronous read process to get response.
              this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length, new AsyncCallback(this.ReadCallback), response);
          }
          catch (IOException ex)
          {
              // Do stuff.
          }
          catch (ObjectDisposedException ex)
          {
              // Do stuff.
          }
      }
  
      /// &lt;summary&gt;
      /// Asynchronous read callback operation.
      /// &lt;/summary&gt;
      private void ReadCallback(IAsyncResult ar)
      {
          // Retrieve the comms response object.
          CommsResponse response = (CommsResponse)ar.AsyncState;
  
          try
          {
              // Call EndRead to complete call made by BeginRead.
              // At this point, new data will be in this._readbuffer.
              int numBytesRead = this._stream.EndRead(ar);
  
              if (numBytesRead &gt; 0)
              {
                  // Create byte array to hold newly received bytes.
                  byte[] rcvdBytes = new byte[numBytesRead];
  
                  // Copy received bytes from read buffer to temp byte array
                  Buffer.BlockCopy(this._readBuffer, 0, rcvdBytes, 0, numBytesRead);
  
                  // Append received bytes to the response data byte list.
                  response.AppendBytes(rcvdBytes);
  
                  // Check received bytes for a correct response.
                  CheckResult result = response.CheckBytes();
  
                  switch (result)
                  {
                      case CheckResult.Incomplete: // Correct response not yet received.
                          if (!this._cancelComm)
                          {
                              this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length,
                                  new AsyncCallback(this.ReadCallback), response);
                          }
                          break;
  
                      case CheckResult.Correct:  // Raise event if complete response received.
                          this.OnCommResponseEvent(response);
                          break;
  
                      case CheckResult.Invalid: // Incorrect response
                          // Do stuff.
                          break;
  
                      default: // Unknown response
                          // Do stuff.
                          break;
                  }
              }
              else
              {
                  // Do stuff.
              }
          }
          catch (IOException ex)
          {
              // Do stuff.
          }
          catch (ObjectDisposedException ex)
          {
              // Do stuff.
          }
      }
  </code></pre>