4

I have the following simple XML serializable type:

[XmlType]
public class TestType
{
    public System.Net.SecurityProtocolType ProtocolType { get; set; }
}

var instanceToSerialize = new TestType { ProtocolType = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 };

I can serialize an instance of this object just fine on my computer and several computers. But on one of the computers I have tested, I am getting the following exception:

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: Instance validation error: '4080' is not a valid value for System.Net.SecurityProtocolType.
at System.Xml.Serialization.XmlCustomFormatter.FromEnum(Int64 val, String[] vals, Int64[] ids, String typeName)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterTestType.Write1_SecurityProtocolType(SecurityProtocolType v)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterTestType.Write3_TestType(String n, String ns, TestType o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterTestType.Write4_TestType(Object o)

I have compared the sgen.exe generated code for working and failing cases. On the working case I have this code generated:

string Write1_SecurityProtocolType(global::System.Net.SecurityProtocolType v) {
    string s = null;
    switch (v) {
        case global::System.Net.SecurityProtocolType.@Ssl3: s = @"Ssl3"; break;
        case global::System.Net.SecurityProtocolType.@Tls: s = @"Tls"; break;
        case global::System.Net.SecurityProtocolType.@Tls11: s = @"Tls11"; break;
        case global::System.Net.SecurityProtocolType.@Tls12: s = @"Tls12"; break;
        default: s = FromEnum(((System.Int64)v), new string[] {@"Ssl3", 
            @"Tls", 
            @"Tls11", 
            @"Tls12"}, new System.Int64[] {(long)global::System.Net.SecurityProtocolType.@Ssl3, 
            (long)global::System.Net.SecurityProtocolType.@Tls, 
            (long)global::System.Net.SecurityProtocolType.@Tls11, 
            (long)global::System.Net.SecurityProtocolType.@Tls12}, @"System.Net.SecurityProtocolType"); break;
    }
    return s;
}

Whereas on the failing code, this is the generated code:

string Write1_SecurityProtocolType(global::System.Net.SecurityProtocolType v) {
    string s = null;
    switch (v) {
        case global::System.Net.SecurityProtocolType.@Tls: s = @"Tls"; break;
        case global::System.Net.SecurityProtocolType.@Tls11: s = @"Tls11"; break;
        case global::System.Net.SecurityProtocolType.@Tls12: s = @"Tls12"; break;
        default: s = FromEnum(((System.Int64)v), new string[] {@"Tls", 
            @"Tls11", 
            @"Tls12"}, new System.Int64[] {(long)global::System.Net.SecurityProtocolType.@Tls, 
            (long)global::System.Net.SecurityProtocolType.@Tls11, 
            (long)global::System.Net.SecurityProtocolType.@Tls12}, @"System.Net.SecurityProtocolType"); break;
    }
    return s;
}

You can notice that the code for Ssl3 enum member is not generated on the failing case. Do you have any idea why that code is missing?

huseyint
  • 14,953
  • 15
  • 56
  • 78

1 Answers1

2

The plain diagnostic is that SGen.exe was run with the wrong reference assemblies. The /reference command line options matter, if it isn't used then it falls back to the ones in c:\windows\microsoft.net

The shoe fits, the SecurityProtocolType enum has been quite fickle. It was changed from .NET 4.0 to 4.5, adding the Tls11 and Tls12 enum members. Lots of Q+A here about it to get them enabled even on a project that targets 4.0. And there is a pretty big problem with SSLv3, it has been compromised beyond repair. Accordingly Microsoft is trying to stop programmers from using it, something you can see back in the .NETCore declaration. The [Obsolete] attribute is one that SGen.exe pays attention to.

It isn't otherwise obvious to me what flavor of reference assembly could have been used. While SslProtocols.Ssl3 has the [Obsolete] attribute in .NETCore, the SecurityProtocolType enum member does not. So SGen.exe accidentally using a .NETCore reference assembly doesn't explain it. Something like Mono or Xamarin doesn't easily explain it. Silverlight or a PCL reference assembly doesn't explain it, at least not on my machine. A wonky beta version is always a possibility.

Unless you have a known reason to use an unusual /reference argument for SGen.exe, the best recommendation is to reinstall the .NET Framework on that machine. And stop using Ssl3, it is truly obsolete.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536