Sunteți pe pagina 1din 35

5

Serializare

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

Ce este serializarea?
Serializarea este procesul prin care convertim un obiect intr-o secventa liniara de bytes (octeti) care poate fi stocata sau transferata. Deserializarea este procesul invers serializarii.

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

Ce este serializarea?

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

Cum serializam un obiect?

PAS1: Cream un stream spre care vom directiona serializarea. PAS2: Cream un obiect BinaryFormatter PAS3: Folosim metoda BinaryFormatter.Serialize
ex: string data = data de salvat; FileStream fs = new FileStream (data.out, FileMode.Create); BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(fs,data); fs.Close();
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

Cum deserializam un obiect?

PAS1: Cream un stream din care vom citi PAS2: Cream un obiect BinaryFormatter PAS3: Cream un obiect in care vom salva datele deserializate PAS4: Apelam metoda BinaryFormatter.Deserialize
ex: FileStream fs = new FileStream(data.out, FileMode.Open); BinaryFormatter bf = new BinaryFormatter(); string data = (string)bf.Deserialize(fs); fs.Close();
11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

Cum cream clase ce pot fi serializate?


Pentru ca o clasa sa fie serializabila trebuie adaugat atributul [Serializable] la clasa. Putem controla serializarea si deserializarea pentru a obtine rezultatele dorite.

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

ex:
[Serializable] class ObiectCumparat { public int productID; public decimal pret; public int cantitate; public decimal total;
public ObiectCumparat(int productID, decimal pret, int cantitate) { this.productID = productID; this.pret = pret; this.cantitate = cantitate; total = pret*cantitate; } }
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

Cum oprim serializarea unor anumiti membri?

Observam ca variabila total este calculata prin inmultirea valorilor pret si cantitate, deci stocarea sa pe disc este inutila si va ocupa spatiu suplimentar. Putem in schimba sa actualizam aceasta variabila dupa deserializare. Pentru a realiza acest lucru platforma .NET contine:
atributul [NonSerialized] pe care il punem inaintea definiri variabilei si care va instrui serializatorul sa nu o serializeze interfata IDeserializationCallback ce contine metoda IDeserializationCallback.OnDeserialization ce va fi apelata cand se termina deserializarea.
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

clasa ObiectCumparat devine:


[Serializable] class ObiectCumparat: IDeserializationCallback { public int productID; public decimal pret; public int cantitate; [NonSerialized] public decimal total; public ObiectCumparat(int productID, decimal pret, int cantitate) { this.productID = productID; this.pret = pret; this.cantitate = cantitate; total = pret*cantitate; } } void IDeserializationCallback .OnDeserialization(Object sender) { total = price * cantitate; }

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

Versionare

O problema ce poate sa apara la serializare este compatibilitatea cu versiunile anterioare. Daca versiunea 1.0 a aplicatiei noaste foloseste un format de clasa si versiunea 1.1 mai adauga un camp ce va fi serializat/deserializat pot sa apara probleme. Pentru a rezolva problema putem folosi atributul [OptionalField] pt. membrii noi adaugati. Acesta nu afecteaza procesul de serializare. La deserializare daca nu va fi gasit in streamul de intrare runtime-ul nu va da eroare dar va seta valoarea variabilei optionale ca null sau valoarea default pentru tipul respectiv.
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

10

In versiunea 1.1 a clasei ObiectCumparat aceasta va avea urmatoarea forma:


[Serializable] class ObiectCumparat: IDeserializationCallback { public int productID; public decimal pret; public int cantitate; [NonSerialized] public decimal total; [OptionalField]public int taxe; } public ObiectCumparat(int productID, decimal pret, int cantitate) { this.productID = productID; this.pret = pret; this.cantitate = cantitate; total = pret*cantitate; } void IDeserializationCallback .OnDeserialization(Object sender) { total = price * cantitate; }

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

11

Versionare

Sfaturi pentru o versionare corecta:


Nu eliminati niciodata un camp serializat dintr-o versiune mai noua Niciodata nu aplicati atributul NotSerialized la o variabila la care nu era aplicat in o versiune anterioara Cand adaugati un camp nou declarati-l optional. Cand stergeti atributul NotSerialized adaugati atributul OptionalField Initializati la deserializare toate campurile optionale cu valori folositoare pentru aplicatia voastra.
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

12

Alegerea unui format de serializare

Platforma .NET include mai multe metode de formatare a datelor serializate:


BinaryFormatter: cea mai eficienta metoda de serializare date in .NET SoapFormatter: format bazat pe XML folositor pentru schimbul in retea de fisiere. Are sanse mai mari sa treaca de firewall-uri decat BinaryFormatter.

11/26/07

L4 .NET ADF - (C) Victor Adrian Prisacariu

13

Alegerea unui format de serializare


In general este recomandat sa folositi BinaryFormatter cand stiti ca toate aplicatiile ce vor deserializa sunt construite folosind platforma .NET. Folositi SOAPFormatter atunci cand doriti sa trimiteti datele serializate prin retea.

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

14

SOAPFormatter

Pentru a folosi SOAPFormatter procedati exact ca la BinaryFormatter.

ex: FileStream fs = new FileStream(data.in, FileMode.Open); SOAPFormatter bf = new SOAPFormatter(); string data = (string)bf.Deserialize(fs); fs.Close(); Pentru a obtine compatibiliate maxima intre aplicatia voastra si alte aplicatii ce vor deserializa datele puteti folosi atribute prin care sa controlati formatul datelor scrise in stream-ul de iesire. Pentru mai multe detali cititi la pagina 280 in cartea .NET .
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

15

Serializare XML

XML este un format standardizat, bazat pe text, pentru stocarea unor informatii ce pot fi citite usor de aplicatii. XML foloseste un format de organizare a datelor de tip arborescent. XML poate fi folosit pentru stocarea oricarui tip de date inclusiv documente, imagini, filme, muzica, etc. .NET framework ofera mai multe biblioteci pentru citire si scriere fisiere XML

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

16

Cand folosim serializare XML?

Este recomandat sa folositi serializarea XML atunci cand doriti interoperatibilitate, mai exact atunci cand doriti ca fisierele produse sau modificate de aplicatia voastra sa fie usor citibile de aplicatii ce nu sunt scrise in .NET In consecinta serializare XML are urmatoarele avantaje:
Interoperatibilitate mai mare Fisierele pot fi editate usor cu editoare normale text Versionare mai usoara
17

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

Cum serializam XML un obiect?

PAS1: Crearea unui stream care va tine obiectul serializat (sau a unui TextWriter sau a unui XmlWriter) PAS2: Crearea unui obiect XmlSerializer ce va primi ca parametru la constructor un tipul obiectului pe care il vom serializa PAS3: Apelarea metodei XmlSerializer.Serialize
ex: FileStream fs = new FileStream(data.out,FileMode.Create); XmlSerializer xmls = new XmlSerializer(typeof(DateTime)); xmls.Serialize(fs,DateTime.Now); fs.Close();
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

18

Cum deserializam XML un obiect?

PAS1: Creare stream de unde vom citi datele serializate PAS2: Creare obiect XmlSerializer (cu parametru la constructor tipul obiectului de deserializat) PAS3: Apelarea metodei XmlSerializer.Deserialize

ex: FileStream fs = new FileStream(data.out,FileMode.Create); XmlSerializer xmlDs = new XmlSerializer(typeof(DateTime)); DateTime dataTrecuta = (DateTime)xmlDs.Deserialize(fs); fs.Close();
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

19

Cum cream clase ce pot fi serializate XML?

Conditiile pe care trebuie sa le indeplineasca o clasa pentru a fi serializabila XML sunt:


clasa trebuie sa fie publica tot membrii serializati trebuie sa fie publici clasa trebuie sa aiba un constructor fara parametri nu trebuie sa aiba atributul Serializable membri privati sau protected vor fi sariti la serializare

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

20

Controlul formatului fisierului XML de iesire

Daca dorim interoperatibilitate cu alte limbaje de programare uneori este necesara schimbarea formatului in care se va scrie sau citi fisierul XML. Aceasta schimbare se face prin diferite atribute aplicate membrilor clasei ce va fi serializata/deserializata

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

21

public class ObiectCumparat


{ } public int productID; public decimal pret; public int cantitate; public decimal total; public ObiectCumparat() { }

Fisierul XML rezultat dupa serializare va avea urmatorul continut: <?xml version 1.0> <ObiectCumparat> <productID>100</productID> <pret>1000</pret> <cantitate>10</cantitate> <total>1212</total> </ObiectCumparat>

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

22

Controlul formatului fisierului XML de iesire

Exemple de atribute (pentru o lista completa vedeti pagina 293 din cartea .NET ADF):
XmlAttribute: Membrul va fi serializat ca atribut XML XmlElement: Membrul va fi serializat ca un element XML XmlIgnore: Membrul va fi ignorat XmlRoot: Este folosit pentru a specifica optiuni despre namespace si numele elementului

Daca atributele nu sunt suficiente pentru a obtine formatul dorit, puteti creea propriul serializator XML implementand IXmlSerializable cu metodele ReadXml si WriteXml.
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

23

ex: [XmlRoot(ObiectDeCumparat)
public class ObiectCumparat { [XmlAttribute] public int productID; public decimal pret; public int cantitate; [XmlIgnore] public decimal total; public ObiectCumparat() { } } <?xml version 1.0> <ObiectDeCumparat productID=100> <pret>1000</pret> <cantitate>10</cantitate> </ObiectDeCumparat>
11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

24

XML Schema

Atunci cand 2 aplicatii schimba intre ele fisiere XML, acestea respecta in general o anumita maniera de organizare numita schema. Pentru mai multe info despre Xml schema: http://www.w3.org/XML/Schema .NET framework contine o aplicatie ce genereaza automat clase dupa o anumita schema (xsd.exe).Cand veti instantia o astfel de clasa fisierul XML generat din ea va respecta schema respectiva. E o metoda mai simpla si typesafe de a parsa si a scrie un document XML care sa respecte un anumit format.

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

25

XML Schema

Pentru a genera o clasa bazata pe o schema:


PAS1: Creati sau copiati schema (fisierul .xsd) PAS2: Deschideti Visual Studio 2005 Command Prompt PAS3: Rulati comanda: xsd C:\schema\library.xsd /classes /language:CS PAS4: Folositi clasa nou creata (Schema.cs) in aplicatia voastra

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

26

Serializare custom
Serializare custom este procesul prin care controlati complet mecanismul de serializare si deserializare a unui obiect. Puteti realiza o interoperatibilitate mai mare si o versionare mai buna folosind serializarea custom.

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

27

Cum implementam o serializare custom?

Puteti modifica mecanismul .NET de serializare/deserializare mostenind interfata ISerializable si aplicand atributul Serializable la clasa. Mostenirea clasei ISerializable inseamna implementarea metodelor GetObjectData si a unui constructor special care va fi folosit la deserializare. Runtime-ul va apela metoda GetObjectData la serializare si acel constructor la deserializare. Compilatorul va va avertiza daca nu ati implementat GetObjectData, dar daca nu ati implementat constructorul doar la runtime se va arunca o exceptie la deserializare.

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

28

Cum implementam o serializare custom?


Metoda GetObjectData trebuie sa completeze un obiect de tip SerializationInfo cu datele pe care doriti sa le serializati din clasa. Tot ce trebuie sa faceti este sa adaugati valorile de serializat ca perechi nume/valoare (ca la o colectie) folosind metoda AddValue Metoda AddValue creeaza intern un obiect de tip SerializationEntry

11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

29

[Serializable] class ObiectCumparat : ISerializable { public int productID; public decimal pret; public int cantitate; [NonSerialized] public decimal total; protected ObiectCumparat(SerializationInfo info, StreamingContext context) { this.productID = info.GetInt32(Product ID); this.pret = info.GetDecimal(Pret); this.cantitate = info.GetInt32(Cantitate); this.total = pret*cantitate; }
} [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue(Product ID,productID); info.AddValue(Pret,pret); info.AddValue(Cantitate,cantitate); }

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

30

Evenimente in serializare

Atunci cand folositi BinaryFormatter .NET framework poate declansa anumite evenimente in diferite momente ale procesului de serializare.

Serializare incepe

[OnSerializing]

Se face serializarea propriu-zisa

Serializarea s-a terminat

[OnSerialized]

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

31

Evenimente in deserializare
Deserializarea incepe [OnDeserializing] Deserializarea are loc

Deserializarea s-a terminat

[OnDeserialized]

IDeserializationCall back. OnDeserialization

11/26/07

L3 .NET ADF - (C) Victor Adrian Prisacariu

32

Evenimente

Pentru a putea raspunde la aceste evenimente trebuie sa construiti metode ce primesc ca parametru un StreamingContext, au ca atribut tipul de eveniment la care raspund si nu returneaza nimic:
ex: [OnDeserializing] void CalculareTotal(StreamingContext sc) { total = pret*cantitate; }
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

33

StreamingContext

Obiectul StreamingContext este folositor atunci cand doriti o serializare/deserializare diferita in functie de destinatia obiectului. ex: in general nu e nevoie sa serializati informatii despre procesul in curs pentru ca ele vor fi invechite la deserializare. Totusi daca deserializatorul este chiar procesul in curs aceasta pot fi foarte folositoare Aceasta informatie este stocata in StreamingContext
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

34

StreamingContext

StreamingContext are 2 proprietati:


Context: o referinta la un obiect care contine orice informatie dorita de programator legata de informatiile de context State: un set de biti care indica sursa sau destinatia obiectelor serializate sau deserializate
File: sursa sau destinatia este un fisier CrossProcess: sursa sau destinatia este alt proces pe aceeasi masina CrossMachine: sursa sau destinatia este alt proces pe alta masina etc.
11/26/07 L3 .NET ADF - (C) Victor Adrian Prisacariu

35