DRAFT Whitepaper: Dealing with Obsolete error messages

In response to a recent thread The Good and the Bad: Obsoletion in the Framework and LOTs of internal discussion, I have written this short whitepaper that describes the intent of using obsolete in the .NET Framework and how it affects your development projects. I believe that that paper balances some of our customer’s requirements that we continue to improve and evolve the .NET Framework with our commitment to provide backwards compatibility in order to preserve customer investments in the .NET Framework today for years to come.

I want to stress that this is just a DRAFT paper… It is not Microsoft’s official position yet. I am still in the process of getting feedback internally and, with this blog entry, externally as well. Please do give me your feedback.

Thanks

Summary:

When migrating source code from V1.0 or V1.1 of the Framework to V2.0 you may see some new compiler warnings indicating that you are using types or members that are obsolete. Generally speaking, this warning does NOT indicate that your code will not work well on version 2.0 of the .NET Framework but it does provide some suggestions for updates to your code that Microsoft recommends you make. Microsoft makes every effort to ensure that your V1.0 and V1.1 based applications run as expected on new versions of the .NET Framework. The obsolete warnings highlight where there is some new functionality in the platform that your program could benefit from using. This brief paper describes some strategies for dealing with these warnings in the least disruptive way. In summary:

  1. Understand that Obsolete warnings from the .NET Framework do NOT imply your application will not migrate cleanly or nor that it is a guaranteed that future versions of the .NET Framework will drop support for that type or member (unless specifically noted in the message).
  2. You may want to suppress the warning with a #pargma or /nowarn compiler switch and use FxCop to flag obsolete members

Description:

Microsoft marks types and members in the .NET Framework as being obsolete (by applying the ObsoleteAttribute) to indicate that there is some new functionality in the Framework that Microsoft recommends you migrate to. When used in the .NET Framework, these obsolete warnings do NOT indicate that your source code will not function properly or that Microsoft will definitely be removing these members in the near future. Microsoft remains committed to backwards compatibility of the .NET Framework in order to ensure that investments you make on the framework today continue to pay off for many years in the future.

What does Obsolete mean in the Framework?

When used in the .NET Framework, the obsolete warnings indicate that there is some new feature of the framework which you should consider migrating to. In many cases by simply changing the functions you call in the framework to the suggested alternative you can make your application more secure, performant or reliable. However in some cases it may not be worth the development costs to move to the new functionality. You can make that determination by understanding the impact of the change on your source code and the benefits as described in the warning text and the linked help page.

In some extreme cases Microsoft will be forced to actually remove an obsolete member in a future version of the .NET Framework. This is likely to be a very rare case. When this is the intent the member will be marked with Error=True in the ObsoleteAttribute indicating that a compiler error (rather than warning) should be generated. You are strongly recommended to migrate your projects off these members to ensure they work seamlessly on future versions of the .NET Framework.

The code below shows an example of using an obsolete member. This code compiles without warnings under V1.1, but when migrated to V2.0 it generates a warning as shown.

 

[C#]

using System;

using System.Xml;

using System.Xml.Schema;

public class SampleOld

{

    public static void Main1()

    {

        XmlSchemaCollection xsc = new XmlSchemaCollection();

        xsc.Add(null, "schema1.xsd"); //Adds schema & compiles

        xsc.Add("ns-a", "schema2.xsd"); //adds schema & compiles all schemas

        foreach (XmlSchema schema in xsc)

        {

            Console.WriteLine("Schema in Coll: " + schema.TargetNamespace);

        }

    }

} // End class

 

[VB]
Imports System.Xml
Imports System.Xml.Schema

Public Module SampleOld
Public Sub Main1()
Dim xsc As New XmlSchemaCollection()
xsc.Add(Nothing, "schema1.xsd")
xsc.Add("ns-a", "schema2.xsd")
For Each schema As XmlSchema In xsc
Console.WriteLine("Schema in Coll: " & schema.TargetNamespace)
Next
End Sub
End Module

It generates these warning:

Warning 1 'System.Xml.Schema.XmlSchemaCollection' is obsolete: 'Consider using System.Xml.Schema.XmlSchemaSet for schema compilation and validation. https://go.microsoft.com/fwlink/?linkid=14202' ObsoleteExample.cs 9 8

Warning 2 'System.Xml.Schema.XmlSchemaCollection' is obsolete: 'Use System.Xml.Schema.XmlSchemaSet for schema compilation and validation. https://go.microsoft.com/fwlink/?linkid=14202' ObsoleteExample.cs 9 38                        

                         

Reading the information on the link you will discover that XmlSchemaSet was obsoleted for these reasons:

  • It implements a deprecated, proprietary Microsoft XML schema language named XML Data Reduced (XDR)
  • Schemas are always compiled when added to the XmlSchemaCollection which led to problems when resolving schemas with interdependencies such as circular imports.

As you see from the warning text and information on the website indicated, the fix is trivial:

[C#]

using System;

using System.Xml;

using System.Xml.Schema ;

public class SampleNew

{

    public static void Main()

    {

        XmlSchemaSet set = new XmlSchemaSet();

        set.Add(null, "schema1.xsd");

        set.Add("ns-a", "schema2.xsd");

        set.Compile(); //Add multiple schemas and explicitly call compile

        foreach (XmlSchema schema in set.Schemas())

        {

            Console.WriteLine("Schema in set: " + schema.TargetNamespace);

        }

    }

} // End class

[VB]
Imports System.Xml
Imports System.Xml.Schema
Public Module SampleNew
Public Sub Main()
Dim xset As New XmlSchemaSet()
      xset.Add(Nothing, "schema1.xsd")
      xset.Add("ns-a", "schema2.xsd")
      xset.Compile()'Add multiple schemas and explicitly call compile
For Each schema As XmlSchema In xset.Schemas()
         Console.WriteLine("Schema in Coll: " & schema.TargetNamespace)
Next
End Sub
End Module

Obsolete and /warnaserror+

Many development teams consider it a best practice to compile with warnings as errors. This practice ensures that all warnings are resolved and any potential issues are addressed. The VB and C# compilers generate a warning for usage of obsolete members of the framework with text that describes the new functionality that you should consider using instead. As we describe above, it may not always make sense to immediately fix these warnings. For teams that compile with warnings as errors (/warnaserror+) this posses a problem as these obsolete warnings are turned into errors which must be addressed. As such Microsoft recommends that teams using /warnaserror+ also use /nowarn:0618 (for C#) or /nowarn:40000 (for VB) to suppress the obsolete messages. Although explicitly turning off all warnings of a certain class is not generally considered good development practice in this case it is the preferred way to handle this situation.

You will of course want to review your usage of obsolete members and decide which ones to fix. Under this plan the preferred way to do that is to use FxCop which contains a rule “ConsiderNotUsingObsoleteFunctionality”. By running FxCop over your project with this rule on you are able to triage the issues out of band of the mainline development process.

This code sample shows how this process would work. This code compiles without warnings under V1.1 and continues to under V2.0 if compiled as shown below.

 

[C#]

using System;

using System.Xml;

using System.Xml.Schema;

public class SampleOld

{

    public static void Main1()

    {

        XmlSchemaCollection xsc = new XmlSchemaCollection();

        xsc.Add(null, "schema1.xsd"); //Adds schema & compiles

        xsc.Add("ns-a", "schema2.xsd"); //adds schema & compiles all schemas

        foreach (XmlSchema schema in xsc)

        {

            Console.WriteLine("Schema in Coll: " + schema.TargetNamespace);

        }

    }

} // End class

Compile line:

C:\ObsoleteExample>csc /warnaserror+ /nowarn:0618 old.cs

 

[VB]
Imports System.Xml
Imports System.Xml.Schema
Public Module SampleOld
Public Sub Main1()
Dim xsc As New XmlSchemaCollection()
xsc.Add(Nothing, "schema1.xsd")
xsc.Add("ns-a", "schema2.xsd")
For Each schema As XmlSchema In xsc
Console.WriteLine("Schema in Coll: " & schema.TargetNamespace)
Next
End Sub
End Module

Compile line:

C:\ObsoleteExample>vbc /warnaserror+ /nowarn:40000 class1.vb

 

 

Alternatively in C#, you can use the #pragma around the offending lines to keep the compiler from issuing a warning or error. As shown here:

using System;

using System.Xml;

using System.Xml.Schema;

public class SampleOld

{

  public static void Main()

    {

#pragma warning disable 0618

        XmlSchemaCollection xsc = new XmlSchemaCollection();

        xsc.Add(null, "schema1.xsd"); //Adds schema & compiles

        xsc.Add("ns-a", "schema2.xsd"); //adds schema & compiles all schemas

#pragma warning restore 0618

        foreach (XmlSchema schema in xsc)

        {

            Console.WriteLine("Schema in Coll: " + schema.TargetNamespace);

        }

    }

} // End class

As you see, we got no warnings or errors in either case. Out of band of the official build you may want to run FxCop to flag potential problems and fix the appropriate ones.

C:\ObsoleteExample>fxcopcmd /rid:Usage# ConsiderNotUsingObsoleteFunctionality /f:old.exe /console

Warning : ConsiderNotUsingObsoleteFunctionality: SampleOld old.cs(9,8): This member is Obsolete. "Consider using System.Xml.Schema.XmlSchemaSet for schema compilation and validation."

 

This mechanism allows you to migrate to new versions of the .NET Framework easily while also being aware of new features of the .NET Framework that maybe worth considering.