InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
También puedes ver ...
SubVersion y Visual Studio
Encriptación con AES Rijndael - Ejemplo
TripleDES - Un ejemplo practico en C#
Insertar una marca de agua en documentos PDF
Handler para manipular imagenes
Conversiones de tipos personalizadas (VB y C#)
Compresión por gzip y deflate
La página Web que está abriendo contiene tanto elementos seguros como no seguros.
Cómo insertar un fichero .xml en un campo de tipo XML de SQL server 2005 o 2008
Comparativa de sentencias VB.Net vs C#


Serialización: XmlSerializer y BinaryFormater

La serialización es un proceso a través del cual almacenamos un objeto existente en la memoria de un ordenador en un medio de almacenamiento - por ejemplo un archivo.

Simplificando mucho - partiendo de un objeto existente en la memoria de un programa -, al serializarlo lo que estamos haciendo es guardar ese objeto en un fichero (u otro medio de almacenamiento). Posteriormente podemos utilizar ese fichero para crear un nuevo objeto que es idéntico en todo al objeto serializado originalmente.

Como veremos en este articulo la afirmación anterior no es del todo cierta, ya que el objeto obtenido como resultado de recuperar el objeto inicial, no es siempre identico en todo al original. Depende de la forma en la que lo serialicemos.

La serializacion XML solo guarda las propiedades públicas del objeto, mientras que la serializacion binaria guarda tanto las propiedades publicas como privadas.

Veamos un ejemplo. Creamos un nuevo proyecto de Consola (en mi caso Visual Studio 2008)

Creamos una nueva clase Foo, esta clase es muy simple, solo tiene tres propiedades:ID, Nombre y Edad.
El matiz está en la propiedad Edad , es privada. La edad se asigna a través del método AsignaEdad y se recupera con DameEdad. Por último sobreescribe el método ToString para que muestre en pantalla los datos.

La clase está marcada con el atributo Serializable.

 

[Serializable]

public class Foo

{

public int ID { get; set; }

public string Nombre { get; set; }

private int Edad { get; set; }

public void AsignaEdad(int edad)

{

Edad = edad;

}

 

public int DameEdad()

{

return Edad;

}

 

public override string ToString()

{

return String.Format("ID:{0}\nNombre:{1}\nEdad:{2}\n",

ID, Nombre, Edad);

}

}

Para que el ejemplo funcione correctamente debemos realizar las siguientes importaciones de espacios de nombres.

 

using System.Xml.Serialization;

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Binary;

Lo que queremos hacer es sencillo. Creamos una nueva instancia de Foo, y asignamos la edad llamando al método AsignaEdad.

Primeramente serializamos la nuestra instancia en Xml y posteriormente la recuperamos (desserializar), mostramdo el contenido de la clase en ambos casos a través de una llamada al método ToString().

 
static void Main(string[] args) {

Foo f = new Foo();

f.ID = 1;

f.Nombre = "El nombre";

f.AsignaEdad(7);

 

Console.WriteLine("Primero en Xml");

XmlSerializer xml = new XmlSerializer(f.GetType());

using (FileStream fs = new FileStream(@"C:\temp\foo1.xml",

FileMode.Create , FileAccess.ReadWrite, FileShare.None))

{

xml.Serialize(fs, f);

fs.Close();

Console.WriteLine(

"Esto es lo que hemos serializado(xml)");

Console.WriteLine(f.ToString());

}

//Ahora recuperamos

using (FileStream fs = new FileStream (@"C:\temp\foo1.xml",

FileMode.Open , FileAccess.Read , FileShare.None))

{

Console.WriteLine("");

Foo otroFoo = (Foo)xml.Deserialize(fs);

fs.Close();

Console.WriteLine("Esto es lo que recuperamos(xml)");

Console.WriteLine(otroFoo.ToString());

}

 

Console.ReadLine();

}

La salida del programa es la siguiente:


Primero en Xml
Esto es lo que hemos serializado(xml)
Id:1
Nombre:El nombre
Edad:7


Esto es lo que recuperamos(xml)
Id:1
Nombre:El nombre
Edad:0

Podemos ver claramente que la propiedad privada - Edad -, tenía el valor 7 antes de serializarse y que vale 0 despues de desserializar. De hecho, si miramos el archivo foo1.xml tendremos lo siguiente:

 

<?xml version="1.0"?>

<Foo

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<ID>1</ID>

<Nombre>El nombre</Nombre>

</Foo>

Es lógico, la clase XmlSerializer - definida en System.Xml.Serialization - utiliza internamente reflexión para crear el documento XML de salida, por lo que no puede tener acceso a las propiedades privadas.

Si lo que queremos es una copia exacta del objeto tendremos que utilizar la serialización binaria. Veamos el mismo ejemplo, pero utilizando la serialización binaria.

 
static void Main(string[] args) {

Foo f = new Foo();

f.ID = 1;

f.Nombre = "El nombre";

f.AsignaEdad(7);

 

Console.WriteLine("Ahora lo mismo en binario");

 

IFormatter formatter = new BinaryFormatter();

using (FileStream fs = new FileStream(@"C:\temp\foo1.bin",

FileMode.Create , FileAccess.Write, FileShare.None))

{

formatter.Serialize(fs, f);

fs.Close();

Console.WriteLine(

"Esto es lo que hemos serializado(bin)");

Console.WriteLine(f.ToString() );

}

 

using (FileStream fs = new FileStream(@"C:\temp\foo1.bin",

FileMode.Open, FileAccess.Read , FileShare.None))

{

Console.WriteLine("");

Foo otroFoo = (Foo)formatter.Deserialize(fs);

fs.Close();

Console.WriteLine("Esto es lo que recuperamos(bin)");

Console.WriteLine(otroFoo.ToString());

}

 

Console.ReadLine();

}

El resultado de la ejecucion es :


Ahora en binario
Esto es lo que hemos serializado(bin)
Id:1
Nombre:El nombre
Edad:7


Esto es lo que recuperamos(bin)
Id:1
Nombre:El nombre
Edad:7
 

Podemos ver que en este caso hemos recuperado el objeto exactamente igual que el objeto inicial. Esto es así porque en este caso lo que estamos serializando es directamente el buffer de memoria - es decir, el array de bytes que representa la objeto.

Pero ... ¿que hacemos si necesitamos serializar en XML pero queremos mantener también los miembros privados?. En este caso tenemos que trabajar un poquillo más, y hacer una breve introduccion a Base64. Base64 es un algoritmo que nos permite representa como un tipo string un array de bytes.

Lo primero que necesitamos es crear una nueva clase - FooWrapper -, que dispondrá de una propiedad pública FooString pensada para almacenar la representacion en Base64 de la instancia de Foo.

 

public class FooWrapper

{

public string FooString { get; set; }

}

La idea es serializar de forma binaria el objeto que tenemos inicialmente, pero no a un fichero como en el ejemplo anterior, sino a un MemoryStream. Posteriormente obtendremos el string en Base64 de este MemoryStream y lo asignamos a la propiedad pública FooString del FooWrapper. Finalmente serializamos en XML el FooWrapper.

Vamos a ayudarnos de la clase Convert, que dispone de métodos para convertir y recuperar bufferes a string y viceversa.

Mejor lo vemos con un ejemplo:

 

static void Main(string[] args)

{

Foo f = new Foo();

f.ID = 1;

f.Nombre = "El nombre";

f.AsignaEdad(7);

 

Console.WriteLine("Ahora en XML con un wrapper en Base64");

/*

* Primero realizamos una serializacion binaria a

* un MemoryStream y obtenemos su representacion

* en Base64

*/

string b64String = String.Empty ;

using (MemoryStream ms =new MemoryStream())

{

IFormatter formatter = new BinaryFormatter();

formatter.Serialize(ms, f);

ms.Close();

b64String = Convert.ToBase64String(ms.ToArray());

Console.WriteLine(

"Esto es lo que hemos serializado:\n{0}\n", b64String);

Console.WriteLine(f.ToString());

}

Console.WriteLine("");

 

//Creamos el wrapper y lo serializamos en XML

XmlSerializer xml = new XmlSerializer(typeof(FooWrapper) );

using (FileStream fs = new FileStream(@"C:\temp\fooWrapper.xml",

FileMode.Create , FileAccess.ReadWrite, FileShare.None))

{

FooWrapper fw = new FooWrapper();

fw.FooString = b64String;

xml.Serialize(fs, fw);

fs.Close();

}

 

//Ahora desserailziamos

using (FileStream fs = new FileStream(@"C:\temp\fooWrapper.xml",

FileMode.Open, FileAccess.Read, FileShare.None))

{

FooWrapper FooWrapper =

(FooWrapper)xml.Deserialize(fs);

fs.Close();

// Ahora recuperamos el Foo del wrapper

byte[] fooBytes =

Convert.FromBase64String(otroFooWrapper.FooString);

MemoryStream ms = new MemoryStream(fooBytes);

IFormatter formatter = new BinaryFormatter();

Foo foo = (Foo)formatter.Deserialize(ms) ;

Console.WriteLine("Esto es lo que recuperamos(xml)");

Console.WriteLine(foo.ToString());

}

Console.ReadLine();

}

La salida que obtenemos es la siguiente:

 

Ahora en XML con un wrapper en Base64
Esto es lo que hemos serializado:

AAEAAAD/////AQAAAAAAAAAMAgAAAEpDb25zb2xlQXBwbGljYXRpb2
43LCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUH
VibGljS2V5VG9rZW49bnVsbAUBAAAAF0NvbnNvbGVBcHBsaWNhdGlvb
jcuRm9vAwAAABM8SUQ+a19fQmFja2luZ0ZpZWxkFzxOb21icmU+a19
fQmFja2luZ0ZpZWxkFTxFZGFkPmtfX0JhY2tpbmdGaWVsZAABAAgIAg
AAAAEAAAAGAwAAAAlFbCBub21icmUHAAAACw==

Id:1
Nombre:El nombre
Edad:7

Esto es lo que recuperamos(xml con wrapper)
Id:1
Nombre:El nombre
Edad:7

El resultado que queriamos. Seguro que a más un desarrollador web le parece esta viendo el ViewState ...

Por úlitmo, decir que no todas la clases son compatibles con la serializacion. La serialización XML no es compatible con objetos que implementan la interface IDictionary , un Hashtable por ejemplo.

Para poder serializar de forma binaria una clase esta debe estar marcada con el atributo Serializable.

Saludos, DJK

 


 Versión para imprimir  Foros de consulta


Añadir comentario ... Para preguntar utiliza los foros
Autor:

Título:


Para preguntar utiliza los foros.



 Versión para imprimir

Serialización: XmlSerializer y BinaryFormater
Autor: Pedro Herrarte Sánchez
Visitas: 2058 Fecha de publicación: 18/06/2009
Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación.

Posee mas de diez años de experiencia trabajando para las principales empresas de España.

Es especialista en tecnologías .NET, entornos Web, bases de datos (SQL Server y ORACLE) e integración de sistemas.

Es experto en desarrollo (C#, ASP.NET, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE).

Es fundador, diseñador y programador de www.devjoker.com.




Visitas: 112 | Comentarios: 3 | Archivo: Articulos
02/02/2010 iPad vs Telesketch
Visitas: 813 | Comentarios: 2 | Archivo: Articulos
Categorias: Humor
Visitas: 770 | Comentarios: 3 | Archivo: Articulos
Visitas: 3187 | Comentarios: 2 | Archivo: Articulos
Categorias: C#
Visitas: 14577 | Comentarios: 7 | Archivo: Articulos
Categorias: C#|Seguridad
Visitas: 1503 | Comentarios: 3 | Archivo: Articulos
Visitas: 698 | Comentarios: 2 | Archivo: Articulos
Visitas: 370 | Comentarios: 0 | Archivo: Articulos
Visitas: 2035 | Comentarios: 2 | Archivo: Articulos
Categorias: C#

Útimos temas recibidos en los foros ...
AYUDA URGENTE PARA CONSULTA ENTRE DOS TABLAS por pepe ... [SQL] 0 15/03/2010
CERTIFICACION CESANTIAS por linda ... [Actualidad] 0 15/03/2010
certificado pensiones horizonte por angela patricia rodriguez ... [Actualidad] 143 26/01/2010
Solicitud certificado de afiliaciones a pensiones y cesantias proteccion por hz ... [Actualidad] 62 10/02/2010
certificado de pensiones del bbva horizonte por danger ... [Actualidad] 127 12/01/2010
certificacion cesantias porvenir por martha perez ... [Actualidad] 6 04/03/2010
cerificado fondo horizonte de pensiones y cesantias por carlos fideligno torres herrera ... [Actualidad] 148 18/01/2010
certificado de afiliacion por EDDY ... [Actualidad] 0 14/03/2010
Cursores por nopodes ... [ORACLE] 0 14/03/2010
peticion urgente mi nombre es juan pablo osorio cardona cc 71115218 por juancho ... [Actualidad] 0 14/03/2010
peticion por juancho ... [Actualidad] 0 14/03/2010
estrato de pencion por carlos antonio mateus gomez ... [Actualidad] 0 14/03/2010

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
19/09/2007 Triggers en Transact SQL    forma parte de...Tutorial de Transact SQL
05/07/2007 Consultar datos en Transact SQL    forma parte de...Tutorial de Transact SQL
21/07/2006 Funciones integradas de PL/SQL    forma parte de...Tutorial PL/SQL
02/09/2007 Procedimientos almacenados en Transact SQL    forma parte de...Tutorial de Transact SQL
14/05/2007 Fundamentos de Transact SQL    forma parte de...Tutorial de Transact SQL
10/06/2007 Multiples escritorios en Windows XP
22/10/2005 El lenguaje SQL    forma parte de...Tutorial SQL
22/10/2005 Introducción SQL    forma parte de...Tutorial SQL
28/06/2006 Procedimientos almacenados en PL/SQL    forma parte de...Tutorial PL/SQL
11/10/2006 Métodos    forma parte de...Tutorial C#

 

Encuesta
¿A que perfil te adaptas mejor?




[Ver] [Votar]