Tags: , , , , , | Categories: asp.net, Dynamic Data Posted by Admin on 12/18/2010 7:43 PM | Comments (7)

Merhabalar, Dynamic Data Preview 4 ile birlikte daha önce müdahale etmemiz güç olan bir çok noktada açıklığa kavuştuk. Örneğin daha önce MetaTable sınıfı sealed(mühürlenmiş) olarak işaretlendiğinden bu sınıftan nesne türetemiyorduk. Bu yazıda MetaModel, MetaTable ve MetaColumn sınıfları türetip kendimize göre özelleştireceğiz. Örnek olması ve faydalı bir yazı olması adına tablo isimleri ve tablonun içindeki sütunları kullanıcı diline uygun hale getiren kodlamayı yapacağız.

Bilindiği üzere dynamic data tablolar için hazırladığı sayfalarda tablo ve sütun adlarını olduğu gibi gösteriyor. Özellikle her bir kolon için ayrı ayrı DisplayName özniteliğini tanımlamamız gerekiyor. Bu yazıda tek bir dosyadan DisplayName atamalarını yapabildiğimiz gibi başlıktan da anlaşılacağı üzere çoklu dil desteğini de yazmış olacağım. Örneğin veritabanında ID olarak tanımlanmış bir alan dynamic data tarafında da ID olarak görüntülenir. Bu alan için türkçe arabirimi için Kimlik Numarası yazarken ingilizce arabiriminde Identification Number yazdırabileceğiz. Yazı boyunca aşağıdaki iki tabloyu kullanacağım.

İlk etapda çeviri bilgilerini tutacak bir ortam belirlemek gerekiyor. Tabiki veritabanında saklamak en doğrusu olacaktır ancak burada yaptığım geliştirmenin diğer projelerimde de kullanılabilir olması gerektiğini düşündüğüm için ek bir tablo koplayama masrafını göze almıyorum ve bu işi ufak bir xml dosyası üzerinden halletmeyi uygun görüyorum. Aslında ilk etapda resource file ile yapmayı düşünmüştüm ancak class library içerisinden resource dosyalarıyla çalışmak biraz sorun oldu. Bu yüzden önce xml dosyasını hazırlayalım. Xml dosyasında nesne tipi, eşsiz adı ve görüntüleme adı yer alacak. Aşağıdaki xml dosyası üzerinden yazıya devam edelim. 


<?xml version="1.0" encoding="utf-8" ?>
<globalization>
  <dbobjects>
    <dbobject type="t" name="Soru" value="Soru Kayıtları" />
    <dbobject type="t" name="Personel" value="Personel Kayıtları" />
    <dbobject type="c" name="Soru.SoruID" value="Soru Nu" />
    <dbobject type="c" name="Soru.Baslik" value="Başlık" />
    <dbobject type="c" name="Soru.Aciklama" value="Açıklama" />
    <dbobject type="c" name="Personel.PersonelID" value="Personel Nu" />
    <dbobject type="c" name="Personel.Adi" value="Personelin Adı" />
    <dbobject type="c" name="Personel.Soyadi" value="Personelin Soyadı" />
  </dbobjects>
</globalization>

 

type niteliğindeki "t" alanı tablo "c" alanı da kolon tipini, "name" kısımı eşsiz adı "value" da görüntüleme adını saklıyor. name kısımı biraz daha abartılıp db ve şema bilgileri de yazılabilir ancak şuan önemsemiyorum. Xml dosyası(tr-TR.xml) hazır olduğuna göre şimdi bu bilgileri okuyup istediğimiz zaman bize söyleyebilecek bir sınıf yazmaya başlayalım.

namespace DynLibrary.Helpers
{
    using System;
    using System.Collections;
    using System.Configuration;
    using System.Data;
    using System.IO;
    using System.Web.Hosting;

    public static class GlobalizationHelper
    {
        /// 
        /// Globalizasyon değerlerini saklıyacak olan koleksiyon
        /// 
        private static Hashtable _globalizationList;

        /// 
        /// Veritabanı nesneleri için yapılacak globalizasyon değerlerini
        /// _globalizationList koleksiyonuna aktaracak olan metot
        /// 
        private static void LoadDbObjects()
        {
            string configFolder = ConfigurationManager.AppSettings["DynamicDataConfigFolder"];
            string fullDbObjectsPath = Path.Combine(HostingEnvironment.MapPath(configFolder), "Globalization");

            // Dynamic data ile ilgili ayarların saklı olduğu klasörden
            // glabalizasyonla alakalı klasördeki xml dosyalarını getir
            string[] fileNames = Directory.GetFiles(fullDbObjectsPath, "*.xml");

            DataSet ds;
            string gKey = string.Empty;

            foreach (var fileName in fileNames)
            {
                ds = new DataSet();

                // Xml dosyasını oku
                ds.ReadXml(Path.Combine(fullDbObjectsPath, fileName));

                if (ds.Tables["dbobject"].Rows.Count > 0)
                {
                    foreach (DataRow row in ds.Tables["dbobject"].Rows)
                    {
                        // _globalizationList koleksiyonu tüm çeviri değerlerini
                        // saklayacağından her bir anahtarın eşsiz olması gerekiyor
                        // bunun için anahtar isimlerini dbobjects.tr-TR.TabloAdi.KolonAdı
                        // şeklinde atamayı şimdilik yeterli görüyorum
                        gKey = string.Format(
                                                "dbobjects.{0}.{1}.{2}",
                                                row["type"], // t, c
                                                Path.GetFileNameWithoutExtension(fileName), // tr-TR, eUS
                                                row["name"] // TabloAdi, TabloAdi.KolonAdi
                                            );

                        // Anahtar ile değer birlikte koleksiyona yazılıyor. Eğer daha
                        // önceden yazılmışsa(Bu metotun tekrar yükleme(update) işlemi
                        // içinde çağırılabileceği düşünülerek) önceki değerin üzerine yaz
                        if (!_globalizationList.Contains(gKey))
                            _globalizationList.Add(gKey, row["value"]);
                        else
                            _globalizationList[gKey] = row["value"];
                    }
                }
            }
        }

        /// 
        /// contsr
        /// 
        static GlobalizationHelper()
        {
            _globalizationList = new Hashtable();

            LoadDbObjects(); // Veritabanı nesneleriyle alakalı çevirileri yükle
        }

        /// 
        /// _globalizationList koleksiyonundan değer okuyacak metot
        /// 
        /// 
        /// 
        /// Değer bulunamadıysa dönderilecek varsayılan değer
        /// 
        /// 
        public static string GetValue(string key, string defaultValue)
        {
            // Koleksiyonda istenen anahtar yoksa defaultValue değişkenini dönder
            if (!_globalizationList.Contains(key))
                return defaultValue;

            // Koleksiyondan okunan değeri dönder
            return Convert.ToString(_globalizationList[key]);
        }

        /// 
        /// Veritabanı nesneleri çevirilerini okumak için
        /// kolaylaştıcı metottur. GetValue metotu çağırılır.
        /// 
        /// table_name.column_name
        /// Değer bulunamadıysa dönderilecek varsayılan değer
        /// 
        public static string GetDbObjectValue(string objectType, string objectName, string defaultValue)
        {
            // UICulture değerini alınıyor
            string uiCultureName = System.Threading.Thread.CurrentThread.CurrentUICulture.CompareInfo.Name;

            // Anahtar oluşturuluyor
            string key = string.Format(
                                       "dbobjects.{0}.{1}.{2}",
                                       objectType, // TabloAdi, TabloAdi.KolonAdi
                                       uiCultureName, // tr-TR, en-US
                                       objectName
                                   );

            // GetValue metotundan ilgili değer okunup dönderiliyor
            return GetValue(key, defaultValue);
        }
    }
}

 


Xml dosyası ve onu okuyup istediğimiz zaman çeviri okuyabileceğimiz sınıf tamamlandığına göre şimdi sıra geldi dynamic datayı kalbinden vurmak.  Bu yazıda kullanılacağı kadarıyla Dynamic data arkaplanda MetaModel adı verilen bir nesneyi kullanıyor. MetaModel nesnesi içinde MetaTable(CreateMetaTablenesnesi, MetaTable nesnesi içinden de MetaColumn(CreateMetaColumnnesnesi üretiliyor. Bizim yapmamız gereken iş ise bu üç  sınıfının yaptığı işleri üstlenecek sınıflar yazmak ve dynamic data'ya bu sınıfları kullan demekten ibaret. Globalizasyon işini yani nesnelerin ingilizce ve türkçe isimlerini de MetaTable ve MetaColumn nesnelerinin DisplayName özelliğini ezerek xml dosyasından okutacağız.

MetaModel sınıfı kaynak kodları:

namespace DynLibrary.Entities
{
    using System.Web.DynamicData;
    using System.Web.DynamicData.ModelProviders;

    /// MetaModel nesnesinden türetilen DynMetaModel nesnesi
    public class DynMetaModel : MetaModel
    {
        public DynMetaModel()
            : base()
        {
        }

/// Tablo nesnesini oluşturan metottur. Bu metotta MetaTable yerine kendi /// nesnemiz olan ve MetaTable nesnesinden türemiş olan DynMetaTable /// nesnesini üretiyoruz. protected override MetaTable CreateTable(TableProvider provider) { return new DynMetaTable(this, provider); } } }

 

MetaTable sınıfı kaynak kodları:

namespace DynLibrary.Entities
{
    using System.Web.DynamicData;
    using System.Web.DynamicData.ModelProviders;
    using DynLibrary.Helpers;

    /// MetaTable nesnesinden türetilen DynMetaTable nesnesi
    public class DynMetaTable : MetaTable
    {
        public DynMetaTable(MetaModel metaModel, TableProvider tableProvider)
            : base(metaModel, tableProvider)
        {
        }

/// Kolon nesnesini oluşturan metottur. Bu metotta MetaColumn yerine kendi /// nesnemiz olan ve MetaColumn nesnesinden türemiş olan DynMetaColumn /// nesnesini üretiyoruz. protected override MetaColumn CreateColumn(ColumnProvider columnProvider) { return new DynMetaColumn(this, columnProvider); }

/// Görüntüleme adını dönderen sınıfı ezen özellik public override string DisplayName { get { return GlobalizationHelper.GetDbObjectValue("t", this.EntityType.Name, base.DisplayName); } } } }

MetaColumn sınıfı kaynak kodları:

 

namespace DynLibrary.Entities
{
    using System.Web.DynamicData;
    using System.Web.DynamicData.ModelProviders;
    using DynLibrary.Helpers;
    public class DynMetaColumn : MetaColumn
    {
        public DynMetaColumn(MetaTable metaTable, ColumnProvider columnProvider)
            : base(metaTable, columnProvider)
        {
        }
        /// 
        ///  Görüntüleme adını dönderen sınıfı ezen özellik
        /// 
        public override string DisplayName
        {
            get
            {
                // TODO: check for displane, uihint etc...
                string key = this.Table.EntityType.Name + "." + this.Name;
                return GlobalizationHelper.GetDbObjectValue("c", key, base.DisplayName);
            }
        }
    }
}

 

Gerekli üç sınıfın kodlamasını tamamladıktan sonra geriye dynamic data'ya DynMetaModel nesnemizi kullanması gerektiğini söylemek kalıyor. Bunun için global.asax dosyasında yapılan tanımlamayı aşağıdaki gibi değiştirmemiz gerekiyor.

 

// Eski hali: MetaModel model = new MetaModel();
DynMetaModel model = new DynMetaModel();



 

Yapılması gereken son kodlama da buydu. Sonuc olarak artık türkçe dili kullanan kullanıcılar tablo ve kolon adlarını türkçe ve okunabilir görebilecekler. Tabiki diğer diller için de aynı şey söz konusu. Aşağıda kodlamadan önce, kodlamadan sonra türkçe ve kodlamadan sonra ingilizce arayüz görüntüleri mevcuttur.

İlk hali:

 



Kodlama sonrası - Türkçe


 


Kodlama sonrası - İngilizce

 

 

Faydalı olması dileğiyle, iyi çalışmalar mutlu kodlar!
Ömer Faruk ZORLU

Kahve ısmarlayın

Aşağıdaki kahve simgesine tıklayarak bana paypal üzerinden kahve ısmarlayabilirsiniz. Kahveye olan düşkünlüğü ile bilinen birisi olarak büyük bir zevkle içeceğimden emin olabilirsiniz.


Comments (7) -

Ege UTKUCU
Ege UTKUCU on 10/12/2011 4:00 AM Öncelikle vakit ayırıp bu yazıyı bizimle paylaştığınız için teşekkürler. Ben projeyi uyguladığımda birkaç sorunla kaşılaştım

ilk 2 sorunumum mantığı aynı

DynMetaModel in createtable kısmıda
ve DynMetaTable ın createcolumn kısmanda
no suitable method found to override hatası alıyorum

diğer 2 hatam ise şöyle

DynMetaTable ın get kısmında
ve DynMetaColumn ın get kısmında
'Blog.Entities.DynMetaTable.DisplayName.get': cannot override inherited member 'System.Web.DynamicData.MetaTable.DisplayName.get' because it is not marked virtual, abstract, or override

hatası alıyorum .Net 4.0 ile çalışıyorum vakit bulduğunuz bir ara gözatarsanız sevinirim ben baya uğraştım aklımı baya kurcaladı ama bulamadım.
Şimdiden teşekkürler iyi çalışmalar
&#214;mer Faruk ZORLU
Ömer Faruk ZORLU on 10/15/2011 10:10 PM Merhabalar Ege, bu kodlamayı .net fw 3.5 ile yazmıştım. Dynamic data projesini .net4 demi oluşturdun yoksa daha önceki bir projeden upgrade mi ettin?

Aldığın hatalar eski sürüm dynamic data referansları ile çalıştığından kaynaklanıyor olabilir çünkü .net4 öncesi bazı sınıflar sealed imzalıydı ve türetilemiyordu. Aldığın hatada ise kalıtım başarılı ancak metotu ezemeyeceğini söylüyor. Referansları kontrol ettikten sonra sorun devam ederse bu konuda benimle tekrar iletişim kurabilirsin.

Ege UTKUCU
Ege UTKUCU on 10/16/2011 11:21 PM öncelikle vakit ayırıp sorunumla ilgilendiğiniz için teşekkür ediyorum
projeyi .net 4.0 da oluşturdum

DynMetaModel in createtable kısmıda
ve DynMetaTable ın createcolumn kısmında aldığım
no suitable method found to override hatasındaki kodlar şu şekildeydi

protected override MetaColumn CreateColumn(ColumnProvider columnProvider)
protected override MetaTable CreateTable(TableProvider provider)

buralardali override kısımları virtual yaptığımda hata almadım ancak getlerdeki hata devam ediyor
&#214;mer Faruk ZORLU
Ömer Faruk ZORLU on 10/17/2011 11:02 AM Tekrar merhaba Ege,
Visual Studio 2010 da yeni bir proje oluşturup tek bir sınıf ekledim. Aşağıdaki gibi DisplayName'in get'ini ezdim ve sorunsuz derleniyor. Sorunu çözemiyorsan akşam vakitlerinde uzaktan bağlanıyım, birde beraber bakalım. Tabi uygunsan Smile

İyi çalışmalar.

[code]
using System.Web.DynamicData;
using System.Web.DynamicData.ModelProviders;

namespace WebApplication1
{
    public class Class1 : MetaTable
    {
        public Class1(MetaModel metaModel, TableProvider tableProvider)
            : base(metaModel, tableProvider)
        {
        }

        public override string DisplayName
        {
            get
            {
                return "OMR-" + base.DisplayName;
            }
        }
    }
}
[/code]
&#214;mer Faruk ZORLU
Ömer Faruk ZORLU on 10/17/2011 11:03 AM Tekrar merhaba Ege,
Visual Studio 2010 da yeni bir proje oluşturup tek bir sınıf ekledim. Aşağıdaki gibi DisplayName'in get'ini ezdim ve sorunsuz derleniyor. Sorunu çözemiyorsan akşam vakitlerinde uzaktan bağlanıyım, birde beraber bakalım. Tabi uygunsan Smile

İyi çalışmalar.

[code]
using System.Web.DynamicData;
using System.Web.DynamicData.ModelProviders;

namespace WebApplication1
{
    public class Class1 : MetaTable
    {
        public Class1(MetaModel metaModel, TableProvider tableProvider)
            : base(metaModel, tableProvider)
        {
        }

        public override string DisplayName
        {
            get
            {
                return "OMR-" + base.DisplayName;
            }
        }
    }
}
[/code]
Ege UTKUCU
Ege UTKUCU on 10/18/2011 5:18 PM Denedim ama olmadı yine benim visual studiomdan kaynaklanan bir sorunmu acaba diye düşünüyorum br akşam müsait olduğunuzda uzaktan bağlanabilirseniz iyi olur çünkü dün gece ckfinder ekledim projeme onda da hata verdi muhtemelen visual studio ile ilgili
&#214;mer Faruk ZORLU
Ömer Faruk ZORLU on 10/18/2011 9:42 PM Tamamdır, sana eposta gönderdim. Kontrol edebilirsen sevinirim.

Add comment




biuquote
Loading