Почему XMLSerializer по умолчанию требует динамического генерации кода для десериализации?C#

Место общения программистов C#
Ответить
Anonymous
 Почему XMLSerializer по умолчанию требует динамического генерации кода для десериализации?

Сообщение Anonymous »

У меня есть вставленная история с не менее интересным вопросом. < /p>
Итак. В настоящее время я делаю инструмент для моей компании, который анализирует данные, полученные с Mex Endpoint службы WCF. В этом все в порядке, но меня попросили собрать мой проект .NET в Native 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

< /code>
Что? Какая ошибка? at (0, 0)?
Я точно знал, что файл .wsdl < /code> не виноват, потому что он пришел из Mex Endpoint, и я проверил его вручную. Ничего особенного, которое кричало «ошибка XML» для меня. /Code> Используется, он продвигает поток на 4096. И этот человек решил свою проблему, установив fs.position = 0; 
. Попробовал это, не помог. Когда я позвонил в обслуживание.

Код: Выделить всё

XMLSerializer.cs

Код: Выделить всё

[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);
}
}
...
...
...
Хорошо ... он пытался понижать с использованием отражения и внутренне упало, потому что '_roottype' был нулевым внутри функции getMapping ...
< P>

Код: Выделить всё

XMLSerializer.cs

Код: Выделить всё

[RequiresUnreferencedCode("calls GenerateXmlTypeMapping")]
private XmlMapping GetMapping()
{
if (_mapping == null || !_mapping.GenerateSerializer)
{
_mapping = GenerateXmlTypeMapping(_rootType!, null, null, null, DefaultNamespace);
}

return _mapping;
}
Хорошо, тогда ... Почему является _roottype null ? Я работаю с конкретным сериализатором, который имеет контекст о том, с каким файлом XML он собирается столкнуться. Итак, я проверил, что на самом деле находится внутри ServiceSction Serializer:

Код: Выделить всё

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;
}
}
Первое, что я заметил, что этот файл в репозитории Dotnet/WCF в последний раз изменился 4 года назад , так что я не использую неверную библиотеку Версия, так почему это начало разбивать и сообщить мне эту ошибку даже для файлов, которые я пробовал, и проанализировал при разработке основных функций? И, хорошо, они создают новый экземпляр обслуживания. Хорошо ... это обслуживаемым сектором -рецидиализатором класс - это просто пользовательская обертка вокруг XmlSerializer , которая использовала пользовательский читатель и писатель. О, вот почему «_roottype» - «нулевой»! Это не требует корня, потому что пользовательский читатель внутренне будет обрабатывать все. < /P>
Но подождите ... почему он использует отражение? У него есть пользовательский считыватель, поэтому он должен попасть в последнее время, если , который фактически вызывает переопределенный CreateReader () . Я начал исследовать WhoSeReflectionBasedSerialization (_mapping) Метод:

Код: Выделить всё

XmlSerializer.cs

Код: Выделить всё

 private static bool ShouldUseReflectionBasedSerialization(XmlMapping mapping)
{
return Mode == SerializationMode.ReflectionOnly
|| (mapping != null && mapping.IsSoap);
}
_mapping является нулевым, потому что он никогда не создается и не заполняется. Конструктор используемого XMLSerializer пуст. Так что второй пункт всегда правда. Таким образом, общее значение зависит только от режима . >

Код: Выделить всё

XmlSerializer.cs

Код: Выделить всё

internal static SerializationMode Mode
{
get => RuntimeFeature.IsDynamicCodeSupported ? s_mode : SerializationMode.ReflectionOnly;
set => s_mode = value;
}
< /code>
И он нажал! 2 недели назад я включил флажок в свойствах проекта «Включить нативную публикацию AOT», так что, конечно, RuntimeFeature.isdynamicCodeSupported 
является ложным. Конечно, этот тройной оператор возвращает Reflectiononly . Я изменил этот флажок, сообщил, что нам придется создать наш собственный анализатор WSDL, если мы хотим использовать этот инструмент, скомпилированный назначен. Недели на этой ошибке, потому что это буквально первый раз, когда -либо из -за этой ошибки, я тщательно гуглил, и ни у кого никогда не было этой ошибки. Я надеюсь, что эта страница будет показана поисковыми системами, и если кто -то столкнется с этой ошибкой, это поможет им. < /P>
Но вопрос все еще остается. Почему? Кажется очень странным, при составлении собственного кода отражение не должно быть действительно использовано для редактирования или создания типов во время выполнения, все типы должны быть скомпилированы и упакованы внутри исполняемого, нет? < /P>
И супер общий вариант использования для XmlSerializer подобен следующему: < /p>

Код: Выделить всё

XmlSerialier serializer = new XmlSerializer(...) { ... };
...
Foo fooObject = (Foo)serializer.Deserialize(reader);
Все типа и поля присутствуют и скомпилируются, так что Почему ? Требуется генерация динамического кода для десериализации с помощью пользовательского считывателя ??


Подробнее здесь: https://stackoverflow.com/questions/794 ... serializat
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»