0

У нас есть проект с «пользовательскими объектами и атрибутами», созданный на java-сервере, и нужны эти данные на клиенте C#.DataContract + IxmlSerializable

например. Пользовательский объект «A» имеет атрибуты «B», «C». Оба «B» и «C» описываются клиентом во время выполнения. Сервер отправляет нам это в XML, как:

<A> 
    <B> B Data </B> 
    <C> C Data </C> 
</A> 

Мы создали класс, реализующий IXmlSerializable, что чтение/запись XML для сервера заполнения пользовательских атрибутов в словарь

public class CustomObject : IXmlSerializable 
{ 
    private Dictionary<String, String> attributes; 

    public void ReadXml(XmlReader reader) 
    { 
     attributes = XDocument.Parse(reader.ReadOuterXml()).Root.Elements() 
      .ToDictionary(xElm => xElm.Name.LocalName, xElm => xElm.Value) 
    } 

    // More Serialization logic for IXmlSerializable is here 
} 

Проект является медленным и мы хотим использовать более быструю сериализацию DataContract. Мы опробовали образец, явно указав строковые коды [DataContract] на наши атрибуты (например, «B», «C»). Однако в наших случаях использования атрибуты не известны во время компиляции. Мы можем запросить сервер для списка атрибутов типа «A».

Как мы можем использовать DataContract для атрибутов, определенных во время выполнения

+0

Вы можете попробовать внедрить ['IExtensibleDataObject'] (https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iextensibledataobject.aspx) в свой' CustomObject', а затем извлечь XML-файл, используя трюк в [ExtensionDataObject не помечен как сериализуемый] (https: // stackoverflow.ком/вопросы/32056762). Но, вы профилировали, чтобы определить, где настоящая проблема? – dbc

+0

Почему вы делаете 'XDocument.Parse (reader.ReadOuterXml())'? Это эффективно анализирует XML дважды. Если у вас возникли проблемы с производительностью, вы можете заменить это на ['ReadSubtree()'] (https://msdn.microsoft.com/en-us/library/system.xml.xmlreader.readsubtree.aspx). – dbc

+0

Спасибо за обратную связь @dbc, кажется, что XDocument занимает около 16 мс для каждого объекта, а также добавляет к нашей сигнатуре памяти. Вот почему мы хотим DataContract. Я проведу ссылку, которую вы поделили. –

ответ

0

Явные контракты данных, которые позволяют произвольно, неизвестные элементы не поддерживаются DataContractSerializer. XmlSerializer поддерживает это через [XmlAnyElementAttribute], но, как указано в ответе Using [XmlAnyElement], нет идентичной функциональности для контрактов данных.

Ваш класс может реализовать IExtensibleDataObject. Он похож на [XmlAnyElement] и предназначен для forward-compatible data contracts. К сожалению, в этом случае неизвестные элементы хранятся в непрозрачном ExtensionDataObject без очевидного способа доступа к значениям. Хотя можно извлечь XML из такого объекта (см. here), он неочевиден и вряд ли будет более впечатляющим, чем ваш текущий код, поскольку он требует повторной сериализации ExtensionDataObject внутри класса-оболочки, а затем разбора результата.

Одно замечание о производительности - когда вы делаете XDocument.Parse(reader.ReadOuterXml()), то reference source показывает эффективно синтаксического анализа XML, а затем потокового его через XmlWriter к StringWriter, то разбор результирующей строки во второй раз. Вместо того, чтобы делать это, вы можете разобрать XML только один раз, вызвав XNode.ReadFrom() на входящем читателя, например, так:

public class CustomObject : IXmlSerializable 
{ 
    private readonly Dictionary<String, String> attributes = new Dictionary<string, string>(); 

    public IDictionary<string, string> Attributes { get { return attributes; } } 

    #region IXmlSerializable Members 

    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() 
    { 
     return null; 
    } 

    void IXmlSerializable.ReadXml(XmlReader reader) 
    { 
     var element = XElement.ReadFrom(reader) as XElement; 
     if (element != null) 
     { 
      foreach (var item in element.Elements()) 
       attributes.Add(item.Name.LocalName, (string)item); 
     } 
    } 

    void IXmlSerializable.WriteXml(XmlWriter writer) 
    { 
     // Do NOT write the wrapper element when writing. 
     foreach (var pair in attributes) 
     { 
      writer.WriteElementString(pair.Key, pair.Value); 
     } 
    } 

    #endregion 
} 

Это должно быть более производительным, чем ваш текущий класс. Например, в Web API performance issues with large dynamic XML сообщенное улучшение для аналогичной оптимизации составило 40%.

Update

Для наилучшей производительности реализующей IXmlSerializable вам нужно будет прочитать содержимое непосредственно из XmlReader с помощью кода на заказ. Далее, например, читает имена элементов и значение в attributes словарь:

void IXmlSerializable.ReadXml(XmlReader reader) 
    { 
     if (reader.IsEmptyElement) 
     { 
      reader.Read(); 
      return; 
     } 
     reader.Read(); 
     while (reader.NodeType != XmlNodeType.EndElement) 
     { 
      switch (reader.NodeType) 
      { 
       case XmlNodeType.Element: 
        var key = reader.Name; 
        var value = reader.ReadElementContentAsString(); 
        attributes.Add(key, value); 
        break; 

       default: 
        // Comment, for instance. 
        reader.Read(); 
        break; 
      } 
     } 
     // Consume the EndElement 
     reader.Read(); 
    } 

См Proper way to implement IXmlSerializable? для некоторых общих принципов вручную чтение иерархии элементов правильно.

+0

Пробовал это, я нахожу ваше решение допустимой проблемой производительности, но оно не добавило значительных изменений, поэтому нам по-прежнему нужно лучшее решение. ExtensionDataObject не поможет, поскольку нам нужен доступ к данным из пользовательских атрибутов. –

+0

@ KitiAzura - самый эффективный способ разобрать XML, то это будет сделано вручную. Из раздела [Глава 9 - Повышение производительности XML] (https://msdn.microsoft.com/en-us/library/ff647804.aspx): * Если вы хотите прочитать документ один раз, используйте [XmlReader]. Это обеспечивает доступ только для чтения, только для чтения и без кэширования данных XML. Эта модель обеспечивает оптимизированную производительность и сохранение памяти. * Также см. [Эффективный Xml Part 1: Выберите правильный API] (https://blogs.msdn.microsoft.com/xmlteam/2011/09/14/effective-xml-part- 1-выбор-на-право-апи /). – dbc

+0

Я думаю, что ваш вышеприведенный комментарий выглядит как правильный ответ. В аренду это то, что я хотел сделать, прежде чем мы столкнулись с DataContract. –

Смежные вопросы