2010-01-23 12 views
6

Tengo un conjunto de objetos de datos de transferencia (por ejemplo, una gran cantidad de reqest, clases de mensaje de respuesta, como MainRequest, MainResponse, ShutDownRequest, ShutDownResponse) Dónde nuevas clases siguen viniendo medida que el proyecto evoluciona. Estas clases se deben (de) serializar desde y hasta varios formatos XML con diferentes XSD públicas. Aparecen nuevos formatos XML a medida que el proyecto evoluciona también.serialización de transferencia de datos objetos en .NET

Mi pregunta aquí es cómo iba a diseñar mis clases e interfaces alrededor estos dos requisitos, especialmente donde debería poner la (de) la lógica real serilization. ¿Debo escribir un servicio estático que pueda tomar las diversas instancias de DTO y sepa cómo serializar cada una de ellas? Cuando lleguen nuevas clases, tengo que tocar cada FormatXSeriaizer y agregar nuevas anulaciones. A medida que aparecen nuevos formatos, solo tengo que escribir nuevas clases 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); 

o los propios DTO deben saber cómo hacerlo. Así que lo tengo todo en un solo lugar, para cada clase de DTO. A medida que llegan nuevas clases de DTO, solo tienen que implementar la serialización para los diversos formatos. Como vienen los nuevos formatos, tengo que tocar cada clase de DTO.

myMainRequestInstace.Serialize(FormatTypeEnum type, XmlWriter writer); 

¿O hay un enfoque completamente diferente? ¿Debería introducir una interfaz común para la serialización y tener alguna inversión de control, para poder cargar nuevos serializadores de formato en tiempo de ejecución?

¿Qué patrón de diseño puede guiarme aquí?

¿Qué código fuente abierto en el mundo .NET podría estudiar para ver diferentes enfoques sobre este tema?

EDIT: Conozco las técnicas generales de serialización existentes en el marco. Mi pregunta está más orientada al diseño de clases que respeta los dos requisitos: múltiples formatos xml y múltiples DTO (tipos de mensajes) que siguen surgiendo a medida que el proyecto evoluciona.

Respuesta

1

parte de la consideración será cómo los diferentes formatos XML son. En particular, ¿pueden lograrse todos utilizando la función de sobrescritura de Serialización XML? Eso le permite proporcionar una matriz de entradas anulando características como elemento o nombre de atributo/si serializar como elementos o atributos, etc.

Esto podría permitir que sus diversos formatos difieran solo en términos de la matriz de anulación pasada a el proceso de serialización. Eso te dejaría con la pregunta de cómo determinar la matriz para pasar.

+0

Ese es el tipo de respuestas que estoy buscando. – bitbonk

3

Ya existen algunos mecanismos integrados para realizar la serialización xml en .NET.

serialización basada en atributos - overview. Todo lo que tiene que hacer es etiquetar los miembros de su clase con atributos y usar la clase XmlSerializer para serializar/deserializar el tipo.


    [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" }); 

salida -

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

O puede presentar toda su xml clases serializables implementan IXmlSerializable.

Editar - Ahora ya no he entendido bien su pregunta original voy a modificar el presente con una técnica que puede utilizar para serializar el mismo objeto en múltiples tipos de formatos XML.

Ahora que su objeto de transferencia de datos se puede serializar en al menos un formato basado en xml, puede hacer un paso de traducción posterior para obtenerlo en el formato que desee utilizando xslt transforms. Xslt es una forma de tomar xml y traducirlo a cualquier cosa utilizando un archivo xslt para obtener instrucciones. En este caso, estaría traduciendo a otro formato xml.

Así es como (si se asume que ya ha escrito su archivo 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); 
+0

Conozco las técnicas existentes en el marco. Mi pregunta está más orientada al diseño de clases que respeta los dos requisitos: múltiples formantes xml y múltiples DTO que siguen llegando a medida que el proyecto evoluciona. Usar también "su" enfoque realmente no funciona si hay múltiples formatos xml para las mismas instancias de DTO, que es un requisito. – bitbonk

+0

Ahh entiendo lo que dices. No sé de una forma de serializar en diferentes formatos con el marco de serialización .NET xml existente, pero creo que tengo una posible solución para usted, así que edité mi respuesta para incluirla. –

5

El mejor enfoque sería algo como esto, este es mi método favorito:

 
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"); 
    } 

} 

Esta es la forma en Implico un control más estricto sobre la serialización de datos binarios y aumento la versión. Ahora, aquellos de ustedes señalarán que ya hay una función disponible para hacer esto, pero viniendo de .NET 1.1, bueno, los viejos hábitos son difíciles.

Observe que en el ejemplo de código anterior utilicé dos métodos diferentes HandleVersionOnePtZero y HandleVersionOnePtOne para manejar las diferentes versiones de la secuencia serializada. Al hacerlo de esta manera, tengo un mayor grado de flexibilidad, ¿qué pasa si el campo someField necesita ser cambiado? Además, observe cómo el campo _fVersion es lo primero que hace la rutina serializable, luego verifica la versión del campo y decide cuál usar.

La única cosa acerca de esto, es que si se cambia el espacio de nombres, a continuación, tendrá dificultades para deserializar los datos, pero se puede utilizar la clase SerializationBinder como ejemplo:

 
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 

espero que esto ayude

+0

OOOOPPPPS Mi mal ... Cuando estaba escribiendo esto, no me di cuenta de que se refería a XML ... perdón por los divagaciones y por los que rechazarán esto ... – t0mm13b

Cuestiones relacionadas