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(CreateMetaTable) nesnesi, MetaTable nesnesi içinden de MetaColumn(CreateMetaColumn) nesnesi ü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
37b6bb1b-9a94-4146-8369-290adab1a688|1|5.0