1. A webszolgáltatások
1.4. XML-szerializáció
1.4. XML-szerializáció
Ha jól figyeltünk, felismerhetjük, miről is van szó a SOAP kapcsán. A függvény paramétereit ugyanúgy szerializálni kell a meghíváshoz, mint ahogy a függvény visszatérési értékét is. Sajnos a http protokoll nem támogatja a bináris adatforgalmat, mivel a http protokoll igazából nem erre lett kitalálva.
A szerializáció itt nem bináris, hanem XML-szerializáció. A problémái hasonlóak, mint a 9.1. fejezet kapcsán említettek. Az ott ismertetett módszerek (Serializable, Optional, NonSerialized attribútumok, OnDeserialization metódus) az XML-szerializáció kapcsán nem alkalmazhatóak, illetve hasztalanok. Ezek mind a bináris szerializációs és deszerializációs folyamat sajátosságai.
Az XML-szerializáció az alábbi szabályokkal írható le:
• csak a publikus mezők és propertyk értékeivel foglalkozik,
• nem tartalmaz típusinformációkat,
• amely osztályt szerializálni szeretnénk, abban lenni kell alapértelmezett (paraméter nélküli) konstruktornak,
• a publikus propertyknek írható és olvasható műveletekkel is kell rendelkeznie, a csak olvasható propertyk értéke nem kerül szerializálásra.
1.4.1. XML-szerializáció tesztelése
using System.Xml.Serialization;
using System.Xml;
FileStream file = new FileStream(@"c:\teszt.xml", FileMode.Create);
XmlSerializer xs = new XmlSerializer ( typeof ( int ) );
XmlTextWriter xmlTextWriter = new XmlTextWriter ( file, Encoding.UTF8 );
//
int a = 12;
xs.Serialize ( xmlTextWriter, a );
file.Close();
Az eredményül kapott XML fájl az alábbit fogja tartalmazni:
<?xml version="1.0" encoding="utf-8"?>
<int>12</int>
A bináris szerializáció kapcsán is kipróbált városok, személyek, házaspárok alkotta lista szerializácója azonban nem fog sikerülni egy komoly probléma miatt: az XML-szerializáció nem támogatja a körkörös hivatkozású adatok szerializációját! Ha még emlékszünk rá, a 9.6. ábrán bemutatott kapcsolatrendszer szerint a házastársak kölcsönösen tartalmazták egymás referenciáit. Ezen példán keresztül mutattuk be, hogy a bináris szerializációnak többek között ilyen jellegű kapcsolatrendszer kezelését is meg kell oldania. Nos, az XML-szerializációnak is meg kellene – de nem tudja. Ez többek között az XML dokumentum képességeire, illetve a SOAP nem alapos kidolgozottságára vezethető vissza. Ezért az eredeti példa (Lajos felesége Gizi, Gizi férje Lajos) XML-szerializációja esetén (egy elég szerencsétlenül semmitmondó) kivétel jelentkezik. A View detail...
linkre kattintva deríthető csak fel a tényleges hibaok: A circular reference was detected while serializing an object of type szemely körkörös hivatkozás volt az adatokban.
10.6. ábra. Az keletkezett kivétel
10.7. ábra. A kivétel részletező oka
Ezért megszüntetjük a körkörös hivatkozást az által, hogy Lajos esetén bejelöljük Gizit feleségként, de Gizinél nem adjuk meg Lajost férjként. Ne felejtsük el a varos és szemely osztályokat paraméter nélküli (alapértelmezett) konstruktorokkal bővíteni!
Eredménye az alábbi XML fájl lesz. Ha alaposabban elgondolkodunk ennek adattartalmán, világossá válik egy újabb probléma: a Lajos házastársa Gizi egy komplex adatstruktúra, mely leírja Gizi személyes adatait, születési helyét mint várost, de semmi sem utal arra, hogy ez az adattartalom igazából ugyanaz, mint a később (is) Gizi névvel leírt személy adatai. Tehát míg eredetileg a memóriában volt 3 személy, 2 város példány, addig az xml szerializációt helyreállító kód 4 személy és 4 város példányt fog a memóriába „kicsomagolni”, mivel ő mit sem tud arról, hogy a sok „Eger” város igazából ugyanazon példány.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfSzemely
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<szemely>
<nev>Lajos</nev>
<szul_ev>1970</szul_ev>
<ferfi_e>true</ferfi_e>
<szuletett>
<nev>Eger</nev>
<orszagKod>HU</orszagKod>
</szuletett>
<hazastarsa>
<nev>Gizi</nev>
<szul_ev>1974</szul_ev>
<ferfi_e>false</ferfi_e>
<szuletett>
<nev>Debrecen</nev>
<orszagKod>HU</orszagKod>
</szuletett>
</hazastarsa>
</szemely>
<szemely>
<nev>Gizi</nev>
<szul_ev>1974</szul_ev>
<ferfi_e>false</ferfi_e>
<szuletett>
<nev>Debrecen</nev>
<orszagKod>HU</orszagKod>
</szuletett>
<orszagKod>HU</orszagKod>
</szuletett>
</szemely>
</ArrayOfSzemely>
1.4.2. XML-deszerializáció tesztelése
A deszerializáció a fenti problémáktól eltekintve a forráskódban egyszerűen felírható.
FileStream file = new FileStream(@"c:\teszt2.xml", FileMode.Open);
XmlSerializer xs = new XmlSerializer(typeof(List<szemely>));
List<szemely> l = (List<szemely>)xs.Deserialize(file);
file.Close();
1.4.3. ISerialization
Az XML-szerializácó egyértelműbb működését érhetjük el, ha a szerializálandó osztályunk implementálja az ISerializable interfészt. Ez egyetlen függvény megírását kéri tőlünk, a GetObjectData metódust, de ugyanúgy feltételez (lényegében igényel) ugyanekkor egy speciális paraméterezésű konstruktort is, melynek pedig a deszerializáció kapcsán lesz majd jelentősége.
public szemely(SerializationInfo info, StreamingContext context) {
nev = (string)info.GetValue("neve", typeof(string));
szul_ev = (int)info.GetValue("szuletett", typeof(int));
}
//Serialization function.
public void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue("neve", nev);
info.AddValue("szuletett", szul_ev);
} }
A szerializáció ekkor nem a korábban ismertett módon zajlik, nincs semmi automatizmus. A GetObjectData metódusban az info paraméterhez kell név-érték párosokat hozzáadni, melyek ugyanebben a formában kerülnek
kiírásra az XML dokumentumba. Tehát amely mezőt (értéket) hozzáadjuk, az belekerül az XML-be, amit nem, az nem kerül bele. Az objektum teljes egészében dönthet tehát saját maga szerializációjáról.
Az ily módon képzett kimenetben az is előfordulhat, hogy egyes mezők értékei nem a C#-beli mezők neveivel, hanem a fejlesztő által választott azonosítókkal. Ez esetben a deszerializáció sem fog működni, de nem is kell.
Amikor a visszaolvasás következik, nem az alapértelmezett konstruktort fogja használni a rendszer, hanem a speciális paraméterezésűt. Ekkor ellentétesen eljárva az info listából kiemelve az elemeket, típuskényszerítve visszaállíthatóak az értékek.