4

我有以下简单的 XML 可序列化类型:

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

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

我可以在我的计算机和几台计算机上很好地序列化这个对象的一个​​实例。但是在我测试过的其中一台计算机上,出现以下异常:

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)

我已经比较了sgen.exe工作和失败案例的生成代码。在工作案例中,我生成了以下代码:

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;
}

而在失败的代码上,这是生成的代码:

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;
}

您会注意到Ssl3枚举成员的代码不会在失败的情况下生成。您知道为什么缺少该代码吗?

4

1 回答 1

2

简单的诊断是 SGen.exe 使用错误的参考程序集运行。/reference命令行选项很重要,如果不使用,那么它会回退到 c:\windows\microsoft.net 中的选项

鞋子合脚,SecurityProtocolType 枚举一直很变幻无常。它从 .NET 4.0 更改为 4.5,添加了 Tls11 和 Tls12 枚举成员。这里有很多关于它的 Q+A,即使在针对 4.0 的项目中也可以启用它们。SSLv3 有一个相当大的问题,它已经被破坏了,无法修复。因此,微软正试图阻止程序员使用它,你可以在.NETCore 声明中看到这一点。[Obsolete] 属性是 SGen.exe 关注的一个属性。

对我来说,本来可以使用哪种参考程序集并不明显。虽然 SslProtocols.Ssl3 在 .NETCore 中具有 [Obsolete] 属性,但 SecurityProtocolType 枚举成员没有。所以 SGen.exe 不小心使用了 .NETCore 参考程序集并没有解释它。Mono 或 Xamarin 之类的东西不容易解释它。Silverlight 或 PCL 参考程序集没有解释它,至少在我的机器上没有。一个不稳定的测试版总是有可能的。

除非您有已知的理由/reference为 SGen.exe 使用不寻常的参数,否则最好的建议是在该计算机上重新安装 .NET Framework。并且停止使用 Ssl3,它确实已经过时了。

于 2017-01-27T18:02:32.470 回答