Haz 3 2009

Enterprise Library – Caching Application Block ile performansı artırmak

Category: Yazılım AraçlarıTürkay @ 02:48

Merhaba arkadaşlar;

Bu makalede, Enterprise Library içinde bulunan Caching Application Block kütüphanesini nasıl kullanacağımıza bir bakacağız. Tabii ki bir örnek eşliğinde...

Öncelikle, caching hakkında biraz konuşalım isterseniz. Veritabanı ile çalışan uygulamalarda; sıkça rastlanan sorunlardan biri verinin istemciye gösterimi sırasında meydana gelen yavaşlamadır. Bu yavaşlamanın kaynağı birçok şey olabilir. Bunlardan birkaçına değinmek gerekirse; çekilen verinin büyük olması, veritabanının istemci dışında bir lokasyonda olması en başta gelir. Cache mekanizması işte bu noktada devreye girer. Ön belleğe almak olarak türkçeye çevirebileceğimiz "caching", şöyle çalışır; veri, yerel makinenin (istemci) RAM'inde belirli bir süre saklanır. Bu sayede aynı veriyi bir daha görmek istediğinizde kaynak veritabanı değil RAM olacaktır. Kısacası, veri sadece bir kez veritabanından çekildiğinden, uygulamada performans artışı sağlanacaktır.

Bu kısa bilgiden sonra, bir Windows Application açarak örnek uygulamamıza geçebiliriz. Bu arada ben, bu uygulamada northwind veritabanını kullandım.

Uygulamamıza ilk önce app.config dosyası ekleyerek işe başlayalım. Bu konfigürasyon dosyasına connectionStrings etiketini yerleştirerek aşağıdaki gibi yapılandıralım:

       <connectionStrings>

         <add name="db" connectionString="Data Source=.;Initial Catalog=Northwind;Integrated Security=True"

          providerName="System.Data.SqlClient" />

       </connectionStrings>

Bu noktada şunu belirtmek istiyorum; Enterprise Library veri tabanı ile çalışırken, connectionString bilgisinin konfigürasyon dosyalarında (app.config ya da web.config) saklanmasına ihtiyaç duyar. Bunun dışında bu connectionString elemanlarının, providerName özelliği de verilmek zorundadır. Teknik olarak bunun sebebi, Enterprise Library içindeki hemen hemen bütün nesnelerin Factory Design Pattern ile üretilmesidir.

Devam edelim... app.config dosyasındaki değerlerin okunabilmesi için, System.Configuration referansını projeye olarak ekleyelim (Projeye sağ click, Add Reference, .NET Sekmesi).

Ardından, veritabanından veri çekmekle görevli bir class oluşturaralım:

       public class CalisanlarVeriSaglayici

       {

          public DataTable TumCalisanlar()

          {

            /*

             * Bu metodun görevi, veritabanına bağlanarak

             * Employees tablosundaki kayıtları getirmektir.

             *

             */

             string connStr = ConfigurationManager.ConnectionStrings["db"].ConnectionString ;

             SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Employees", connStr);

             DataTable dt = new DataTable();

             da.Fill(dt);

             return dt;

           }

         public byte[] CalisanResmi(int EmployeeID)

        {

          /*

           * Bu metod ise, veritabanına bağlanarak

           * verilen employeeID bilgisine göre çalışanın

           * resmini getirmektedir.

           */

           object resim=null;

           SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["db"].ConnectionString);

           SqlCommand cmd = new SqlCommand("SELECT Photo FROM Employees WHERE EmployeeID=@id ", conn);

           cmd.Parameters.AddWithValue("@id", EmployeeID);

           conn.Open();

           try

           {

              resim = cmd.ExecuteScalar();

             //Cache mekanizmasının çalışıp çalışmadığını gözlemlemek üzere, resim çekme işlemini 2 saniye geciktireceğiz.

              System.Threading.Thread.Sleep(2000);

           }

           finally

           {

            conn.Close();

           }

           if (resim==null || resim.GetType()==typeof(System.DBNull))

           {

              return null;

           }

           return (byte[])resim;

         }

       }

Gerçi açıklama satırında da belirttim ama, gözden kaçırılmasını da istemiyorum. Bu örnek uygulama, yerel veritabanı üzerinde çalışacağından veriler elbette çok hızlı gelecektir. Bu nedenle, en azından resim bilgisini alırken, hızı yavaşlatmak için System.Threading.Thread.Sleep(2000) kodunu kullandım.

Şimdi sıra geldi, veriyi gerektiğinde cache içine atacak ve öncelikli olarak cache'den veri almaya çalışacak bir class oluşturmaya. Fakat bu class'ı oluşturmadan önce yapmamız gereken bir kaç şey daha var. Projemizin referanslarına bu kez Enterprise Library Caching Application Block referansını ekleyelim.

Bu dll dosyasını ekledikten sonra, caching için app.config dosyasında bir etiket daha yapılandırmamız gerekiyor. Enterprise Library, bu işi yapabilmemiz için bize bir editör geliştirmiş. app.config dosyasına sağ tıklayıp "Edit Enterprise Library Configuration" seçeneğini işaretleyerek bu editörü açalım.

Burada konfigürasyon dosyasına sağ tıklayarak açılan menüden New | Caching Application Block komutunu verelim.

Bu komut, app.config dosyasında caching konfigürasyonu için yeterlidir. Bu işlemden sonra, app.config dosyasına aşağıdaki etiketin eklendiğini gözlemleyebilirsiniz:

       <cachingConfiguration defaultCacheManager="Cache Manager">

         <cacheManagers>

           <add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"

            numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"

            type="Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager, Microsoft.Practices.EnterpriseLibrary.Caching, Version=4.1.0.0,  Culture=neutral, PublicKeyToken=31bf3856ad364e35"

            name="Cache Manager" />

         </cacheManagers>

      </cachingConfiguration>

Tamamdır. Artık cache işlemlerini üstlenecek bir class oluşturabiliriz.

Dosyanın üst kımına aşağıda belirttiğim namespace bilgisini ekliyoruz:

       using Microsoft.Practices.EnterpriseLibrary.Caching;

... ve clasımız:

       public class CalisanCache

       {

         private CalisanCache()

         { }

         public static DataTable CalisanlariGetir()

         {

          CalisanlarVeriSaglayici cv = new CalisanlarVeriSaglayici();

          DataTable dt = cv.TumCalisanlar();

          return dt;

         }

         public static Bitmap CalisanResmi(int employeeID)

         {

           byte[] resim = null;

           //Öncelikle cache'de resim olup olmadığını kontrol ediyoruz:

           ICacheManager cache = CacheFactory.GetCacheManager();

           resim = (byte[])cache[employeeID.ToString()];

           //eğer cache'de resim yoksa:

           if (resim == null)

           {

              //veritabanına bağlanarak resim bilgisini alırız.

              CalisanlarVeriSaglayici cv = new CalisanlarVeriSaglayici();

              resim = cv.CalisanResmi(employeeID);

              //ardından bu resmi cache'e ekliyoruz:

              cache.Add(employeeID.ToString(), resim);

           }

          //eğer db'de de resim yoksa

          if (resim == null)

          {

             return null;

          }

          using (MemoryStream ms = new MemoryStream())

          {

             /*

              * resim nesnesi doluysa, bu byte dizimizi MemoryStream nesnemize yazdırıyoruz.

              * Daha sonra bu nesneyi Bitmap nesnesine dönüştürüyoruz.

              */

              ms.Write(resim, 78, resim.Length - 78);

              return new Bitmap(ms);

          }

        }

        public static void CacheTemizle()

        {

            ICacheManager cache = CacheFactory.GetCacheManager();

            cache.Flush();

        }

Burada CalisanResmi() isimli metot, önce cache nesnesini kontrol etmektedir. Eğer cache'de çalışanın resmi yoksa veritabanına gidip, oradan resmi çekmekte ve bu resmi cache içine atmaktadır. Böylece bu metod şunu garanti ediyor; aynı personel resmini ikinci kez görmek istediğimizde, veritabanına değil cache nesnesine gidecek ve resmi oradan getirecek.

Bu class içinde yine dikkat çekmek istediğim bir yer var... MemoryStream nesnesine byte[] değerini yazarken dizinin başından ve sonundan 78 elemanı çıkarttığıma dikkat etmişsinizdir. Bunun sebebi, Northwind veritabanında yer alan çalışan resimlerinin içinde ilk ve son 78 eleman, resim dışında notlar içeriyor olmasıdır. Yani bu durum sadece northwind ile alakalıdır.

Artık bu class da bittiğine göre, Form'umuzu aşağıdaki gibi tasarlayabiliriz..

Son olarak, formumuzun koduna geçiyoruz:

       private void Form1_Load(object sender, EventArgs e)

       {

         cmbCalisan.DataSource = CalisanCache.CalisanlariGetir();

         cmbCalisan.DisplayMember = "LastName";

         cmbCalisan.ValueMember = "EmployeeID";

        }

        private void cmbCalisan_SelectedValueChanged(object sender, EventArgs e)

        {

           try

           {

               this.Cursor = Cursors.WaitCursor;

               pictureBox1.Image = CalisanCache.CalisanResmi(Convert.ToInt32(cmbCalisan.SelectedValue));

               this.Cursor = Cursors.Default;

            }

          catch { }

       }

Uygulamayı test etmek için şunu yapın; projeyi çalıştırdıktan sonra, her çalışanı birer kez görün ve iki saniye beklediğinizi gözlemleyin. Ardından daha önce seçtiğiniz çalışanlardan birini tekrar seçin. Bu kez hiç beklemediğinizi fark edeceksiniz. Çünkü veri bu kez cache içinden geliyorJ

İşte Enterprise Library'nin başarılı bir katmanını böylece örneklemiş olduk.

Kendinize çok iyi bakın

turkay@turkayurkmez.com

Tags: , , ,

10 kişi tarafından 3.8 olarak değerlendirildi

  • Currently 3,8/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Yorumlar

Yorum ekle


(Gravatar simgesini gösterecek)

  Country flag

biuquote
  • Yorum
  • Canlı önizleme
Loading