Serialización de datos en C# en Binario, Soap y Xml

Serialización de datos en C# en Binario, Soap y Xml Quizás muchos desarrolladores hayan escuchado hablar del termino “serializar la información” y no

0 downloads 96 Views 489KB Size

Recommend Stories


Restador binario
Circuitos. Restadores y sumadores. Semirrestador

TIPOS DE DATOS COMPUESTOS ESTÁTICOS EN C
TIPOS DE DATOS COMPUESTOS ESTÁTICOS EN C Tipos de Datos Compuestos Estáticos en C UNIDAD 5: ARRAYS (listas y tablas) EN C 5.1 INTRODUCCIÓN Arregl

IBM i Versión 7.2. Base de datos Programación SQL XML
IBM i Versión 7.2 Base de datos Programación SQL XML  IBM i Versión 7.2 Base de datos Programación SQL XML  Aviso Antes de utilizar esta

High Pressure Soap Lance
Operating Instructions and Parts Manual High Pressure Soap Lance BUILT TO LAST Please read and save these instructions. Read carefully before attem

Story Transcript

Serialización de datos en C# en Binario, Soap y Xml Quizás muchos desarrolladores hayan escuchado hablar del termino “serializar la información” y no saber de que se trata. Pues bien, resulta que la serialización de datos no es otra cosa que transformar los datos de tal manera que pueda ser transferida por un canal (Internet, archivo plano, memoria, etc) a otro sistema. En otras palabras, si queremos compartir información de nuestro sistemas con otras aplicaciones o viceversa, tendremos que utilizar serialización de datos. De manera nativa, el Framework de .NET nos ofrece la posibilidad de serializar la información en tres formatos: Binario, Soap, Xml. La serialización en formato binario consiste en convertir la información a bytes y se utiliza comúnmente para los escenarios donde la información es transferida por la red hacia un sistema destino, el cual recibe dicha información

y

realiza

el

proceso

inverso

de

la

serialización

=

Deserializacion para construir el objeto (información) que fue transferido. La serialización en formato Soap consiste en convertir los datos en un “documento estándar” en el cual se incluirá además de los datos a serializar, una serie de información adicional que será utilizada por el sistemas destino para construir el objeto original. Esta serialización es la que se utiliza en escenarios con Web Services. Finalmente la serialización en formato Xml, consiste en transformar la información en un documento Xml que será interpretado por el sistema destino. Los formatos de serialización Binario y Soap están contenidos en el namespace System.Runtime.Serialization, mientras que el Xml esta en el namespace System.Xml.Serialization. Para ejemplificar cada escenario, supongamos que en nuestra aplicación se utiliza una entidad llamada Empleado definida como se muestra a continuación: public class Empleado { private int identificacion;

private string nombre; private string apellido; private int edad; private string telefono; private DateTime fechaIngreso; private int diasLaborables; public int Identificacion { get { return identificacion; } set { identificacion = value; } } public string Nombre { get { return nombre; } set { nombre = value; } } public string Apellido { get { return apellido; } set { apellido = value; } } public int Edad { get { return edad; } set { edad = value; } } public DateTime FechaIngreso { get

{ return fechaIngreso; } set { fechaIngreso = value; diasLaborables= (DateTime.Now.Subtract(fechaIngreso).Days); } } public string Telefono { get { return telefono; } set { telefono = value; } } public int diasLaborables { get { return diasLaborables; } set { diasLaborables = value; } } } Serialización en formato Binario Como se mencionó anteriormente, éste método se utiliza generalmente para intercambiar información con otros sistemas a través de la red. Sin embargo para agilidad en la ilustración de su funcionamiento, los datos serializados en este post, se enviarán a un archivo de texto para visualizar su contenido. Esta serialización tiene la desventaja que solo funcionará entre aplicaciones .NET, es decir, que tanto la aplicación que serializa como la aplicación que deserializa deben ser aplicaciones desarrolladas bajo la plataforma .NET.

El primer paso para serializar un objeto en .NET, es incluir el atributo Serializable en la definición de nuestra clase así: [Serializable] public class Empleado {…] Esto le indicará al runtime de .NET que este objeto estará habilitado para ser serializado cuando se requiera, de lo contrario, se generará una excepción del tipo System.Runtime.Serialization.SerializationException. Después, implementar la serialización binaria es tan sencillo como invocar el método Serialize de la clase BinaryFormatter que encontramos en el namespace System.Runtime.Serialization. Este método recibe como parámetros un Stream y el objeto que deseamos serializar, por ejemplo:

Si abrimos el archivo datoSerializado.txt, obtenemos:

Como se ve en la figura, la información obtenida después del proceso de serialización contiene una serie de caracteres especiales. Esto es porque en realidad estamos serializando en formato binario y el bloc de notas no esta en capacidad de interpretar este tipo de información. Sin embargo, en la vida real, se supone que ese stream es enviado a través de la red y recibido por una aplicación destino, la cual utilizará el método Deserialize del objeto BinaryReader para obtener el objeto Empleado que fue enviado inicialmente, así:

Lo cual da como resultado lo siguiente:

Profundizando un poco más en como el runtime de .NET serializa los datos, debemos saber que en tiempo de ejecución el runtime convierte en bytes cada uno de los miembros del objeto sin importar el tipo o nivel de acceso (public, private, protected, etc). Esto en algunas ocasiones puede no ser lo que deseemos hacer, sino mas bien omitir algunos campos que consideramos no son necesarios al momento de serializar. En nuestro ejemplo especifico, para que queremos serializar el campo díasLaborados si puede ser calculado en tiempo de ejecución?. Esto implica un costo que podemos evitar ya que a mayor cantidad de miembros a serializar, mayor cantidad de información tendrá que ser transferida por red o almacenada en disco. Para modificar el comportamiento de la serialización binaria, podemos utilizar el atributo NonSerialized en cada uno de los miembros que deseamos omitir, así: [NonSerialized] private int diasLaborables; Con esto logramos que el resultado de la serialización sea el siguiente:

Donde se puede ver que ya no existe ninguna información referente al miembro diasLaborables. Sin embargo, al momento de ejecutar la aplicación destino y deserializar el objeto, obtenemos lo siguiente:

Donde podemos observar que no se está calculando el valor del campo diasLaborados. Esto se debe a que el proceso de deserialización lo que hace

es “recrear” el estado del objeto serializado y como el campo diasLaborados no está incluido en la información serializada, es omitido en el proceso de deserialización. Por fortuna, existe la interfaz IDeserializationCallback, la cual incluye el método OnDeserialization que es llamado una vez termina el proceso de deserialización del objeto. Implementar esta interfaz solucionará nuestro problema ya que en dicho método podemos calcular el valor del miembro diasLaborados

y

así

garantizamos

que

siempre

que

se

realice

una

deserialización del objeto, se tendrá el estado completo del mismo. Para implementar la interfaz, se hace lo siguiente sobre el objeto Empleado: [Serializable] public class Empleado:IDeserializationCallback { //Definicon de miembros #region IDeserializationCallback Members public void OnDeserialization(object sender) { DiasLaborados = (DateTime.Now.Subtract(fechaIngreso).Days); } #endregion } Así, ejecutando nuevamente el código que se encarga de realizar la deserialización tenemos:

Serialización en formato SOAP.

La serialización en formato SOAP, consiste en utilizar un formateador especial que genera un documento SOAP con la información del objeto que deseamos serializar. Este formato de serialización es el utilizado en los servicios Web por su gran interoperabilidad entre sistemas ya que me permite tener los sistemas desarrollados bajo diferentes plataformas e incluso ejecutándose en diferentes plataformas (Linux, Windows, etc). Sin embargo, una de las desventajas que tiene este formato de serialización es que genera una gran cantidad de información al serializar nuestro objeto (debido a que se debe cumplir con el estándar de los documentos SOAP). Por este motivo, es necesario analizar que tipo de serialización utilizar en nuestra aplicación. Así entonces tenemos que la serialización binaria es la más eficiente pero sólo nos sirve para escenarios donde las aplicaciones están desarrolladas en .NET. Si por el contrario, necesitamos compartir nuestros datos con aplicaciones desarrolladas en otros lenguajes y además cumplir con el estándar SOAP, utilizaremos el formato SOAP y finalmente si lo que necesitamos es compartir información con aplicaciones desarrolladas en otros lenguajes pero no es necesario cumplir con ningún estándar, podemos utilizar el formato XML. Para serializar en formato SOAP, sólo se debe utilizar el formateador SoapFormatter

que

se

encuentra

en

el

namespace

System.Runtime.Serialization.Formatters.Soap, así:

Después de serializar obtenemos el siguiente resultado:

Como se ve en la figura, el comportamiento de la serialización en formato SOAP también se ve afectada por el uso del atributo NonSerialized

Serialización en formato XML. La serialización en formato XML consiste en transformar el objeto en un documento XML, donde por defecto, el nodo raíz será el tipo de dato que estemos serializando y sus miembros serán elementos de ese nodo raíz. La implementación de la serialización XML difiere un poco de las presentadas anteriormente ya que no se utiliza un formateador sino que se hace utilizando la

clase

XmlSerializer

que

se

encuentra

en

el

namespace

System.Xml.Serialization. Esta clase recibe como parámetro el tipo de dato que deseamos serializar. Por ejemplo:

De esta manera le estamos indicando al objeto XmlSerializer que deseamos serializar un objeto de tipo Empleado, el cual al momento de invocar el método Serialize, genera un documento XML como el siguiente:

Como se puede ver en la figura anterior, el miembro diasLaborados fue serializado. Esto es porque la serialización XML no se ve afectada por el atributo NonSerialized. Sin embargo, la interface IDeserializationCallback si aplica para el proceso de la deserialización del objeto. Para modificar el comportamiento de la serialización XML, se debe usar el atributo XmlIgnore sobre el miembro que deseamos omitir, así: [XmlIgnore] public int DiasLaborados { get { return diasLaborados;

} set { diasLaborados = value; } }

Es de notar que el atributo se ha utilizado sobre la propiedad DiasLaborados y no sobre el miembro diasLaborados. Esto es porque la serialización XML serializa únicamente los miembros públicos del objeto, por lo cual si usamos el

atributo

XmlIgnore

sobre

el

miembro

privado

diasLaborados,

el

XmlSerializer igual seguiría generando el elemento DiasLaborados en el documento XML. En el namespace System.Xml.Serialization, existen varios atributos que permiten modificar el comportamiento de la serialización XML y así obtener diferentes estructuras del documento XML generado. Uno de los atributos más usado es el XmlAttribute el cual se usa sobre cualquier miembro público y sirve para indicarle al runtime que dicho miembro lo genere como un atributo del nodo raíz y no como un elemento. Por ejemplo: [XmlAttribute] public int Identificacion { get { return identificacion; } set { identificacion = value; } } Luego de serializar nuevamente el objeto con el código ilustrado anteriormente, obtenemos:

Donde se ve claramente que el miembro Identificación es un atributo del nodo Empleado y no un elemento de dicho nodo como se había generado en el ejemplo previo. www.asociacionaepi.es

Sobrecarga de operadores en C# La sobrecarga de operadores en C# permite redefinir la acción de un operador en relación a una clase. En el ejemplo de hoy plantearemos una clase Vector y luego procederemos a redefinir el operador + para dicha clase. Luego cuando sumemos dos objetos de esa clase vector generaremos otro objeto de dicha clase que resulte de la suma de sus componentes. El empleo de la sobrecarga de operadores debe hacerse con mucho cuidado de no desvirtuar el concepto que representa dicho operador (por ejemplo sobrecargar el operador “-” para la clase Vector y que genere la suma de sus componentes). Vamos con un ejemplo de uso:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SobrecargaOperadores1 { class VectorEnteros { private int []vec;

public VectorEnteros() { vec = new int[5]; } public void Cargar() { for (int f = 0; f < vec.Length; f++) { Console.Write("Ingrese componente:"); vec[f] = int.Parse(Console.ReadLine()); } } public void Imprimir() { for (int f = 0; f < vec.Length; f++) { Console.Write(vec[f] + " "); } Console.WriteLine(); } public static VectorEnteros operator +(VectorEnteros v1, VectorEnteros v2) { VectorEnteros su = new VectorEnteros(); for (int f = 0; f < su.vec.Length; f++) { su.vec[f] = v1.vec[f] + v2.vec[f]; }

return su; } } class Program { static void Main(string[] args) { VectorEnteros v1 = new VectorEnteros(); Console.WriteLine("Carga del primer vector"); v1.Cargar(); VectorEnteros v2 = new VectorEnteros(); Console.WriteLine("Carga del segundo vector"); v2.Cargar(); Console.WriteLine("Primer Vector"); v1.Imprimir(); Console.WriteLine("Segundo Vector"); v2.Imprimir(); VectorEnteros vt; vt = v1 + v2; Console.WriteLine("Vector Resultante"); vt.Imprimir(); Console.ReadKey(); } } }

www.asociacionaepi.es

Delegados en C# Lo primero que te preguntas es que tipo de problema resuelven los delegados, o sea… para que debería aprender a usar delegados? Para responderte esta pregunta, lo mejor es ilustrarlo con un ejemplo: Supongamos que tenemos el siguiente método de ordenación.

public void Sort(IComparable[] items){ for(i=; i 28) || (month == 2 && day > 29)) return false; // Verifico los meses que no tienen 31 dias if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) return false; return true; } } public int Day { get { return day; } } public int Month { get { return month; } } public int Year { get { return year; } } //Metodo para comparar fecha, nota que esta clase tambien hereda //de IComparable public int CompareTo(object x) { Date d = x as Date; if (d == null) throw new ArgumentException(); // Uso operadores ternarios para comparar las fechas (asi me evito unos cuantos if else) return (d.Year > year || (d.Year == year && d.Month > month) || (d.Year == year && d.Month == month && d.Day > day)) ? -1 : (d.Year == year && d.Month == month && d.Day == day) ? : 1; } } class Program { //En el metodo Main es donde usamos las clases y

//programamos algunos metodos que vayamos a utilizar static void Main(string[] args) { //Creo el array de personas que voy a ordenar Persona[] personas = new Persona[] { new Persona("Tom", new Date(1, 11, 1988), 169), new Persona("Jio", new Date(31, 8, 1990), 170), new Persona("Simone", new Date(7, 9, 1991), 165), new Persona("Ruben", new Date(22, 10, 1988), 165) }; //Ordeno el array de personas Sort(personas); //Imprimo las personas despues de ordenarlas foreach (Persona p in personas) { Console.WriteLine("Nombre: {0} Date: {1}, {2}, {3}, Height: {4}", p.Name, p.Birthday.Day, p.Birthday.Month, p.Birthday.Year, p.Height); } Console.ReadKey(); } //Metodo de ordenacion sencillo //Puedes ver otros métodos de ordenación en post anteriores: static void Sort(IComparable[] items) { for (int i = ; i < items.Length - 1; i++) for (int j = i + 1; j < items.Length; j++) //Comparamos las personas usando el metodo CompareTo que implementamos if (items[i].CompareTo(items[j]) > ){ IComparable tmp = items[i]; items[i] = items[j]; items[j] = tmp; } } }

Como has visto hasta ahora, el método Sort se basa solo en el criterio definido por el método CompareTo de la clase que implemente IComparable (en este caso la clase Persona), pero que tal si quisiéramos tener diferentes criterios de ordenación para un mismo objeto? En nuestro caso, que tal si quisieramos ordenar un grupo de personas por orden alfabético? o por estatura?

Una alternativa

Para lograr esto se podría pensar en tener varios métodos de comparación dentro de la clase Persona, pero entonces ya el método Sort no nos serviría para comparar cualquier tipo que fuera IComparable, sino que la signatura sería static voidSort(Persona[] items) y por tanto tendríamos que escribir un

método Sort para cada tipo de objeto que vayamos a ordenar. El código cliente (el que está en el método Main) debería tener la posibilidad de escoger el criterio de comparación que desea utilizar, y es aquí donde el uso de delegados nos viene como anillo al dedo.

La solución usando delegados

Un delegado no es más que un tipo que recibe métodos con una signatura específica, al principo va a resultar un poco chocante si nunca te has visto en la necesidad de usarlo, porque no es muy común y muchos lenguajes no lo soportan, y la verdad a mi me tomó un poco de tiempo asimilar esto, así que si todavía no logras entender bien, te aconsejo que busques un poco más de información en el MSDN. La signatura de los delegados viene siendo de la siguiente forma:

public delegate [valor de retorno] Comparison([parametro 1], [parametro 2], ... , [parametro n]);

En nuestro caso el delegado que vamos a utilizar es:

public delegate int Comparison(object x, object y);

que devuelve un entero y recibe dos objetos, esto quiere decir que este delegado recibirá como argumento cualquier método que devuelva un int y reciba dos parámetros de tipo object. A mi no me gusta mucho utlizar object (ya que tenemos genericidad) pero es mejor en este caso para ilustrar su utilidad. Otra característica de los delegados es que lo podemos definir en cualquier parte del código, o sea, no tiene que estar dentro de una clase como los métodos, variables o propiedades, de hecho no tengo ni idea de como está implementado este tipo, pero apuesten a que voy a buscar después que termine este post… Una vez que insertemos el delegado en cualquier parte de nuestro código, modificamos el método Sort para que lo use:

static void Sort(Persona[] items, Comparison compare) { for (int i = ; i < items.Length - 1; i++)

for (int j = i + 1; j < items.Length; j++) //Comparamos usando el delegado if (compare(items[i],items[j]) > ) { Persona tmp = items[i]; items[i] = items[j]; items[j] = tmp; } }

Añadimos los métodos para comparar por nombre, por fecha de nacimiento y por altura a la clase Persona:

//Comparamos por nombre en orden alfabético public static int CompareByName(object x, object y) { Persona p1 = x as Persona; Persona p2 = y as Persona; //En C# se considera que una letra minuscula es menor que cualquier letra mayuscula //por eso tenemos que usar la propidad OrdinalIgnoreCase de la clase StringComparer return StringComparer.OrdinalIgnoreCase.Compare(p1.Name, p2.Name); } //Comparamos por altura de menor a mayor public static int CompareByHeight(object x, object y) { Persona p1 = x as Persona; Persona p2 = y as Persona; //El tipo float tiene un comparador por defecto, que es el que utilizamos return p1.Height.CompareTo(p2.Height); } //Comparamos por fecha de nacimiento como hacíamos en CompareTo public static int CompareByBirthday(object x, object y) { Persona p1 = x as Persona; Persona p2 = y as Persona; //El tipo float tiene un comparador por defecto, que es el que utilizamos return p1.Birthday.CompareTo(p2.Birthday); }

Ahora veamos como utlizar estos en el código cliente:

static void Main(string[] args) { Persona[] personas = new Persona[] { new Persona("Tom", new Date(1, 11, 1988), 169), new Persona("Jio", new Date(31, 8, 1990), 170), new Persona("Simone", new Date(7, 9, 1991), 165), new Persona("Ruben", new Date(22, 10, 1988), 165) }; //Pasamos como parámetro al delegado el método CompareByName

Sort(personas, Persona.CompareByName); //También se puede usar el nombre del método directamente sin pasarlo como parámetro //Sort(personas, new Comparison(Persona.CompareByName)); Console.WriteLine("Ordenando las personas en orden alfabético"); foreach (Persona p in personas) { Console.WriteLine("Nombre: {0}", p.Name); } Console.WriteLine(); Console.WriteLine("Ordenando las personas por fecha de nacimiento"); //Pasamos como parámetro al delegado el método CompareByBirthday Sort(personas, Persona.CompareByBirthday); foreach (Persona p in personas) { Console.WriteLine("Date: {0}, {1}, {2}",p.Birthday.Day, p.Birthday.Month, p.Birthday.Year); } Console.WriteLine(); Console.WriteLine("Ordenando las personas por altura"); //Pasamos como parámetro al delegado el método CompareByHeight Sort(personas, Persona.CompareByHeight); foreach (Persona p in personas) { Console.WriteLine("Height: {0}",p.Height); } Console.ReadKey(); }

Que tal si ahora nos piden que ordenemos a las personas por orden alfabético a partir de la segunda letra del nombre? Solamente tendríamos que añadir el método:

//Comparamos por nombre en orden alfabético a partir d la segunda letra public static int CompareFromSecondLetter(object x, object y) { Persona p1 = x as Persona; Persona p2 = y as Persona; //Usamos substring para comparar los nombres a partir de la segunda letra return StringComparer.OrdinalIgnoreCase.Compare(p1.Name.Substring(1), p2.Name.Substring(1)); }

y usarlo como:

Sort(personas, Persona.CompareFromSecondLetter);

Muchas gracias

www.asociacionaepi.es

Habilitar la depuración remota de eventos en las app de SharePoint Cuando estamos desarrollando apps para SharePoint, es posible depurar las app de tipo autohosted o provider hosted aunque no se encuentren en el servidor de SharePoint. Al utilizar un Service bus de Windows Azure, Visual Studio se comunica con el mismo servicio de Windows Communication Foundation (WCF) que los manejadores de evento remotos (remote event receivers y app event receivers) usan. De esta forma, se evitan problemas de red entre la app guardada en la nube y la app local y es posible depurar los eventos remotos. Para crear el service bus, necesitamos una cuenta de Windows Azure. Una vez hayamos entrado en la cuenta, en “Service bus”, le daremos a “crear”:

Habrá que escribir un nombre para el namespace del bus de datos y aceptar:

Hay que esperar un rato, mientras el Service bus se está activando:

Una vez que esté creada, hay que pinchar en ella y pinchar en “Información de conexión”:

Copiamos la “Cadena de conexión”:

En Visual Studio, hacemos clic derecho en el proyecto de la app y vamos a propiedades. En la pestaña de SharePoint, en la parte inferior, hay que marcar la casilla “Enable remote event debugging” y pegar la cadena de conexión:

Una vez hayamos hecho esto, podremos depurar eventos remotos en nuestra app. www.asociacionaepi.es

Get in touch

Social

© Copyright 2013 - 2024 MYDOKUMENT.COM - All rights reserved.