我有一个插入的故事,还有一个有趣的问题。
我目前正在为我的公司制作一个工具,该工具解析了从WCF服务的MEX端点收到的数据。一切都可以,但是我被要求将.NET项目编译到本地AOT,以排除安装.NET运行时的需求并提高性能Yada-yada。一个绝对普遍的请求。
但在测试中,测试人员已经开始遇到此错误:
System.InvalidOperationException
HResult=0x80131509
Message = There is an error in XML document (0, 0).
Source = System.Private.Xml
Stack trace:
in System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
in System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
in System.Web.Services.Description.ServiceDescription.Read(XmlReader reader, Boolean validate)
in System.Web.Services.Description.ServiceDescription.Read(Stream stream, Boolean validate)
in DocSynth.Remote.WCF.Services.WSDLParser.ReadWSDLFiles(IEnumerable`1 filePaths)
in DocSynth.Remote.WCF.Services.WCFMEXMetadataProvider.ParseWCFFiles(WCFFilesPreparationResult files)
Initial Stack trace:
System.ArgumentNullException.Throw(string)
System.ArgumentNullException.ThrowIfNull(object, string)
System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(System.Type, System.Xml.Serialization.XmlRootAttribute, string)
System.Xml.Serialization.XmlSerializer.GetMapping()
System.Xml.Serialization.XmlSerializer.Deserialize(System.Xml.XmlReader, string, System.Xml.Serialization.XmlDeserializationEvents)
Internal Exception 1:
ArgumentNullException: Value cannot be null. Arg_ParamName_Name
什么?什么错误?在(0,0)?
我肯定知道.WSDL
文件没有错,因为它来自MEX端点,而且我手动检查了它。没有什么特别的对我尖叫的“ XML错误”。因此,我已经开始探索:从这个MSDN帖子开始,我了解到,当使用
XMLTextReader
创建Stream
时,它将流到4096。 。尝试过,没有帮助。NEXT:我已经开始逐步检查代码。当我打电话
fs.Position = 0;
时,它执行了以下代码:
ServiceDescription.Read(fs)
XMLSerializer.cs
okay ...它试图使用反射进行反序列化,而在内部掉落,因为“ _roottype”在功能内部无效......
...
[RequiresUnreferencedCode(TrimDeserializationWarning)]
public object? Deserialize(XmlReader xmlReader, string? encodingStyle, XmlDeserializationEvents events)
{
events.sender = this;
try
{
if (_primitiveType != null)
{
if (encodingStyle != null && encodingStyle.Length > 0)
{
throw new InvalidOperationException(SR.Format(SR.XmlInvalidEncodingNotEncoded1, encodingStyle));
}
return DeserializePrimitive(xmlReader, events);
}
// This 'else if' was executed
else if (ShouldUseReflectionBasedSerialization(_mapping) || _isReflectionBasedSerializer)
{
return DeserializeUsingReflection(xmlReader, encodingStyle, events);
}
else if (_tempAssembly == null || _typedSerializer)
{
XmlSerializationReader reader = CreateReader();
reader.Init(xmlReader, events, encodingStyle);
return Deserialize(reader);
}
else
{
return _tempAssembly.InvokeReader(_mapping, xmlReader, events, encodingStyle);
}
}
...
...
...
GetMapping
然后……然后...为什么是XMLSerializer.cs
?我正在使用一个特定的序列化器,该序列化机具有有关其即将遇到的XML文件的上下文。因此,我已经检查了
[RequiresUnreferencedCode("calls GenerateXmlTypeMapping")]
private XmlMapping GetMapping()
{
if (_mapping == null || !_mapping.GenerateSerializer)
{
_mapping = GenerateXmlTypeMapping(_rootType!, null, null, null, DefaultNamespace);
}
return _mapping;
}
的序列化器中实际是什么:
_rootType
null
我注意到的第一件事是,Dotnet/WCF存储库中的此文件最后一次更改了4年前
,所以我没有使用错误的库版本,那么为什么它开始破坏并告诉我这个错误对于我在开发主要功能时尝试和解析的文件?我开始研究这个序列化的,...好吧,他们创建了一个新实例,该实例在此getter上方定义。好的...那个
ServiceDesction
类只是使用自定义阅读器和作家的自定义包装器。哦,这就是为什么“ _roottype”为“ null”!它不需要根类型,因为内部自定义阅读器将处理所有内容。 但要等...为什么它会使用反射?它具有自定义阅读器,因此应该落入最后一个clast clust call called
ServiceDescription.cs
。我已经开始研究internal class ServiceDescriptionSerializer : XmlSerializer
{
protected override XmlSerializationReader CreateReader()
{
return new ServiceDescriptionSerializationReader();
}
protected override XmlSerializationWriter CreateWriter()
{
return new ServiceDescriptionSerializationWriter();
}
public override bool CanDeserialize(System.Xml.XmlReader xmlReader)
{
return xmlReader.IsStartElement("definitions", Namespace);
}
protected override void Serialize(Object objectToSerialize, XmlSerializationWriter writer)
{
((ServiceDescriptionSerializationWriter)writer).Write125_definitions(objectToSerialize);
}
protected override object Deserialize(XmlSerializationReader reader)
{
return ((ServiceDescriptionSerializationReader)reader).Read125_definitions();
}
}
[XmlIgnore]
public static XmlSerializer Serializer
{
get
{
if (s_serializer == null)
{
WebServicesSection config = WebServicesSection.Current;
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("s", XmlSchema.Namespace);
WebServicesSection.LoadXmlFormatExtensions(config.GetAllFormatExtensionTypes(), overrides, ns);
s_namespaces = ns;
s_serializer = new ServiceDescriptionSerializer();
s_serializer.UnknownElement += new XmlElementEventHandler(RuntimeUtils.OnUnknownElement);
}
return s_serializer;
}
}
方法:ServiceDescriptionSerializer
ServiceDescriptionSerializer
XmlSerializer
是无效的,因为它从未创建或填充。使用的XMLSerializer的构造函数为空。因此,第二子句始终是正确的。因此,总价值仅取决于
else if
是
CreateReader()
,我去检查了这种模式是什么,以及为什么它的值为ShouldUseReflectionBasedSerialization(_mapping)
::
XmlSerializer.cs
private static bool ShouldUseReflectionBasedSerialization(XmlMapping mapping)
{
return Mode == SerializationMode.ReflectionOnly
|| (mapping != null && mapping.IsSoap);
}
_mapping
。我已经更改了该复选框,报道说,如果我们要本地使用此工具,我们将必须创建自己的WSDL解析器。但随后感到沮丧,我在这个错误上花了1.5周的时间,因为这实际上是这个错误的曾经是曾经的一次错误,我已经彻底搜索了谷歌搜索,没有人遇到过这个错误。我希望此页面通过搜索引擎索引,如果有人遇到此错误,它将对他们有所帮助。
但是这个问题仍然存在。
为什么?为什么XMLSerializer需要动态代码生成以序列化,如果程序是用本机代码构建的?似乎很奇怪,当编译本机代码时,反射不应在运行时进行编辑或创建类型,所有类型都应在可执行文件中进行编译和打包,否?XMLSerializer的超级通用用例就是这样:
Mode
所有类型和字段信息都存在并已编译,所以当? 为什么XMLSerialials需要使用自定义阅读器的动态代码生成?
您是正确的,如果您具有预编译的序列化器,那么您可以避免生成动态序列化组件。
但是你没有那些。您所拥有的只是AOT二进制文件,这还不足。它希望您使用XML工具预先生成序列化组件。对于.net框架,即工具,并且
for .net core在构建项目文件之前,您需要在项目文件中添加一些行。
ReflectionOnly