Rex
Rex

Reputation: 1144

How do I fix the CA2202 warning?

Below is a method that I use to parse an XML. It is giving the CA2202 warning on code analysis which says that the object mStream can be disposed multiple times and I should not call dispose more than once. How can I solve this warning?

public static String PrintXML(String XML)
    {
        String result = "";
        string[] xmlSeperators = new string[] { "<?" };
        string[] splitResults = new string[2];

        if (!String.IsNullOrEmpty(XML))
        {
            using (MemoryStream mStream = new MemoryStream())
            {
                using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
                {
                    XmlDocument document = new XmlDocument();
                    try
                    {
                        // Load the XmlDocument with the XML.
                        //Check if it is only XML 
                        if (XML.StartsWith("<?"))
                        {
                            document.LoadXml(XML);
                        }
                        else
                        {
                            //Split the string appended before XML
                            splitResults = XML.Split(xmlSeperators, 2, StringSplitOptions.None);
                            if (splitResults.Length > 1)
                            {
                                string d = "<?" + splitResults[1];
                                document.LoadXml(d);
                            }
                        }
                        writer.Formatting = Formatting.Indented;
                        // Write the XML into a formatting XmlTextWriter
                        document.WriteContentTo(writer);
                        //xx.WriteTo(writer);
                        writer.Flush();
                        mStream.Flush();
                        // Have to rewind the MemoryStream in order to read its contents.
                        mStream.Position = 0;
                        // Read MemoryStream contents into a StreamReader.
                        StreamReader sReader = new StreamReader(mStream);
                        // Extract the text from the StreamReader.
                        String FormattedXML = sReader.ReadToEnd();

                        if (splitResults[0] != null)
                        {
                            result = splitResults[0] + "\n" + FormattedXML;
                        }
                        else
                        {
                            result = FormattedXML;
                        }
                    }
                    catch (XmlException xe)
                    {
                        Log.Error(xe);
                        throw;
                    }                        
                }                   
            }
        }
        return result;
    }

Upvotes: 3

Views: 1642

Answers (3)

Habib
Habib

Reputation: 223187

The reason for getting this warning is that XmlTextWriter.Dispose() will ensure that the under lying MemoryStream object is also disposed. So when the using scope of the MemoryStream ends, it will try disposing the MemoryStream object and hence the warning.

using block compiles into a try-finally block. Inner using block in your code would call Dispose on your writer. That will call Dispose on your MemoryStream object mStream. At the exit of control from inner using block, the outer using block will try to dispose the object writer, but since it has already been disposed, you are getting the warning on Code analysis tool.

To get rid of the warning, you can remove the first using statement and use a try-finally block. But remember to set mStream to null as soon as you enter the second using statement. This has been explained at CA2202: Do not dispose objects multiple times

Your code would look like:

public static String PrintXML(String XML)
{
    String result = "";
    string[] xmlSeperators = new string[] { "<?" };
    string[] splitResults = new string[2];

    if (!String.IsNullOrEmpty(XML))
    {
        MemoryStream mStream  = null;
        try
        {
            mStream = new MemoryStream();
            using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
            {
                mStream = null; // important 
                XmlDocument document = new XmlDocument();
                try
                {
                    // Load the XmlDocument with the XML.
                    //Check if it is only XML 
                    if (XML.StartsWith("<?"))
                    {
                        document.LoadXml(XML);
                    }
                    else
                    {
                        //Split the string appended before XML
                        splitResults = XML.Split(xmlSeperators, 2, StringSplitOptions.None);
                        if (splitResults.Length > 1)
                        {
                            string d = "<?" + splitResults[1];
                            document.LoadXml(d);
                        }
                    }
                    writer.Formatting = System.Xml.Formatting.Indented;
                    // Write the XML into a formatting XmlTextWriter
                    document.WriteContentTo(writer);
                    //xx.WriteTo(writer);
                    writer.Flush();
                    mStream.Flush();
                    // Have to rewind the MemoryStream in order to read its contents.
                    mStream.Position = 0;
                    // Read MemoryStream contents into a StreamReader.
                    StreamReader sReader = new StreamReader(mStream);
                    // Extract the text from the StreamReader.
                    String FormattedXML = sReader.ReadToEnd();

                    if (splitResults[0] != null)
                    {
                        result = splitResults[0] + "\n" + FormattedXML;
                    }
                    else
                    {
                        result = FormattedXML;
                    }
                }
                catch (XmlException xe)
                {
                    Log.Error(xe);
                    throw;
                }
            }
        }
        finally 
        {

            if (mStream != null)
            {
                mStream.Dispose();
            }

        }
    }
    return result;
}

Upvotes: 3

Ryan M
Ryan M

Reputation: 2112

This happens when you have nested using statements where the inner statement contains the resource from the outer statement. In this case, the XmlTextWriter will dispose of the MemoryStream when it is disposed, and then the outer using statement will cause it to be disposed for a second time.

You can manually dispose the MemoryStream by replacing the outer using statement with a try/finally:

MemoryStream mStream = null;
try
{
    mStream = new MemoryStream();
    using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
    {
      mStream = null;
     ...
    }
}
finally
{
    if(mStream != null)
        mStream.Dispose();
}

(See http://msdn.microsoft.com/en-us/library/ms182334.aspx)

Upvotes: 0

Afzaal Ahmad Zeeshan
Afzaal Ahmad Zeeshan

Reputation: 15860

You can Suppress the error warning as the other answer is saying, but the actuall way to remove this problem to actually calling the .Dispose() method only once in your code and only after you're done working with it. A disposed object would raise, System.ObjectDisposedException exception if you dispose it again, but is not for sure. A correct dispose method can be called on an object, multiple times and will/might not generate an error for you. But is not guaranteed to do so.

The fix for this has been stated by Microsoft's Developer Network document,

To fix a violation of this rule, change the implementation so that regardless of the code path, Dispose is called only one time for the object.

For more: http://msdn.microsoft.com/en-us/library/ms182334.aspx

Upvotes: 1

Related Questions