为什么默认XMLSerializer需要动态代码生成以进行验证?

问题描述 投票:0回答:0

我有一个插入的故事,还有一个有趣的问题。

我目前正在为我的公司制作一个工具,该工具解析了从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); }

它点击了! 2周前,我在项目属性“启用本机AOT出版物”中启用了一个复选框,因此当然是错误的。当然,该三元操作员返回

_mapping
。我已经更改了该复选框,报道说,如果我们要本地使用此工具,我们将必须创建自己的WSDL解析器。
但随后感到沮丧,我在这个错误上花了1.5周的时间,因为这实际上是这个错误的曾经是曾经的一次错误,我已经彻底搜索了谷歌搜索,没有人遇到过这个错误。我希望此页面通过搜索引擎索引,如果有人遇到此错误,它将对他们有所帮助。

但是这个问题仍然存在。

为什么?为什么XMLSerializer需要动态代码生成以序列化,如果程序是用本机代码构建的?似乎很奇怪,当编译本机代码时,反射不应在运行时进行编辑或创建类型,所有类型都应在可执行文件中进行编译和打包,否?
XMLSerializer的超级通用用例就是这样:
Mode
所有类型和字段信息都存在并已编译,所以
当?
为什么XMLSerialials需要使用自定义阅读器的动态代码生成?
    

您是正确的,如果您具有预编译的序列化器,那么您可以避免生成动态序列化组件。

但是你没有那些。您所拥有的只是AOT二进制文件,这还不足。它希望您使用XML工具预先生成序列化组件。对于.net框架,即
工具

,并且
for .net core
在构建项目文件之前,您需要在项目文件中添加一些行。

ReflectionOnly

    

c# .net xml wcf wsdl
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.