Cómo matar una operación APM pendiente

Si tiene una operación pendiente, p. Ej.

stream.BeginRead(_buffer, 0, _buffer.Length, _asyncCallbackRead, this);

y cierra el proveedor de transmisión, por ejemplo

serialPort.Close();

Como era de esperar, causa una excepción.

¿Existe un método preferido por el cual uno podría cancelar una operación APM pendiente, antes de cerrar el puerto?

La respuesta de Colby no es la respuesta que esperaba, pero al menos cierra una infructuosa vía de investigación.

Felizmente he encontrado una solución.

Para cada transmisión, mantengo diversa información de estado en una claseDeviceSession. Esta clase tiene un método.ReadStream proporcionando la implementación para elAsyncCallback que maneja los datos entrantes.

Tenga en cuenta que_asyncCallbackRead y cualquier otra variable que comience con un guión bajo es un miembro privado de clase asignado en el constructor de DeviceSession.

El constructor también proporciona la llamada inicial a_stream.BeginRead.

void ReadStream(IAsyncResult ar)
{
  if (IsOpen) 
    try
    {
      DevicePacket packet;
      int cbRead = _stream.EndRead(ar);
      _endOfValidData += cbRead;
      while ((packet = GetPacket()) != null)
        CommandStrategy.Process(this, packet);
      _stream.BeginRead(_buffer, _endOfValidData, 
        _buffer.Length - _endOfValidData, 
        _asyncCallbackRead, null);
    }
    catch (Exception ex)
    {
      Trace.TraceError("{0}\r\n{1}", ex.Message, ex.StackTrace);
      _restart(_streamProvider, _deviceId);
    }
}

Tenga en cuenta que no me he molestado en configurarar.AsyncState. Debido a que el delegado de devolución de llamada hace referencia al método de una instancia específica de DeviceSession, la información de contexto detallada y fuertemente tipada (contenida en los miembros de esta instancia de DeviceSession) esautomáticamente en alcance. Este es el punto de tener un objeto de sesión.

Volviendo al tema de abortar un escucha, cerrar el proveedor de flujo desencadena la devolución de llamada pero al intentar invocar EndRead resulta en unIOException.

En general, dicha excepción indica una falla que requiere un reinicio del escucha y uno querrá responder reiniciando el proveedor de flujo y recreando la sesión. Esto se complica por la ausencia de una forma confiable independiente del proveedor de flujo para determinar si el proveedor ha fallado o si el usuario está tratando de reiniciar la conexión (por ejemplo, conectó un nuevo dispositivo en el puerto).

El truco es agregar más contexto (IsOpen) alDeviceSession para indicar si la sesión está abierta o se ha cerrado, y úsela para completar sin problemas la ejecución abortiva final deReadStream.

SiIsOpen estrue entonces unIOException representa una falla en la necesidad de recuperación. SiIsOpen esfalse la falla fue inducida deliberadamente y no se requiere ninguna acción.

Respuestas a la pregunta(2)

Su respuesta a la pregunta