Search code examples
c#.netcode-analysisfxcop

CA2202, how to solve this case


Can anybody tell me how to remove all CA2202 warnings from the following code?

public static byte[] Encrypt(string data, byte[] key, byte[] iv)
{
    using(MemoryStream memoryStream = new MemoryStream())
    {
        using (DESCryptoServiceProvider cryptograph = new DESCryptoServiceProvider())
        {
            using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write))
            {
                using(StreamWriter streamWriter = new StreamWriter(cryptoStream))
                {
                    streamWriter.Write(data);
                }
            }
        }
        return memoryStream.ToArray();
    }
}

Warning 7 CA2202 : Microsoft.Usage : Object 'cryptoStream' can be disposed more than once in method 'CryptoServices.Encrypt(string, byte[], byte[])'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 34

Warning 8 CA2202 : Microsoft.Usage : Object 'memoryStream' can be disposed more than once in method 'CryptoServices.Encrypt(string, byte[], byte[])'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 34, 37

You need Visual Studio Code Analysis to see these warnings (these are not c# compiler warnings).


Solution

  • This compiles without warning:

        public static byte[] Encrypt(string data, byte[] key, byte[] iv)
        {
            MemoryStream memoryStream = null;
            DESCryptoServiceProvider cryptograph = null;
            CryptoStream cryptoStream = null;
            StreamWriter streamWriter = null;
            try
            {
                memoryStream = new MemoryStream();
                cryptograph = new DESCryptoServiceProvider();
                cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write);
                var result = memoryStream;              
                memoryStream = null;
                streamWriter = new StreamWriter(cryptoStream);
                cryptoStream = null;
                streamWriter.Write(data);
                return result.ToArray();
            }
            finally
            {
                if (memoryStream != null)
                    memoryStream.Dispose();
                if (cryptograph != null)
                    cryptograph.Dispose();
                if (cryptoStream != null)
                    cryptoStream.Dispose();
                if (streamWriter != null)
                    streamWriter.Dispose();
            }
        }
    

    Edit in response to the comments: I just verified again that this code does not generate the warning, while the original one does. In the original code, CryptoStream.Dispose() and MemoryStream().Dispose() are actually called twice (which may or may not be a problem).

    The modified code works as follows: references are set to null, as soon as responsibilty for disposing is transferred to another object. E.g. memoryStream is set to null after the call to CryptoStream constructor succeeded. cryptoStream is set to null, after the call to StreamWriter constructor succeeded. If no exception occurs, streamWriter is disposed in the finally block and will in turn dispose CryptoStream and MemoryStream.