Сериализация объектов передачи данных в.NET

У меня есть ряд объектов передачи данных (например, много reqest, классов ответного сообщения, как MainRequest, MainResponse, ShutDownRequest, ShutDownResponse), Где новые классы продолжают прибывать, поскольку проект развивается. Эти классы должны быть (de), сериализированный от и до различных форматов XML с другим общедоступным XSDs. Новые форматы XML прибывают, поскольку проект развивается также.

Мой вопрос здесь состоит в том, как я разработал бы свои классы и интерфейсы вокруг этих двух требование, особенно куда я должен поместить фактическое (de) serilization логика. Я должен записать статический сервис, который может взять различные экземпляры DTO знание, как сериализировать каждый из них? Когда новые классы прибывают, я должен коснуться каждого FormatXSeriaizer и добавить новые переопределения. Когда новые форматы прибывают, я просто должен записать новые классы FormatXSerializer.

FormatASerializer.Serialize(XmlWriter writer, MainResponse r);
FormatASerializer.Serialize(XmlWriter writer, ShutDownResponse r);
FormatBSerializer.Serialize(XmlWriter writer, MainResponse r);
FormatBSerializer.Serialize(XmlWriter writer, ShutDownResponse r);

или если DTOs themself знают, как сделать это. Таким образом, у меня есть все это в одном месте - для каждого класса DTO. Когда новые классы DTO прибывают, они просто должны реализовать сериализацию для различных форматов. Когда новые форматы прибывают, я должен коснуться каждого класса DTO.

myMainRequestInstace.Serialize(FormatTypeEnum type, XmlWriter writer);

Или есть ли полный другой подход? Я должен представить общий интерфейс для сериализации и иметь некоторую инверсию управления, таким образом, я мог загрузить новые сериализаторы формата во времени выполнения?

Какой шаблон разработки может вести меня сюда?

Какой открытый исходный код в мире.NET я мог изучить для наблюдения разных подходов к этому предмету?

Править: Я знаю об общих методах сериализации, существующих в платформе. Мой вопрос более приспособлен к дизайну класса, который уважает эти два требования: несколько xml форматов и несколько DTOs (типы сообщений), которые продолжают стать проектом, развиваются.

6
задан True Soft 16 June 2010 в 15:45
поделиться

4 ответа

Уже есть некоторые встроенные механизмы для выполнения сериализации XML в .NET.

Сериализация на основе атрибута - Обзор . Все, что вам нужно сделать, это пометить члены вашего класса с атрибутами и использовать класс XMLSerializer для сериализации / десериализации типа.


    [XmlRoot("myXmlClass")]
    public class MyXmlClass
    {
        [XmlAttribute("myAttribtue")]
        public string MyAttribute { get; set; }
        [XmlElement("myElement")]
        public string MyElement { get; set; }
    }

    var output = new MemoryStream();
    var serializer = new XmlSerializer(typeof(MyXmlClass));
    serializer.Serialize(output, new MyXmlClass { MyAttribute = "foo", MyElement = "bar" });

Выход -

<myXmlClass myAttribute="foo">
    <myElement>bar</myElement>
</myXmlClass>

или вы можете сделать все ваши серии XML-классов IXMLSERializable .

Редактировать - Сейчас, поскольку я неправильно понял ваш оригинальный вопрос, я поправлю на это с техникой, которую вы можете использовать для сериализации одного и того же объекта на несколько разных форматов XML.

Теперь, когда ваш объект передачи данных является сериализен, по меньшей мере, один формат на основе XML, который вы можете сделать шаг по переводу на почту, чтобы получить его в формате, который вы хотите использовать XSLT Transforms . XSLT - это способ взять XML и перевести его во что-либо, используя файл XSLT для получения инструкций. В этом случае вы будете переводиться в другой формат XML.

Вот как (предполагая, что вы уже написали свой файл XSLT) -


    // output stream from before
    output.Seek(0, SeekOrigin.Begin);
    var reader = XmlReader.Create(output);
    // cache this for performance reasons
    XslCompiledTransform transform = new XslCompiledTransform();
    transform.Load("c:\myTransforms\commonToFormatA.xslt");
    var writer = XmlWriter.Create(Console.Out); // write final output to console.
    transform.Transform(reader, writer);
3
ответ дан 10 December 2019 в 02:47
поделиться

Часть рассмотрения будет насколько различны форматы XML. В частности, они все могут быть достигнуты путем использования функции переопределения XML-сериализации? Это позволяет вам предоставить массив переопределения записей, таких как элемент или имя атрибута /, следует ли сериализовать как элементы или атрибуты и т. Д.

Это может позволить вам иметь различные форматы, отличающиеся только с точки зрения массива переопределения процесс сериализации. Это оставило бы вас с вопросом о том, как определить массив.

1
ответ дан 10 December 2019 в 02:47
поделиться

Читайте о пользовательских сериализаторах XML, они должны иметь возможность сделать все, что вам требуется.

http://geekswithblogs.net/marcel/archive/2006/05/19/78989.aspx

0
ответ дан 10 December 2019 в 02:47
поделиться

Лучшим подходом было бы что-то вроде этого, это мой любимый подход:

public class SomeClass : ISerializable{
   private float _fVersion;
   ....
   public float Version {
       get { return this._fVersion; }
   }

   private SomeClass(SerializationInfo info, StreamingContext context) {
      bool bOk = false;
      this._fVersion = info.GetSingle("versionID");
      if (this._fVersion == 1.0F) bOk = this.HandleVersionOnePtZero(info, context);
      if (this._fVersion == 1.1F) bOk = this.HandleVersionOnePtOne(info, context);

      if (!bOk) throw new SerializationException(string.Format("SomeClass: Could not handle this version {0}.", this._fVersion.ToString()));
   }
   public void GetObjectData(SerializationInfo info, StreamingContext context) {
      info.AddValue("versionID", this._fVersion);
      if (this._fVersion == 1.0F) {
         info.AddValue("someField", ...);
         info.AddValue("anotherField", ...);
      }
      if (this._fVersion == 1.1F) {
         info.AddValue("someField1", ...);
         info.AddValue("anotherField2", ...);
      }
   }
   private bool HandleVersionOnePtZero(SerializationInfo info, StreamingContext context) {
      bool rvOk = false;
      ... = info.GetValue("someField");
      ... = info.GetValue("anotherField");
   }

   private bool HandleVersionOnePtOne(SerializationInfo info, StreamingContext context) {
      bool rvOk = false;
      ... = info.GetValue("someField1");
      ... = info.GetValue("anotherField2");
   }

}

Так я усиливаю более жесткий контроль над сериализацией двоичных данных и повышаю версию. Теперь, те из вас отметят, что для этого уже есть возможность, но исходя из .NET 1.1, ну, старые привычки умирают с трудом.

Обратите внимание, что в приведенном выше примере кода я использовал два разных метода HandleVersionOnePtZero и HandleVersionOnePtOne для работы с различными версиями сериализованного потока. Делая это таким образом, я получаю большую степень гибкости, скажите, что если поле someField нужно изменить? Также обратите внимание, что поле _fVersion - это первое, что сериализуемая рутина делает сначала, затем проверяет версию поля и решает, какую из них использовать.

Единственное, что в этом случае, если вы измените пространство имён, то вам будет сложно десериализовать данные, но вы можете использовать класс SerializationBinder в качестве примера:

public class SomeClassBinder : System.Runtime.Serialization.SerializationBinder {
    public override Type BindToType(string assemblyName, string typeName) {
      Type typeToDeserialize = null;
      try {
         // For each assemblyName/typeName that you want to deserialize to
         // a different type, set typeToDeserialize to the desired type.
         string assemVer1 = System.Reflection.Assembly.GetExecutingAssembly().FullName;
         if (assemblyName.StartsWith("foobar")) {
             assemblyName = assemVer1;
             typeName = "fubar" + typeName.Substring(typeName.LastIndexOf("."), (typeName.Length - typeName.LastIndexOf(".")));
         }
         typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
      } catch (System.Exception ex1) {
          throw ex1;
      } finally {
    }
    return typeToDeserialize;
  }
}

it would be called like this:
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new SomeClassBinder();
SomeClass sc = bf.Deserialize(stream); // assume stream is declared and open

Надеюсь, это поможет

.
5
ответ дан 10 December 2019 в 02:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: