Koray Kırdinli

Yazılım ve İş Yaşamı Hakkında Paylaşımlar

C# ile Serilizasyon ve Deserilazasyon

Bir çok uygulama bir nesne içerisinde veriyi saklamaya veya transfer etmeye ihtiyaç duyar. Bunu .NET içerisinde yapmanın en kolay yolu serilizasyondur. 3 tip serileştirme tekniği vardır. Bunlar Binary, SOAP ve XML Serilization.
Bir uygulamada veriyi memory’de serileştirip saklamak , network üzerinden transfer etmek ve tekrardan nesneyi oluşturmak serilizasyon ve deserilizasyon ile mümkündür.
Serilizasyon bir nesneyi alıp bir dizi lineer byte dizisine çevirme işlemidir diyebiliriz.
Serilizasyon sınıfları System.Runtime.Serialization namespace’i altındadır.

Serilizasyon nerede işimize yarar:
Eğer bir nesneyi bir dosyaya serileştirme yapmadan yazıp daha sonra okumak istersek bu sefer nesnenin property’lerini manuel olarak set etmemiz gerekecek fakat serilizasyon işleminde nesneyi olduğu gibi geri alabilmek mümkün.
Diğer bir örnek: Bir nesneyi farklı bir bilgisayarda çalışan bir programa network üzerinden bu nesneyi gönderebilir , remoote uygulamada bu nesneyi deserilize edip işlemlerini yapabilir.
Windowsta bir nesneyi clipboard’a kopyaladığımızda,web servislerinde,remoting yaparken serilizasyon  yapmaktadır.

Basit olarak bir binary serileştirme işleminin adımlarını yazacak olursak.
1- Stream nesnesi oluşturulur ( File veya MemoryStream)
2- BinaryFormatter nesnesi oluşturulur
3- Formatter’ın serialize metodu çağrılır ve stream kapatılır.

string data = “Koray Kırdinli”;

FileStream fs = newFileStream(“SerializesString.Data”, FileMode.OpenOrCreate);

BinaryFormatter bf = newBinaryFormatter();

bf.Serialize(fs, data);
fs.Close();

Fakat yukarıdaki işlemde serilizasyon yapmak çok efektif değil düz bir şekilde dosyaya da yazabilirdik. Serilizasyon daha kompleks işlemlerde asıl faydasını göstermekte yani nesneleri. Örneğin bir teks değilde DateTime’ı serilize etmek örnek olarak verilebilir.

Desirilazasyon işlemi ise serilizasyonun tam tersidir. Aşağıdaki kod yardımı ile serilize ettiğimiz bir nesneyi geri almamız mümkün.

FileStream fs = newFileStream(“SerializesString.Data”, FileMode.Open);

BinaryFormatter bf = newBinaryFormatter();

string data = (string)bf.Deserialize(fs);

fs.Close();
Kendi yazdığımız bir sınıfı da Serilizable niteliği sayesinde serilize edilebilir hale getirebiliriz. Ayrıca serilizasyon işlemi System.Security.Permissions namespace’i altındaki SecurityPermission niteliğine ihtiyaç duyar. Default olarak bu policy’ye internetten indirilen veya intranet bir kod parçasında izin verilmez fakat  lokal makinada izin verilir. Bunun sebebi ise gizli veriyi koruma altına almaktır.

[Serializable]

publicclassShoppingCartItem : IDeserializationCallback

{

    publicint ProductId;

    publicdecimal Price;

    publicint Quantity;

    [NonSerialized] publicdecimal Total; // Bu değer dinamik hesaplandığı için

    //ve verinin boytunu küçültmek için serilize etmiyoruz.

 

[OptionalField] publicbool Taxable;

//Eğer bir field’a OptionalField niteliğini eklersek bu field daha önce serilize

//edilmiş veride olmasa bile uygulama hata fırlatmaz. Versiyon uyumluluğu için kullanılabilir.

 

#region IDeserializationCallback Members

//Bu sınıfın nesnesi deserilize olurken IDeserializationCallback interface’ini

//implement edip OnDeserialization eventi içerisinde hesaplatma işlemini yapıyoruz.

        publicvoid OnDeserialization(object sender)

        {

            Total = Price * Quantity;

        }

#endregion

    }
.NET Framework serilize edilmiş veriyi formatlamak için System.Runtime.Serialization namespace’i altında 2 formatlayıcı barındırıyor. İkisi de IRemotingFormatter interface’ini implemente eder.
BinaryFormatter : System.Runtime.Serialization.Formatters.Binary namespace’i altındadır. Eğer serilize eden ve deserilize eden uygulama .NET ile yazılmışsa kullanılmalıdır.
SoapFormatter : System.Runtime.Serialization.Formatters.Soap namespace’i altındadır.Eğer deserilize edecek uygulama .NET ile yazılmamışsa kullanmak mantıklıdır. Ayrıca Firewall’lardan daha rahat geçer. Yani network uygulamalarında daha başarılıdır.Kullanmak için System.Runtime.Serialization.Formatters.Soap.dll ‘i uygulamaya referans vermek gereklidir. Binary Formatter ile serileştirilmiş veriyi okuması daha zor iken Soap ile serileştirilmiş veri xml tabanlı daha düzgün bir şekilde okunabilir.

ShoppingCartItem entity = newShoppingCartItem(1, 100m, 10, 1000);

FileStream fs = newFileStream(“SerializeSoap.Data”, FileMode.OpenOrCreate);

SoapFormatter bf = newSoapFormatter();

bf.Serialize(fs,entity);

fs.Close();

 

 

1

100

10

false

 

 

 
ShoppingCartItem entity = newShoppingCartItem();

FileStream fs = newFileStream(“SerializeSoap.Data”, FileMode.Open);

SoapFormatter bf = newSoapFormatter();

entity = (ShoppingCartItem)bf.Deserialize(fs);

fs.Close();

MessageBox.Show(

    String.Format(“Pid:{0},Price{1},Quantity={2},TOTAL={3}”,

    entity.ProductId,entity.Price,entity.Quantity,entity.Total));
XML serileştirme veriyi farklı sistemlerin veri alışverişini sağlayabilmek amacıyla oluşturulmuş XML yapısında saklamaktadır..NET içerisinde XML dökümanına yazma ve okuma için bir çok sınıf mevcuttur. System.Xml.Serialization namespace’i altında serileştirme sınıflarını bulabilirsiniz.
Peki ne zaman Xml serileştirme kullanmalıyız :  Eğer deserilize edecek uygulama .NET değil ve nesne olduğu gibi serileştirilecek ise XML serileştirme kullanılabilir. Bu yöntem text tabanlı olduğu için bütün işletim sistemlerinde ve uygulama ortamlarında kolayca okunabilir. Ayrıca bir notepad gibi basit bir araçla bile kolayca okunabilir. Özellikle uygulamaları customize etmekte oldukça kullanışlıdırlar.

FileStream fs = newFileStream(“SerializeDate.xml”, FileMode.OpenOrCreate);

XmlSerializer xs = newXmlSerializer(typeof(DateTime));

xs.Serialize(fs, DateTime.Now);

fs.Close();

MessageBox.Show(DateTime.Now.ToLongTimeString());

FileStream fs = newFileStream(“SerializeDate.xml”, FileMode.Open);

XmlSerializer xs = newXmlSerializer(typeof(DateTime));

DateTime date = (DateTime)xs.Deserialize(fs);

fs.Close();

MessageBox.Show(date.ToLongTimeString());   

 

Bir sınıfı aşağıdaki şekilde Xml serilizasyona uygun hale getirebiliriz.

[XmlRoot(“Cart”)]

publicclassCartItem

{

    [XmlAttribute] publicInt32 productId;

    publicdecimal price;

    publicInt32 quantity;

    [XmlIgnore] publicdecimal total;

}
Eğer iki farklı uygulama xml dosyaları paylaşacaklar ise developer’lar xml standartlarını ortak olarak belirleyebilmek için xml schema’lardan yararlanırlar.Xml schema xml dökümanının yapısını belirler.Xml schemaları oluşturmak için xsd.exe gibi bir araçtan faydalanılabilir.Veya standart olarak .NET içerisindeki XmlReader ve XmlWriter sınıflarından yararlanılabilir.

Bir dataseti ister yukarda anlattığımız yöntem ile ya da myDataSet.WriteXml(“DataSet.xml”); metodu ile direk olarak serilize edebiliriz.

Custom Serilization : Bir sınıfı ISerilizable sınıfının GetObjectData metodunu override ederek default serilizasyonu kullanmadan custom bir serilizasyon yapabiliriz. Bu bir nesnenin geçersiz bir elemanı olduğunda işimize yarayabilir.
GetObjectData metonunda parametre olan SerilizationInfo nesnesi içerisine elemanları doldurmak gereklidir.Bu elemana name/value çifti olarak elemanlar yerleştirilir.

 

 

 

 
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]

publicvoid GetObjectData(SerializationInfo info, StreamingContext context)

{

    info.AddValue(“Product Id “, productId);

    info.AddValue(“Price”,price);

    info.AddValue(“Quantity”, quantity);

}

 

Serilizasyon işlemlerinde istediğimiz aşamada veriye müdahale etme şansımız bulunmaktadır. Bunu xml nitelikleri ile yapabiliyoruz.
[OnSerializing] : Sınıf içerisine bir metoda bu tagı eklersek o metod nesneyi serilize ederken çalışır.

[OnSerialized] : Serilizasyon işlemi bittikten sonra çalışır.

[OnDesilizating] : Desilize işlemi nesne deserilize işlemi yapılırken çalışır.

IDesirilizationCallback,OnDesilization()
[OnDesirialized] : Deserilize işlemi bitince çalışır.

[Serializable]

publicclassCustomer

{

    publicInt32 productId;

    publicdecimal price;

    publicInt32 quantity;

    publicdecimal total;
//Bu metodalar parametre olarak StreamingContext almak ve void return etmek //zorundadırlar.

    [OnSerializing]

    void CalculateTotal(StreamingContext sc)

    {

        total = price * quantity;

    }

 

    [OnDeserialized]

    void CheckTotal(StreamingContext sc)

    {

        if (total == 0) CalculateTotal(sc);

    }

}

May 17, 2010 - Posted by | C# | , , ,

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s