c# stream objectdisposedexception

c# - ¿Puede un CryptoStream dejar la base abierta?



objectdisposedexception (5)

Creo un MemoryStream , lo paso a CryptoStream para escribir. Quiero que CryptoStream , y deje el MemoryStream abierto para que luego lo lea en otra cosa. Pero tan pronto como se CryptoStream , también se elimina el MemoryStream .

¿Puede CryptoStream dejar abierto el MemoryStream base de alguna manera?

using (MemoryStream scratch = new MemoryStream()) { using (AesManaged aes = new AesManaged()) { // <snip> // Set some aes parameters, including Key, IV, etc. // </snip> ICryptoTransform encryptor = aes.CreateEncryptor(); using (CryptoStream myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write)) { myCryptoStream.Write(someByteArray, 0, someByteArray.Length); } } // Here, I''m still within the MemoryStream block, so I expect // MemoryStream to still be usable. scratch.Position = 0; // Throws ObjectDisposedException byte[] scratchBytes = new byte[scratch.Length]; scratch.Read(scratchBytes,0,scratchBytes.Length); return Convert.ToBase64String(scratchBytes); }


A partir de .NET 4.7.2, hay un segundo constructor con un parámetro bool agregado llamado leaveOpen . Si se establece en verdadero, el método de disposición de CryptoStream no llamará a disposición en la secuencia subyacente.

Además, el otro constructor sin el parámetro leaveOpen simplemente reenvía los parámetros al nuevo constructor con leaveOpen configurado en false .

MSDN
CryptoStream.Dispose(bool disposing)


Como segunda solución, puede crear un objeto WrapperStream que simplemente pase todas las llamadas a lo largo, excepto Dispose / Close. Haga un envoltorio alrededor de su flujo de memoria, entregue el envoltorio al flujo criptográfico, y ahora, al cerrar el flujo criptográfico no toque el flujo de memoria.


Mi solución simple:

class NotClosingCryptoStream : CryptoStream { public NotClosingCryptoStream( Stream stream, ICryptoTransform transform, CryptoStreamMode mode ) : base( stream, transform, mode ) { } protected override void Dispose( bool disposing ) { if( !HasFlushedFinalBlock ) FlushFinalBlock(); base.Dispose( false ); } }


Puede, pero no podrá utilizar declaraciones utilizando. Deberá administrar manualmente la eliminación del objeto y también deberá llamar a FlushFinialBlock() para asegurarse de que todos los datos se escribieron en la secuencia subyacente antes de trabajar en él.

Una vez que haya terminado de trabajar con la transmisión, puede disponer de todos los recursos que estaba esperando en el bloque final al final.

MemoryStream scratch = null; AesManaged aes = null; CryptoStream myCryptoStream = null; try { scratch = new MemoryStream(); aes = new AesManaged(); // <snip> // Set some aes parameters, including Key, IV, etc. // </snip> ICryptoTransform encryptor = aes.CreateEncryptor(); myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write); myCryptoStream.Write(someByteArray, 0, someByteArray.Length); //Flush the data out so it is fully written to the underlying stream. myCryptoStream.FlushFinalBlock(); scratch.Position = 0; byte[] scratchBytes = new byte[scratch.Length]; scratch.Read(scratchBytes,0,scratchBytes.Length); return Convert.ToBase64String(scratchBytes); } finally { //Dispose all of the disposeable objects we created in reverse order. if(myCryptoStream != null) myCryptoStream.Dispose(); if(aes != null) aes.Dispose(); if(scratch != null) scratch.Dispose(); }


Resulta que no hay necesidad de separar el bloque de uso {} en try {} finalmente {} ... En última instancia, solo tienes que usar FlushFinalBlock () dentro de la declaración de uso, y anidar cualquier otra cosa dentro como necesario.

using (MemoryStream scratch = new MemoryStream()) { using (AesManaged aes = new AesManaged()) { // <snip> // Set some aes parameters, including Key, IV, etc. // </snip> ICryptoTransform encryptor = aes.CreateEncryptor(); using (CryptoStream myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write)) { myCryptoStream.Write(someByteArray, 0, someByteArray.Length); myCryptoStream.FlushFinalBlock(); scratch.Flush(); // not sure if this is necessary byte[] scratchBytes = scratch.ToArray(); return Convert.ToBase64String(scratchBytes); } } }