İş Zekası Hakkında Her Şey – 14
Unified Dimensional Model
SQL Server 2005 ile birlikte Microsoft Unified Dimensional Model (UDM) adı
verilen yeni bir teknoloji sundu. UDM yapısı OLAP sisteminin sunduğu
multidimensional storage ve preprocessed aggregate’lar gibi avantajların
tümünden faydalanırken, klasik OLAP sistemlerinin dezavantajlarından korunmak
amacıyla tasarlandı.
Yapı
UDM bir data mart’ın üzerinde konumlandırılan ve son kullanıcı açısından OLAP
sisteminden hiç bir farkı olmayan bir yapıdır. Bu yapısına karşın UDM’in en
önemli avantajlarından biri aslında bir data mart’a gereksinim duymamasıdır.
UDM’i bir ya da daha fazla OLTP sistemini destekleyecek şekilde
tasarlayabiliriz. Aynı zamanda data mart ve OLTP sistemlerin bir arada bulunduğu
karma bir yapı da oluşturmanız mümkündür. UDM farklı veritabanı
sağlayıcılarından hatta XML formatındaki verilerden de faydalanabilmektedir.
UDM measure, dimension, hiyerarchy, hem star hem snowflake yapısındaki
küpleri hatta doğrudan OLTP sisteminden gelen tabloları barındırabilir. Bu esnek
yapı bir data mart tasarımı yapmadan business intelligence çözümleri
üretebilmemizi sağlasa da, bir data mart tasarımı yapmanın faydalı olduğu
durumlar elbette bulunmaktadır ki bu durumları ilerleyen bölümlerde detaylı
olarak ele alıyor olacağız.
Veri Kaynakları
UDM bir ya da daha fazla veri kaynağı tanımlaması ile başlar. Veri kaynakları,
UDM’e veri sağlayacak bir ya da daha fazla veritabanı bağlantısına ilişkin
bilgileri barındırır. Veri kaynağı sunucu adını, veritabanı adını ve kullanıcı
bilgilerini bir kaç ek bilgi ile birlikte kapsar. Oracle, MySQL gibi pek çok
farklı veritabanı sağlayıcısına bağlantı kurabilmemizi sağlayan farklı OLE DB
providerları bulunmaktadır. Bu sayede BI platformumuz SQL Server dışındaki
veritabanı sağlayıcılarından da faydalanabilmektedir.
Data View’lar
Veri kaynakları tanımlandıktan sonra kullanılacak tablo ve alanların
tanımlandığı data view oluşturulur. Data View’lar farklı veri kaynaklarından
gelen tablo ve fieldları bir araya getirebilir. Örneğin sipariş yönetim
sisteminden gelen tablolar, satış yönetim sisteminden gelenlerle
birleştirilebilir. Data View’ların sunduğu bu çoklu veri kaynağı desteği, UDM’in
ismindeki “Unified” ifadesinin temelidir.
Tablo ve fieldlar data view’a eklendikten sonra data view, veritabanında yer
alan ve gereksinim duymadığımız maddelerin filtrelenmesinde kullanılabilir. Data
View’a sadece BI çözümünde gereksinim duyulacak tablo ve fieldlar eklenir. Veri
kaynaklarındaki tablo yapısı değişmez. Data view, sonraki adımlarda nelerin
oluşturulabileceğini doğrudan yönetir.
Bu özellikle veri kaynaklarının çok büyük ve yüksek derecede normalizasyonun
söz konusu olduğuy OLTP sistemlerinde oldukça faydalıdır. Data View sadece
measure, dimension ve hiyerarchy’ler için gereksinim duyulan tabloları
kullanılabilir halde tutarak ihtiyaç duyulmayan verilerin oluşturacağı gereksiz
kalabalığın önüne geçer. Aynı şekilde tabloların içinde yer alan gereksinim
duyulmayan fieldlar görüntülenmez.
Data View’ı daha kolay anlaşılabilir hale getirmek için tablo ve fieldlarda
kullanıcı dostu isimler ve açıklamalar kullanılabilir. Bu metadata UDM’in
tümünde kullanılır. Bu fieldların kullanımı ile oluşturulan tüm measure,
dimension ve hierarchy’ler, bu kullanıcı dostu isim ve açıklamaları kullanırlar.
Ek olarak, data view’ı veri modeline sanal eklemeler yapmak için de
kullanabiliriz. Bu eklemeler, veritabanının kendisinde değil, sadece UDM içinde
yer alan sanal modelde oluşturulur. Bu sayede gerekli durumlarda bu eklemeleri
OLTP sistemine hiç bir müdahalede bulunmadan oluşturabilir, değiştirebilir ve
silebiliriz.
Sanal eklentilere örnek vermek gerekirse, veritabanında iki tablo arasında
tanımlanmamış bir ilişkinin tanımlanmasından bahsedebiliriz. Başka örnek ise
tabloya eklenecek hesaplanmış bir alan olabilir. Farklı veritabanlarından gelen
fieldlar ile yapılacak hesaplamalar ya da farklı fieldlardaki metinsel ifadeleri
kullanarak oluşturulan metinsel ifadeler, hesaplanmış alanları sıklıkla
kullandığımız noktalardan biridir.
Data View tamamlandıktan sonra, içeriği measure, dimension, hierarchy ve küp
oluşturma işleminde kullanıma hazırdır.
Şu ana kadar UDM ile BI modellemesinde 2 aşamadan bahsettik. Önce veri
kaynaklarını, sonrasında ise data view tasarımını gerçekleştirdik.

Proaktif Önbellekleme (Proactive Caching)
UDM, Geleneksel OLAP sistemlerinin sunduğu performans avantajını sağlamak için
preprocessed aggregate’ları kullanır. Yüksek erişebilirlik için bu preprocessed
aggregate’lar bir proactive cache’de tutulur.
Bu yapı sadece gerektiğinde oluşturulduğundan ve sadece kaynak veri modelinde
değişiklik olduğunda değiştirildiği için tercih edilmiştir. Kullanılan bu yapı,
IIS’in web sayfalarını önbelleklemek için kullandığı altyapıya oldukça
benzemektedir.
UDM caching mekanizmasının diğer caching mekanizmalarından ve IIS’te yer alan
caching mekanizmasından farkı, proaktif olmasıdır. IIS’te sayfa sadece ilk
erişimde cache’e aktarılır. İlk kullanıcı bu aktarım nedeniyle makul bir süre
beklemektedir.UDM’de ise, bir talep olması beklenmeksizin caching
gerçekleştirilir. UDM veri kaynağında ileride oluşacak değişiklikleri monitör
eder. Caching seçeneklerinde belirtilen zamanda UDM cache’i siler ve güncel
verilerle yeniden oluşturur.
Proactive caching MOLAP, ROLAP ve HOLAP yapılarında kullanılabilir. UDM bu
mimarilerden hangisini kullanmanız gerektiği konusunda size yardımcı olarak
doğru kararı vermenizi kolaylaştırır. Karar sürecinde dikkat etmemiz gereken en
temel noktalar “responsiveness” ve “latency”dir.
Xml Tanımlamaları
UDM’de yapılan tüm tanımlamalar XML dosyalarında saklanır. Her veri kaynağı,
data view, dimension ve küp tanımlaması kendi xml dosyasında tutulur. Bu XML
dosyalar doğrudan veri içermezler. XML dosyaları sadece tanımlamaları içerir.
Kısaca bu XML dosyaları, UDM’in kaynak kodudur.
Avantajlar
UDM geleneksel OLAP mimarileri ile karşılaştırıldığında pek çok avantaj
sunmaktadır. En temel avantajları vurgulamak gerekirse;
Transactional Veriye Dayanan OLAP Mimarisi
UDM OLAP küplerinin doğrudan transactional veri ile oluşturulmasına izin verir.
UDM kesin bir star ya da snowflake data mart’a gereksinim duymaz. Bunun yerine
iyi yapılandırılmış, ilişkisel bir veritabanı yeterli olur.
Bu OLTP sistemlerdeki verilerin Data Mart’a aktarımına duyulan gereksinimi ve
ETL yazma sırasında oluşan zaman kaybını ortadan kaldırır ki bu zamanla birlikte
uygulama sürecinin basitleştirilmesi ve daha düşük proje bütçeleri anlamına da
gelmektedir.
Son Derece Düşük Gecikme (Latency)
OLAP sistemini doğrudan OLTP sistemlerine dayandırarak data warehouse
sistemlerde ortaya çıkan gecikme en aza indirgenmiş olur. Gerçekte gerçek
zamanlı ya da neredeyse gerçek zamanlı performans elde edebiliriz. Ancak elbette
gerçek zamanlı iş zekası çözümlerini, OLTP sistemlerde oluşturacağı iş yükünü
göz önünde bulundurarak planlamamız gerekir.
Oluşturma ve Bakım Kolaylığı
UDM mimarisi OLAP projelerinin oluşturulmasındaki karmaşıklığı ortadan kaldırır.
UDM data mart gereksinimini ortadan kaldırarak veri oluşturma, transformation ve
load işlemlerini oluşturmak için harcanan zaman ve iş gücünü asıl işimiz olan iş
zekası’na yönlendirmemizi sağlar. Sadece bu bile, UDM’i diğer OLAP sistemlerine
tercih etmemiz için yeterli bir gerekçedir.
Source Control ile Tasarım Versiyonlaması
UDM içindeki her nesnenin kendi xml dosyasında tutulması sayesinde, UDM içindeki
her nesnenin versiyonlaması, source safe benzeri bir source control mekanizması
ile yürütülebilir. Source control mekanizması nesnelerdeki değişiklikleri takip
eder ve gerekli durumlarda karşılaştırma ve roll back imkanı sunar. Bu bir BI
projesinde özellikle geliştirme aşamasında oldukça faydalı bir özelliktir.
Sırada
Yazı dizisinin sonraki bölümünde teoriye biraz ara vereceğiz ve geliştirme
ortamını tanıyarak, BI çözümlerine doğru ilk adımımızı atacağız.
İş Zekası Hakkında Her Şey – 13
Mimari
OLAP sisteminin en temel parçası küp ve içerdiği önceden hesaplanmış değerlerdir (preprocessed aggregates). OLAP sistemleri küp verilerini barındırmak için 3 temel mimariden birini kullanır. Her mimarinin farklı avantaj ve dezavantajları vardır. Aşağıdaki şekilde bu sistemlerin avantaj ve dezavantajlarını görebilirsiniz.

Relational Olap (ROLAP)
Relational OLAP küp verilerini çok boyutlu bir veritabanında saklar. Leaf-level measure’lar ilişkisel küp için veri kaynağı görevini üstlenmiş olan data mart’ta barındırılır. Preprocessed aggregate’lar da bir ilişkisel veritabanı tablosunda barındırılırlar.
Bir karar verici, belirli bir kaç değeri öğrenmek istediğinde, ROLAP sistemi önce dimension üyesinin bir hesaplama mı değer mi içerdiğine bakar. Hesaplama içeriyorsa değer ilişkisel tablodan, değer içeriyor ise data mart’tan alınır.
ROLAP mimarisi, ilişkisel veritabanlarına dayanan yapısı nedeniyle diğer OLAP mimarilerine kıyasla çok daha büyük boyutlarda veri barındırabilir. ROLAP mimarisi leaf-level değerleri doğrudan data mart’tan aldığından dolayı, ROLAP sisteminden dönen leaf-level değerler her zaman data mart’ın kendisi kadar güncel olacaktır. Bir başka söylemle, ROLAP sistemi leaf-level veriler söz konusu olduğunda herhangi bir gecikme ile karşılaşmamıza neden olmamaktadır. ROLAP sisteminin dezavantajı ise aggregate ve leaf-level değerlerin okunmasının diğer OLAP mimarilerine kıyasla daha yavaş olmasıdır.
Multidimensional OLAP (MOLAP)
Multidimensional OLAP (MOLAP) hem küp verisini ROLAP mimarisindeki gibi bir multidimensional veritabanında barındırır. Bununla birlikte hem preprocessed aggregate değerler hem de leaf-level değerlerin bir kopyası multidimensional veritabanında barındırılır. Bu nedenle, tüm talepler multidimensional veritabanından cevaplanır ki bu da MOLAP sistemlerin son derece yüksek tepki süresine sahip olmasının en temel nedenidir.
MOLAP sistemine veri yükleme işlemi gerçekleştirilirken leaf-level veriler de multimensional veritabanına kopyalandığından bekleme süresi daha uzun olmaktadır. Bu yapı nedeniyle, MOLAP sisteminden dönen leaf-level değerler, data mart ile farklılık gösterebilmektedir. MOLAP sistemi leaf-level değerleri multidimensional veritabanında barındırdığından daha fazla disk alanına gereksinim duymaktadır.
Hybrid OLAP (HOLAP)
Hybrid OLAP (HOLAP) mimarisi ROLAP ve MOLAP mimarilerinin bir karışımıdır. HOLAP her iki mimarinin avantajlarından faydalanmak ve zayıf yönlerinden kaçınmak amacıyla tasarlanmıştır.
HOLAP mimarisi küp ve preprocessed aggregate değerlerini multidimensional veritabanında barındırır. Bu, aggregate değerlerin okunma hızını son derece yüksek tutar. Bununla birlikte HOLAP yapısı leaf-level değerleri küp için veri kaynağı rolünü üstlenen ilişkisel data mart’ta barındırır. Bu leaf-level değerlerin okunması için ek zaman gereksinimini ve datamart ile küp arasındaki değer farklılıklarının önüne geçmemizi sağlar.
Dezavantajlar
OLAP sistemlerinin iş zekası çözümleri açısından sundukları pek çok avantaj olsa da, bazı dezavantajları da bulunmaktadır.Bu bölümde bu dezavantajların üzerinde duracağım;
Maliyet (ya da Yönetim, Bakım, Geliştirme Zorlukları)
OLAP sistemleri son kullanıcı açısından oldukça kolay ve kullanışlı bir ortam sunmakta. Bu kolaylığı sağlamak için işin zor kısmı yönetim ve geliştirme bölümlerine aktarılmış durumdadır. Bu karmaşıklık, iş zekası sistemlerinin geliştirilmesi için daha yüksek seviyede teknik bilgi gereksinimini doğurmaktadır.
Tüm dimension, hiyerarchy ve measure’ların tanımlanması ve oluşturulması gerekir. Sonraki adımda bu nesnelerin küpler içinde tanımlanması gerekir. Bu, organizasyon, hedefleri ve işleyişi hakkında oldukça detaylı bilgi gereksinimi anlamına gelmektedir. Bununla birlikte geliştirme ve bakım ekiplerinin data mart ve seçilen OLAP araçları hakkında bilgi sahibi olması zorunludur.
Elbette geliştirme ve bakım ekibi için gereken bilgi ve deneyim oranı arttıkça maliyet de artar. İş zekası projeleri son derece yüksek malieytli uzmanlık gereksinimi yüzünden oldukça yüksek maliyetli olabilmektedir. Bu faktör, tek başına pek çok organizasyonun iş zekası çözümlerinden uzak durmasına yol açmaktadır.
Data Mart Gereksinimi
Pek çok durumda, OLAP sistemleri star ya da snowflake mimarisindeki bir data mart’a gereksinim duyarlar. Veriler OLTP sisteminden, data mart’a aktarılır ki bu iş genellikle schedule edilmiş görevler aracılığıyla gerçekleştirilir ve veri aktarımı sırasında veri temizleme ve düzenleme işlemleri (veri yükleme / data loading) de gerçekleştirilir. OLTP sistemlerindeki değişiklikler elbette ilgili data loading rutinlerinde değişiklik anlamına gelecektir.
Gecikme
OLAP sisteminin kullandığı data mart yapısı nedeniyle data loading işlemi gerçekleşene kadar OLTP sistemlerdeki veriler, OLAP sistemleri tarafından görülemeyecektir. Data loading işlemi çoğu senaryoda gecelik olarak gerçekleştirildiği için OLAP sistemi OLTP sistemini 1 gün sonradan takip edecektir.
Salt Okunur
Bazı durumlarda bir OLAP analizi sırasında bazı verilerin güncellenmesi istenebilmektedir. Bu verilerdeki hatalardan kaynaklanabileceği gibi karar vericinin farklı what-if senaryolarını gözlemlemek istemesinden de kaynaklanabilir, örneğin: “Komisyonlar yüzde 1 oranında arttırılmasının kar tutarına etkisi ne olacaktır?”.
Çoğu durumda OLAP verileri read-only durumdadır. OLAP sistemimizin writeback desteği olsa dahi, veri güncellemesini data mart üzerinde yapıyor olacaktık ve değişikliklerimiz transactional sisteme yansımayacaktı.
Bu bölümde temel OLAP mimarilerini ele aldık. Sonraki bölümün konusu ise temel OLAP mimarilerilerinin dezavantajlarından korunmak için geliştirilmiş olan Unified Dimensional Model yapısı olacak.
Deflate Stream – Compress & Decompress
Merhaba, üzerinde çalışmakta olduğum projede bugun yapmış olduğum bir işlemin kodlarını sizinle paylaşmak istiyorum. Senaryo aslında çok derin, ama ben kısaca bahsedeyim. Kullanıcı bir Windows App yardımıyla SQL’e dosya yükler, veya bu dosyayı download eder. Tabi bu aşamada önemli olan şey içeriye yüklenen verinin boyutunun yüksek olabileceğinden dolayı bu dosyanın içeriğini sıkıştırarark yüklemektir. Veriyi database’de tutacagımız alan BINARY tipindedir. Buyrun kodlar.
Dosyayı OpenFileDialog ile kullanıcıdan seçtiriyorum, ve seçilen dosyanın path’ini aşağıdaki function’a gönderiyorum.
1: public byte[] FileToByteArray(string filePath)
2: {
3: FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
4: BinaryReader br = new BinaryReader(fs);
5:
6: long totalBytes = new FileInfo(filePath).Length;
7:
8: byte[] buffer = br.ReadBytes(Convert.ToInt32(totalBytes));
9: bufferSize = totalBytes;
10:
11: fs.Close();
12: fs.Dispose();
13: br.Close();
14:
15: return Compress(buffer);
16: }
Bu function oluşturduğu byte[] değerlerini Compress isimli aşağıdaki fonksiyon gönderiyor.
1: public static byte[] Compress(byte[] data)
2: {
3: MemoryStream ms = new MemoryStream();
4: DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress);
5: ds.Write(data, 0, data.Length);
6: ds.Flush();
7: ds.Close();
8: return ms.ToArray();
9: }
Bir dosyayı alarak, sıkıştırdık ve DB’ye kayıt etmeye hazır hale getirdik.
Şimdide DB’deki dosyayı kullanıcının download etmesini sağlayacak kod bloğunu yazıyorum.
1: FolderBrowserDialog dialog = new FolderBrowserDialog();
2: dialog.ShowDialog(this);
3:
4: if (!string.IsNullOrEmpty(dialog.SelectedPath))
5: {
6: string file = String.Format("{0}\\{1}", dialog.SelectedPath, ocd.FILE_NAME);
7:
8: FileStream fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write);
9: BinaryWriter bw = new BinaryWriter(fs);
10:
11: bw.Write(Decompress(ocd.FILE_DATA.ToArray()).ToArray());
12: bw.Flush();
13:
14: bw.Close();
15: }
Burada 11. satırda çağırılan function’ın almış oldugu ocd.FILE_DATA, bizim SQL’de depolamış olduğumuz binary verisidir.
Gönderildiği Decompress fonksiyonunun içeriği aşağıdaki gibidir.
1: public byte[] Decompress(byte[] data)
2: {
3: const int BUFFER_SIZE = 256;
4: byte[] tempArray = new byte[BUFFER_SIZE];
5: List<byte[]> tempList = new List<byte[]>();
6: int count = 0, length = 0;
7:
8: MemoryStream ms = new MemoryStream(data);
9: DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
10:
11: while ((count = ds.Read(tempArray, 0, BUFFER_SIZE)) > 0)
12: {
13: if (count == BUFFER_SIZE)
14: {
15: tempList.Add(tempArray);
16: tempArray = new byte[BUFFER_SIZE];
17: }
18: else
19: {
20: byte[] temp = new byte[count];
21: Array.Copy(tempArray, 0, temp, 0, count);
22: tempList.Add(temp);
23: }
24: length += count;
25: }
26:
27: byte[] retVal = new byte[length];
28:
29: count = 0;
30: foreach (byte[] temp in tempList)
31: {
32: Array.Copy(temp, 0, retVal, count, temp.Length);
33: count += temp.Length;
34: }
35:
36: return retVal;
37: }
İşte bu kadar basit. Bu sistem sayesinde her türlü verinin içeriğini Compress ederek DB’de saklayabilirsiniz. Hatırladığım kadarıyla SQL’de binary field’ı max 2 GB’a kadar verı tutabiliyor. 4 GB’da olabilir tabi
Silverlight 4 Beta ile WebCam ve Mikrofon Erişimi
Silverlight’ın ilk üç versiyonunda müthiş yenilikler geldi ve kullanım oranı her versiyon ile birlikte katlanarak arttı. Hala eksik olan birşeyler vardı, bunların başında WebCam ve Mikrofon erişimi geliyordu. Silverlight 4 Beta ile birlikte müjdeli haber geldi ve artık silverlight ile WebCam ve Mikrofon erişimi mümkün! Hemde kullanımı son derece basit. Uygulamaya geçmeden önce Silverlight 4 Beta için gerekli olan araçları indirip kuralım.
- Visual Studio 2010 Beta 2 yada Visual Web Developer Express 2010 Beta 2
- Silverlight 4 Beta Tools for Visual Studio 2010
- Windows Runtime yada Mac Runtime
- Microsoft Expression Blend for .NET 4 Preview
Araçları kurduktan sonra örneğimiz için Visual Studio 2010 ile yeni bir Silverlight projesi başlatalım. Formumuza Webcam’den gelen görüntüyü göstermek için Rectangle nesnesi, Ses ve kamera aygıtlarını listelemek için iki adet combobox nesnesi, camerayı başlatmak-durdurmak ve cameradaki görüntünün resmini almak için bir adet button ve image nesnesi ekleyelim. XAML kodumuz aşağıdaki gibi oldu.
[XAML]
<UserControl xmlns=” http://schemas.microsoft.com/winfx/2006/xaml/presentation”mlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″ xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″ x:Class=”WebCamMicrofon.MainPage” Height=”340″ Width=”550″>
<Grid x:Name=”LayoutRoot” Background=”White”>
<Rectangle Fill=”White” Width=”400″ Height=”300″Stroke=”Black” Margin=”10,20,130,20″ x:Name=”player”/>
<ComboBox HorizontalAlignment=”Right” VerticalAlignment=”Top” Width=”120″ Margin=”0,20,8,0″ x:Name=”cmbAudioSources”/>
<ComboBox HorizontalAlignment=”Right” Margin=”0,54,8,0″ VerticalAlignment=”Top” Width=”120″ x:Name=”cmbVideoSources”/>
<Button Content=”Fotoğraf Çek” Width=”104″ Margin=”422,0,24,175″ x:Name=”btnTake” Height=”22″ erticalAlignment=”Bottom” />
<Button Content=”Durdur” HorizontalAlignment=”Right” VerticalAlignment=”Top” Width=”104″ x:Name=”btnStop”Margin=”0,115,24,0″/>
<Button Content=”Oynat” HorizontalAlignment=”Right” VerticalAlignment=”Top” Width=”104″ x:Name=”btnStart” Margin=”0,89,24,0″/>
<Image Height=”90″ HorizontalAlignment=”Left” Margin=”422,193,0,0″ Stretch=”Fill” x:Name=”image” VerticalAlignment=”Top”Width=”120″ />
</Grid>
</UserControl></DIV>
CaptureSource nesnesi, sistemdeki görüntü ve sesin istemcinin browserında yayınlanmasını sağlar. (Hatta yayın sırasında bir karenin yakalanmasını sağlıyor J).
CaptureSource nesnesinin Start metodunu kullanarak görüntünün capture edilmesini sağlıyoruz. Stop medodu ise capture işleminin durdurulmasını sağlıyor. State isimli enum ile CaptureSource nesnesinin capture durumunu kontrol edebiliriz. AudioCaptureDeviceözelliği sistemde yer alan ilişkili bir ses aygıtını, VideoCaptureDevice özelliği de sistemde yer alan ilişkili bir görüntü aygıtını temsil eder.
CaptureDeviceConfiguration nesnesi, sistemde yer alan ses ve görüntü aygıtlarına erişmemizi sağlar. Ayrıca kullanıcının bu aygıtlara erişime izin verip vermediğini kontrol eden üyeleri vardır.
[C#]
public partial class MainPage : UserControl
{
public CaptureSource CaptureSource { get; set; }
public MainPage()
{
InitializeComponent();
// Kontrolllerin eventlerini oluşturalım
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
this.btnStart.Click += new RoutedEventHandler(btnStart_Click);
this.btnStop.Click += new RoutedEventHandler(btnStop_Click);
this.btnTake.Click += new RoutedEventHandler(btnTake_Click);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
// İlk yükleme de sistem de yer alan aygıtları ilgili kontrollere yüklüyoruz.
AygitlariYukle();
}
private void AygitlariYukle()
{
// CaptureSource Nesnesinin örneğini alalım.
CaptureSource = new CaptureSource();
// Ses aygıtlarını combobox’a yükleyelim. GetAvailableAudioCaptureDevices() Metodu sisteme yer alan ses aygıtlarını getiriyor.
cmbAudioSources.ItemsSource = CaptureDeviceConfiguration.GetAvailableAudioCaptureDevices();
cmbAudioSources.DisplayMemberPath = “FriendlyName”;
// Kamera aygıtlarını combobox’a yükleyelim. GetAvailableVideoCaptureDevices() Metodu sisteme yer alan kamera aygıtlarını getiriyor.
cmbVideoSources.ItemsSource = CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices();
cmbVideoSources.DisplayMemberPath = “FriendlyName”;
}
void btnStart_Click(object sender, RoutedEventArgs e)
{
// CaptureSource nesnesi başlatılmadıysa…
if (CaptureSource.State != CaptureState.Started)
{
// Seçtiğimiz ses aygıtını CaptureSource nesnesinin AudioCaptureDevice özelliğine bağlayalım.
CaptureSource.AudioCaptureDevice = (AudioCaptureDevice)cmbAudioSources.SelectedItem;
// Seçtiğimiz kamera aygıtını CaptureSource nesnesinin VideoCaptureDevice özelliğine bağlayalım.
CaptureSource.VideoCaptureDevice = (VideoCaptureDevice)cmbVideoSources.SelectedItem;
// VideoBrush nesnesi oluşutralım ve SetSource metoduna CaptureSource’u parametre olarak geçelim.
VideoBrush vb = new VideoBrush();
vb.SetSource(CaptureSource);
// Player isimli kontrol de kameradan gelen görüntüyü gösterelim…
player.Fill = vb;
// İstemci aygıtlara erişimi izni verdiyse capture işlemini başlatalım.
if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
{
CaptureSource.Start();
}
}
}
void btnStop_Click(object sender, RoutedEventArgs e)
{
// Kamera görüntüsünü capture ediliyorsa.
if (CaptureSource.State != CaptureState.Stopped)
{
// Capture işlemini durduralım.
CaptureSource.Stop();
}
}
void btnTake_Click(object sender, RoutedEventArgs e)
{
// Kamera görüntüsü capture ediliyorsa.
if (CaptureSource.State== CaptureState.Started)
{
CaptureSource.AsyncCaptureImage((rsm) =>
{
image.Source = rsm; // Yakalanan kamera görüntüsünü Image nesnesine bağlayalım
});
}
}
}</DIV>
Uygulamamızı çalıştırdığımızda aşağıdaki gibi bir uyarı çıkacaktır. (Kamera ve Ses aygıtınıza erişime izin vermemizi istiyor) Evet diyerek devem edelim.
Sistemimizde yer alan ses ve kamera aygıtını seçerek kameradan görüntü almaya başlayalım.
Oynat dediğimizde:)
Birde resim yakalayalım
Bu makalenin de sonuna geldik başka bir makale de görüşmek üzere. Silverlight ile kalın
Örnek uygulama için tıklayınız
Sem GÖKSU
www.semgoksu.com | www.yazilimgunlugu.com
sem.goksu@yazilimgunlugu.com
Kaynaklar
Silverlight 4 Beta SDK
ASP.NET 4.0 – URL Routing
Web uygulamarında kullanıcıların yapmış olduğu işlemlerde parametre aktarımı bazı durumlarda QueryString ile (URL’den) yapılmaktadır. Bu durumda adres çubuğunda oluşan link çok uzun ve okunamaz hale geliyor. Bu kullanıcı açısından görüntü kirliliği yaratıyor, arama motorları tarafından indexlenme ihtimalini azaltıyor ve geliştirici açısından parametrelerin okunması ve takip edilmesi zorlaştırıyor. Örneğin;
<I>http://semgoksu.com/search.aspx?Kategori=ASP.NET&Tarih=15122009&Baslik=URLRouting</I>
ASP.NET 4.0 ile birlikte URL Routing’i kullanarak bu sorunu ortadan kaldırabiliyoruz. Bu sayede hem oluşan link daha kısa ve anlamlı oluyor, hemde URL içerisindeki klasör yapısına sayfa ile ilgili keywordleri koyarak arama motorlarının daha kolay indexlemesini ve bu sayede sayfalarımızın daha üst sıralarda çıkması sağlayarak büyük bir avantaj sağlamış oluyoruz. Yukarıda vermiş örneği ASP.NET 4.0 URL Routing’i kullanarak aşağıdaki gibi yapabiliriz.
<I>http://semgoksu.com/Arama/ASP.NET/15122009/URLRouting</I>
URL Routing ilk olarak MVC ile birlikte geldi ve artık ASP.NET 4.0 ile birlikte URL Yönlendirme işlemi yapabilmemiz için her şey hazır durumda. Visual Studio 2010’u kullanarak yeni bir ASP.NET uygulaması oluşturalım ve konuyu örneklendirelim. Uygulamayı oluşturduktan sonra web uygulamamıza yeni bir Global.asax dosyası ekleyelim.
Globax.asax dosyası içerisinde bulunan <I>Application_Start</I> methodu içerisinde URL yönlendirme işlemini yapacağız. Bunun için ihtiyacımız olan ilk şey <I>RouteTable</I>. Bu sınıf farklı formatlardaki url yönlendirmelerini(Route’ları) saklayacak olan Route koleksiyonudur. İki parametre alır; Route’un adı ve Route nesnesi. <I>Route</I> nesnesi de URL’in gösterileceği formatı belirtmek için kullanılır. Uygulamaya gelen istekler Route’un formatına uygunsa PageRouteHandler’ın belirttiği path’e yönlenir. <I>PageRouteHandler</I> sınıfı yönlendirilecek olan fiziksel dosyayı Constructor’da(Yapıcı metot) parametre olarak alır.
Sonuç olarak sayfaya yapılan request’lar RouteTable’daki Route’lardan birine uygun formattaysa PageRouteHandler’in işaret ettiği sayfaya yönlenir. URL bizim belirttiğimiz formatta görüntülenirken arka tarafta ilgili fiziksel dosya üzerinde işlem yapılır.
İlk olarak ana sayfamızdan(Default.aspx) detay sayfaya (detay.aspx) sayfasına bir yönlendirme işlemi yapalım. Detay sayfasına bir de parametre gönderelim ve bu parametreyi detay sayfada yakalayarak ekran da görüntüleyelim.
[Global.asax]
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Web.Routing" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add("Detay", new Route("Detay/{Parametre}", new PageRouteHandler("~/Detay.aspx")));
}
</script>
</DIV>
Appplication_Start metodu içerisinde sayfamıza gelecek olan url formatını <I>Klasor/{Parametre}</I> şeklinde belirttik. ({Parametre} yerine istediğimiz bir değeri gönderebileceğiz) Bu formatta gelen bütün istekler detay.aspx sayfasını gösterecek.
[Default.aspx]
<asp:HyperLink ID="link" runat="server" NavigateUrl=’<%$ RouteUrl:RouteName=Detay, Parametre=Sayfa1 %>’>Detaya Git</asp:HyperLink>
</DIV>
Ana sayfaya bir HyperLink nesnesi ekledik. HyperLink içerisinde ilk olarak sayfamızın gideceği Route’u ve o Route’a göndereceğimiz Parametreyi bildirdik. Oluşacak olan format şu şekilde olacak. NavigatetUrl içerisinde kullanılan RouteUrl’i kod tarafında kullanamıyoruz.
<I>http://localhost:50751/Detay/Sayfa1</I>
Şimdi Detay.aspx sayfaya gidelim ve gönderdiğimiz parametreyi yakalayalım. Route içerisinde gönderdiğimiz bütün parametreler RouteDataiçerisinde yer alır. Göndermiş olduğumuz parametreye erişmek için RouteData.Values[“Parametre”] yada RouteData:Name şeklinde kullanırız.
[Detay.aspx.cs]
protected void Page_Load(object sender, EventArgs e)
{
if (RouteData.Values["Parametre"]!=null)
{
Response.Write(RouteData.Values["Parametre"].ToString());
}
}
</DIV>
Sayfayı çalıştırdığımız da URL istediğimiz şekilde gitmiş ve Detay.aspx sayfasına göndermiş olduğumuz parametreyi’de ekranda görüntüledik.
Şimdi farklı bir örnek yapalım ve birden fazla parametreyi nasıl göndeririz ona bakalım. Bu örnekte SQL Server 2005’te yer alan örnek veritabanlarından AdventureWorks’u kullanarak Kategorileri ilk ekran da listeyelim. Kullanıcı ilgili kategoriye tıkladığında farklı bir sayfa da ilgili ürünler listelensin. Sayfaya göndereceğimiz URL formatını da istediğimiz gibi değiştirelim. Bunun için global.asax dosyamızı düzenleyelim. Route içerisinde format istediğimiz gibi düzenleyebiliriz. KategoriID ve KategoriAdi parametrelerini istediğimiz değerleri verebileceğiz.
[Global.asax]
<%@Application Language="C#" %>
<%@ Import Namespace="System.Web.Routing" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add("Kategoriler", new Route("Katgoriler/{KategoriAdi}/{KategoriID}", new PageRouteHandler("~/Detay.aspx")));
}
</script>
</DIV>
Sayfamıza bir Repeater ekleyelim. Burada Kategorileri listeleyeceğiz. Veritabanındaki verilere erişmek için projemize bir adet <I>LINQ to SQL Classes</I> Dosyası ekleyelim. İsim olarak AdventureWorks diyelim.
Kullanacağımız ProductSubCategory ve Product tablolarını’da dosyamıza alalım. Şimdi kategorilerimizi listeleyek olan HTML kodunu yazalım. Sayfaya Repeater, içerisinede bir HyperLink ekliyoruz.
[Default.aspx]
<asp:Repeater ID="rptKategoriler" runat="server" OnItemDataBound="rptKategoriler_ItemDataBound">
<ItemTemplate>
<asp:HyperLink ID="hlKategori" runat="server">
</asp:HyperLink><br />
</ItemTemplate>
</asp:Repeater>
</DIV>
Şimdide veritabanından verileri LINQ to SQL ile çekelim ve Repeater’a bağlayalım. ItemDataBound eventin’de HyperLink nesnesini yakalayıp kontrolün Text ve NavigateUrl özelliğini datadan gelen değer ile dolduracağız.
[Default.aspx.cs]
AdventureWorksDataContext db = new AdventureWorksDataContext();
protected void Page_Load(object sender, EventArgs e)
{
rptKategoriler.DataSource = (from k in db.ProductSubcategories select k).Take(10); // 10 kayıt alalım
rptKategoriler.DataBind();
}
protected void rptKategoriler_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item|| e.Item.ItemType == ListItemType.AlternatingItem )
{
HyperLink hl = e.Item.FindControl("hlKategori") as HyperLink;
hl.Text = DataBinder.Eval(e.Item.DataItem, "Name").ToString();
RouteValueDictionary parameters = new RouteValueDictionary()
{
{ "KategoriID", DataBinder.Eval(e.Item.DataItem, "ProductSubCategoryID").ToString() },
{ "KategoriAdi",DataBinder.Eval(e.Item.DataItem, "Name").ToString() }
}; // Route’un alacağı parametreler’i dinamik olarak dolduruyoruz
VirtualPathData path = RouteTable.Routes.GetVirtualPath(null,"Kategoriler", parameters);
hl.NavigateUrl = path.VirtualPath; // Oluşan Route’un pathini hyperlinke atadık.
}
}
</DIV>
Kategorilerin listeleneceği sayfayı hazırladık. Şimdi de gidip detay sayfada görüntülenecek olan ürünler için gerekli sayfayı hazırlayalım. İlk olarak HTML’e bir Repeater ekleyelim ve içine bir label atalım. Text özelliğinde de ürün’ün adını görüntüleyelim.
[Detay.aspx]
<asp:Repeater ID="rptUrunler" runat="server">
<ItemTemplate>
<asp:Label ID="lblUrunAdi" runat="server" Text=<%# Eval("Name") %>>
</asp:Label><br />
</ItemTemplate>
</asp:Repeater>
</DIV>
Veriyi LINQ to SQL ile çekerek Repeater’a bağlayalım. Diğer sayfadan gelen KategoriID parametresinide almayı unutmuyoruz. Ürünler gelen KategoriID parametresine göre listelenecek.
[Detay.aspx.cs]
AdventureWorksDataContext db = new AdventureWorksDataContext();
protected void Page_Load(object sender, EventArgs e)
{
if (RouteData.Values["KategoriID"]!=null)
{
int UrunID = Convert.ToInt32(RouteData.Values["KategoriID"]);
UrunleriGetir(UrunID);
}
}
private void UrunleriGetir(int KategoriID)
{
rptUrunler.DataSource = from u in db.Products
where u.ProductSubcategoryID == KategoriID
select u;
rptUrunler.DataBind();
}
</DIV>
Şimdi sayfayı çalıştıralım ve sonuca bakalım,
Kategorilerden birine tıklayalım.
İşte bu kadar J
Bu makalenin de sonuna geldik başka bir makale de görüşmek üzere. ASP.NET ile kalın
Sem GÖKSU
www.semgoksu.com| www.yazilimgunlugu.com
sem.goksu@yazilimgunlugu.com
Kaynaklar
msdn.com
ASP.NET 4.0 – Page.Description ve Page.Keyword Özellikleri
ASP.NET 4.0 ile birlikte Page sınıfına Description ve Keyword isimli iki yeni özellik eklendi. Bu özellikleri kullanarak web uygulamalarına keywords ve desctiption meta etiketlerini ekleyebiliyoruz.
ASP.NET 4.0 Öncesi
ASP.NET 4.0 öncesinde keywords ve description meta etiketlerini <head> etiketi arasına yazabiliyorduk.
<headrunat="server">
<title>Page Description ve Page Keyword Özelliği</title>
<meta name="keywords" content="Buraya sayfa ile ilgili anahtar kelimeler gelecek..’ />
<meta name="description" content="Buraya sayfanın açıklaması gelecek…" />
</head></DIV>
ASP.NET 4.0 Yaklaşımı
ASP.NET 4.0 ile birlikte sayfa direktiflerinden Keywords ve Description özelliğini kullanarak meta etiketini belirleyebiliyoruz.
[HTML]
<%@
Page Language="C#"
AutoEventWireup="true"
CodeFile="Default.aspx.cs"
Inherits="_Default"
Keywords="Anahtar kelimeler…"
Description="Sayfa ile ilgili açıklama…"
%></DIV>
Bu bilgilerin veritabanından geleceğini de düşünürsek bu işlemi dinamik olarak da yapabiliriz.
[C#] protected void Page_Load(object sender, EventArgs e)
{
this.Keywords = "Anahtar kelimeler…";
this.Description = "Sayfa ile açıklama…";
}</DIV>
Eğer sayfada head etiketi arasında tanımlı keywords yada description meta etiketi varsa bizim belirlediğimiz bilgiler üzerine yazılacaktır.
ASP.NET 4.0 – Kontroller için ClientIDMode Özelliği
ASP.NET de kontroller render edildikten sonra bir ID değeri alıyor ve bu ID değeri tüm kontroller için benzersiz oluyor. Bu yüzden, eğer kontrol UserControl yada MasterPage içerisindeyse kontrol’ün ID’si <I>UserControlAdi_KontrolAdi</I> şeklinde uzun bir isme sahip oluyor. Bu şekilde özellikle istemci taraflı geliştirme yaparkan(Javascript, JQuery vs.) bu kontrollere erişmek çok zor oluyor ve uygulamayı geliştiren kişinin geliştirme süresini uzatıyordu.
ASP.NET 4.0 Öncesi ve Read-Only ClientID Özelliği
Aslında ASP.NET içerisinde her kontrolün ClientID isimli read-only bir propertysi var. Bu property ile kontrolün alacağı ID’ye erişebiliyoruz. Fakat kontrolü bir user control içerisine taşırsak <I>WebUserControl1_lblClientID</I> gibi bir ClientID’ye sahip oluyor. Bu da istemci tarafında yapılan işlemi ve süreci etkiler, yapılan işlemin hatalı olmasına neden olur. Çünkü eğer harici bir dosya içinde İstemci taraflı işlemler yapılıyorsa orada da ilgili değişikliğin yapılması gerekir.
ASP.NET 4.0 Öncesi ClientID Özelliği
Response.Write(KonrolAdi.ClientID);
KonrolAdi.ClientID = “Atanamaz”; // => Read only bir özellik, atama yapılamaz !
</DIV>
ASP.NET 4.0 Yaklaşımı ve ClientIDMode Özelliği
İstemci taraflı geliştirmenin web uygulamalı içerisinde kullanımın artmasıyla birlikte bu sorunu aşmak için ASP.NET 4.0 ile birlikte kontrollere ClientIDMode isimli bir özellik eklendi. Bu özellik kontrol render edildikten sonra kontrolün alacağı ClientID değerinin istediğimiz gibi atanmasını sağlıyor. Yani ClientID’nin değeri eskiden olduğu gibi uzunca bir değer olabilir, bizim vereceğimiz her hangi bir değer olabilir ya da kontrol’ün ID’si ile aynı olabilir.
ClientIDMode özelliğinin alabileceği 4 özellik var. Bunlar Legacy (varsayılan değer), Inherit, Static, Predictable.
Legacy
ClientIDMode’un default değeridir. Eğer ClientIDMode özelliğine Legacy’i enum’u set edilmişse kontrolün alacağı ID değeri önceki sürümlerde olduğu gibidir. Yani uzunca bir ClientID oluşur
Örnek Kullanımı
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:Label ID="lblSample" ClientID="lblSample" ClientIDMode="Legacy" runat="server" Text="Deneme"></asp:Label>
</asp:Content>
Html Çıktısı
<span id="ctl00ctl00_ContentPlaceHolder1_lblSample">Deneme</span>
</DIV>
Inherit
Her kontrol için default davranış gösterir. İçerisinde yer aldığı parent kontrolün ClientIDMode property’si ne olarak belirlenmişse, kontrol içinde o özellik atanır. Örneğin bir MasterPage ve Content sayfası var. Content sayfanın içinde de bir Label var. Master Page içerisindeki ContentPlaceHolder’ın ClientIDMode özelliği static ise Content sayfa içerisinde yer alan kontrolün özelliği de static olarak belirlenir.
Örnek Kullanımı
Master Page
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server" ClientIDMode="Static"> </asp:ContentPlaceHolder>
Content
<asp:Label ID=" lblSample" ClientID="lblInheritSample" ClientIDMode="Inherit" runat="server" Text="Deneme"></asp:Label>
Html Çıktısı
<span id="lblInheritSample">Deneme</span> // Parent Kontrolün(Content) ClientIDMode özelliği static olduğu için içteki kontrolünde ClientIDMode özelliği static olarak atandı…
</DIV>
Static
Bu mod seçildiğinde, kontrolün ClientID’ne ne atamışsak oluşacak olan HTML çıktısına da o değer atanır. Burada dikkat edilmesi gereken şey, ClientID’nin benzersiz olduğundan emin olmak zorundayız. Yani elimizde 2 User Control var. Her ikisi içinde de bir label olduğunu düşünürsek iki label’ın CleintID’si farklı olması gerekir. Eğer ikisi de aynı olursa, client site de yapacağımız işlemler de yanlış sonuçlar alabiliriz. Özellikle de databound kontrollerinden kullanmamak gerekir.
Örnek Kullanımı
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:Label ID=" lblSample" ClientID=”lblClientSample" ClientIDMode="Static" runat="server" Text="Deneme"></asp:Label>
</asp:Content>
Html Çıktısı
<span id=" lblClientSample">Deneme</span>
</DIV>
Predictable
Bu özellik, Gridview, Repeater gibi DataBound kontroller için daha kullanışlıdır. Burada işe yarayacak bir diğer property de RowClientIDSuffixözelliğidir. Bu özellik ile DataBound kontrolünün kolonu içerisinde yer alan kontrolün ClientID’nin değerinin sonuna takı olarak belirttiğimiz alanın değeri eklenir.
Örnek Kullanımı
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" ClientIDMode="Predictable" RowClientIDSuffix="UrunAdi"> // RowClientIDSuffix özelliğine veri kaynağından gelen bir alan yazmak zorundayız. Birden fazla kontrol için yapacaksak alanları virgül ile ayırabiliriz.
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="lblUrunAdi" runat="server" Text=’<%# Eval("UrunAdi") %>’></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Html Çıktısı
<table cellspacing="0" rules="all" border="1" id="ctl00_ContentPlaceHolder1_GridView1" style="border-collapse:collapse;">
<tr><th scope="col"> </th></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_lblUrunAdi_Kalem">Kalem</span>
</td></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_lblUrunAdi_Defter">Defter</span>
</td></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_lblUrunAdi_Silgi">Silgi</span>
</td></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_lblUrunAdi_Dosya Kağıdı">Dosya Kağıdı</span>
</td></tr>
</table>
Eğer ClientIDMode özelliğini Predictable yapmasaydık,
<table cellspacing="0" rules="all" border="1" id="ctl00_ContentPlaceHolder1_GridView1" style="border-collapse:collapse;">
<tr><th scope="col"> </th></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_ctl02_lblUrunAdi">Kalem</span>
</td></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_ctl03_lblUrunAdi">Defter</span>
</td></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_ctl04_lblUrunAdi">Silgi</span>
</td></tr><tr><td>
<span id="ctl00_ContentPlaceHolder1_GridView1_ctl05_lblUrunAdi">Dosya Kağıdı</span>
</td></tr>
</table>
</DIV>
Makalenin sonuna geldik, başka bir makalede görüşmek üzere. ASP.NET ile kalın
Sem GÖKSU
www.semgoksu.com | www.yazilimgunlugu.com
sem.goksu@yazilimgunlugu.com
Kaynaklar
msdn.com
ASP.NET 4.0 Caching – Data Caching
İlk makalemiz de performansı arttırmak için Output Caching ile sayfanın çıktısını önbelleğe almıştık. Output Caching ile sayfa çıktısının tamamını yada belli bir kısmını önbellekleyebiliyorduk. Fakat her zaman bu yeterli olmayacaktır. Bazı durumlar da sayfa içerisinde kullanılan verinin yada verilen de önbelleklenmesi gerekebilir. Bu durumda Output Caching kullanamayız, çünkü Output Caching ile sadece sayfanın çıktısını önbellekleyebiliyoruz. Uygulamamız içerisinde veri yada verileri önbelleğe alabilmek için Data Caching’i kullanmamız gerekiyor.
Output Caching’de bahsettiğimiz durum Data Caching içinde geçerlidir. İstenilen bilginin tekrar tekrar kaynaklardan çekilmesi yerine, gelen ilk istek server tarafından karşılanacak (veritabanı yada başka bir sağlayıcı da olabilir) sonrasında ise önbelleklenen veri bellekten alınıp uygulama içerisinde kullanılacak. Veritabanından aldığımızı düşünürsek bu işlem performans için çok önemli bir artış sağlıyor olacaktır.
Yukarıdaki örnek, önbelleklenen ve önbelleklenmeyen bir database işleminin akış şemasını gösteriyor. İlk örnekte gelen her istek ilgili Query’i çalıştırmak için database’e bağlanıyor, hem server tarafında trafik oluyor hem de verinin databaseden getirilmesi sırasında performans kaybı yaşanıyor. İkinci örnekte ise sadece ilk seferde veritabanına bağlanıyor ve veriyi önbelleğe atıyor. Sonrasında gelen tüm talepler önbellekten getiriyor. Bu da verinin hazır bir şekilde alınmasını, dolayısıyla uygulamanın daha performanslı çalışmasını sağlıyor.
En basit kullanım şekli ile bir nesneyi Cache’e atmak aşağıdaki gibidir…
Cache.Insert(“Key”, Data);</DIV>
Cache’e attığımız nesneyi silmek istiyorsak da aşağıdaki gibi bir kullanıma ihtiyacımız var.
Cache.Remove(“Key”);</DIV>
Data caching için kullanabileceğimiz 3 yöntem var. Absolute Time, Sliding Time(Süreye Bağlı Önbellekleme) ve File Dependency (Dosya Değişimine göre Önbellekleme).
Absolute Time
Belirtilen süre boyunca data önbellekte saklanır bu süre içerisinde gelen talepler önbellekten karşılanır. Sürenin sonunda ise data önbellekten silinecektir.
Cache.Insert(“key”, data, null, DateTime.Now.AddMinutes(1), System.Web.Caching.Cache.NoSlidingExpiration);</DIV>
İlk parametre, önbelleğe alınan veriye ulaşabilmemiz için ulaşacağımız key, ikinci parametre önbellekte saklanacak olan verinin kendisi, üçüncü parametre CacheDependency nesnesi (biz burada bunu şimdilik kullanmayacağımızı için null gönderiyoruz), dördüncü parametre verinin ne kadar süre önbellekte kalacağını belirten DateTime tipinde bir değer, son parametre de TimeSpan tipinde bir değer istiyor, Absolute Time için, parametre olarak Cache sınıfında bulunan NoSlidingExpiration fielad’ını parametre olarak gönderiyoruz.
Sliding Time
Belirtilen süre boyunca data önbellekte saklanır. Eğer bu süre içerisinde yeni bir talep gelirse süre yeni baştan başlar. Sürenin sonunda ise veri önbellekten silinir.
Cache.Insert(“key”, Data, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(120));</DIV>
Absolute time da olduğu, Sliding Time içinde ilk üç parametre aynı. Dördüncü parametre hatırlarsak bizden DateTime tipinde bir parametre istiyordu. Sliding Time’a göre önbellekleme yapacaksak, Cache sınıfında bulunan NoAbsoluteExpiration fieldını parametre olarak yolluyoruz, son parametreye de timespan tipinde bir değer yolluyoruz.
File Dependency
Disk üzerinde yer alan bir dosyadan çekilen verinin içeriği değişene kadar önbellekleme yapılır.
[XML]
<?xml version=”1.0″ encoding=”utf-8″?>
<Products>
<Product>
<ProductID>1</ProductID>
<Name>Masa</Name>
</Product>
<Product>
<ProductID>2</ProductID>
<Name>Sandalye</Name>
</Product>
<Product>
<ProductID>3</ProductID>
<Name>Dolap</Name>
</Product>
</Products></DIV>
[C#]
CacheDependencydep = new CacheDependency(Server.MapPath(“Data.xml”));
//XML’en gelen verinin data isimli bir objeye atıldığı varsayılmıştır…
Cache.Insert(“key”, data, dep, DateTime.Now.AddHours(2), System.Web.Caching.Cache.NoSlidingExpiration);
</DIV>
İki saat boyunca önbelleğe alınır ancak, dosyada herhangi bir değişiklik olursa önbelleklenen veri silinir.
Örnek
Öğrenci koleksiyonu içerisinde yer alan veriyi 30 dakika boyunca önbellekten getirelim. Bunun için ilk olarak Ogrenci isimli bir nesne oluşturalım. Aynı nesne içerisinde öğrencileri getirecek öğrenci listesi de yer alacak.
[Ogrenci.cs]
classOgrenci
{
public static List<Ogrenci> Ogrenciler()
{
// Veriyi database’den de getirebilirsiniz… Sadece örnek olması için bu şekilde yaptık.
return new List<Ogrenci>()
{
new Ogrenci(){ OgrenciID = 1, AdSoyad = “Sem Göksu”},
new Ogrenci(){ OgrenciID = 2, AdSoyad = “Elçin Göksu”},
new Ogrenci(){ OgrenciID = 3, AdSoyad = “Ercan Kilercioğlu” }
};
}
public int OgrenciID { get; set; }
public string AdSoyad { get; set; }
}</DIV>
Şimdi sayfamızın Page_Load eventine gidelim.
[Page_Load]
List<Ogrenci> Ogrenciler = null;
if(Cache["Ogrenciler"] != null)
{
Ogrenciler = Cache["Ogrenciler"] as List<Ogrenci>;
Response.Write(“Veri Cache’den getirildi…”);
}
else
{
Ogrenciler = Ogrenci.Ogrenciler();
Cache.Insert(“Ogrenciler”, Ogrenciler, null, DateTime.Now.AddMinutes(30), System.Web.Caching.Cache.NoSlidingExpiration); // Absolute Time Caching
Response.Write(“Veri Veri Kaynağından Getirildi…”);
}
GridView1.DataSource = Ogrenciler;
GridView1.DataBind();
</DIV>
Testimizi yapalım…
| Sayfayı çalıştıralım, | İkinci kez çalıştıralım, |
Makalenin sonuna geldik, başka bir makalede görüşmek üzere…
Sem GÖKSU
www.semgoksu.com | www.yazilimgunlugu.com
sem.goksu@yazilimgunlugu.com
Kaynaklar
asp.net
ASP.NET 4.0 Caching – Output Caching
Web uygulamaları geliştirirken en önemli konulardan bir tanesi performanstır. ASP.NET ile web uygulaması geliştirirken yapılan uygulamanın daha performanslı çalışması için Caching(Önbellekleme) Mekanizması kullanılır. Caching ile sayfanın HTML çıktısının tamamı yada belli bir kısmı bellekte saklanır. Böylece HTML derlenip, tekrar tekrar oluşturulmak yerine bellekten alınarak kullanıcıya iletilir. Bu sayede hem serverdaki trafik azalır hem de gelen isteğin değerlendirilip HTML’in yeniden üretilmesi sırasında kaybedilen zaman kazanılmış olur.
HTML çıktısının tamamını önbellekleyebileceğimiz gibi belli bir kısmını da önbellekleyebiliriz. Önbelleklediğimiz bir alan içerisinde de belli bir alanı dinamik hale getirebiliriz. İlk olarak sayfa çıktısının tamamının nasıl önbellekleneceğine bakalım.
Output Caching (HTML çıktısının önbelleklenmesi)
Output Caching ile sayfanın tamamının belli bir süre içerisinde önbelleklenmesini sağlayabiliriz. Böylece sayfa önbelleğe alındıktan sonra bir sonraki ziyarette HTML önbellekten alınarak kullanıcıya gösterilecek. (Bir sonraki ziyaretin de önbellekleme süresi içerisinde olması gerekiyor)
Sayfayı önbelleklenebilmesi için sayfamıza OutputCache direktifini(Directive) eklememiz gerekiyor. Örnek kullanım;
<%@OutputCache Duration=”300″ Location=”Any” VaryByParam=”none” %></DIV>
Burada ilk göze çarpan Duration ve Location özellikleridir. Duration özelliği saniye cinsinden sayfanın cache’de ne kadar tutulacağına belirliyor. Location özelliği de sayfanın nerede önbellekleneceğini belirten bir enum sunuyor, bu enumun varsayılan değeri Any’dir.
OutputCacheLocation Enum’unun alabileceği değeler
Any
Önbellekleme, isteği yapan Client, Proxy Server yada isteğin yapıldığı server üzerinde olur.
Client
Önbellekleme, isteği yapan Client’ de olur.
DownStream
Önbellekleme, isteği yapan Client’de ve Proxy Server üzerinde olur.
None
Önbellekleme yapılmaz.
Server
Önbellekleme, isteğin yapıldığı Server üzerinde olur.
ServerAndClient
Önbellekleme, isteği yapan Client’de ya da isteğin yapıldığı Server üzerinde olur.</DIV>
Şimdi bir ASP.NET sayfası açalım. Sayfa direktiflerine OutputCache direktifini ekleyelim. Sayfamız 300 saniye boyunca önbelleklenecek.
<%@OutputCache Duration=”300″ Location=”Any” VaryByParam=”none” %></DIV>
Sayfanın Page_Load eventine de aşağıdaki kodu yazalım.
protectedvoid Page_Load(object sender, EventArgs e)
{
Response.Write(DateTime.Now.ToString());
}</DIV>
Sayfa çalıştığında ilk istek değerlendirilecek ve o anki tarih ve saat bilgisi ekrana gelecek. Bundan sonra yapılacak istekler de 300 saniye boyunca önbelleklenmiş veri ekrana gelecek. 300 saniye sonunda da yeni tarih ve saat ekranda gösterilecek.
| İlk İstek | 300 Sn içindeki istekler | 300 Sn Sonra |
| 2009-02-18 12:21:00 | 2009-02-18 12:21:00 | 2009-02-18 12:26:00 |
Bu şekilde çıktıyı önbelleğe aldık, peki ya sayfamıza QueryString’den gelen değerlere göre farklı bilgi içeriyorsa ne olacak? İşte bu durumda her QueryString anahtarı için ayrı ayrı çıktıların önbelleklenmesi sağlayan VaryByParam özelliğini kullanıyoruz.
<%@OutputCache Duration=”300″ Location=”Any” VaryByParam=”KategoriID” %></DIV>
QueryString’den gelen KategoriID anahtarının değerine göre önbellekleme yapılır.
<%@OutputCache Duration=”300″ Location=”Any” VaryByParam=”KategoriID,Dil” %></DIV>
QueryString’den gelen KategoriID ve Dil anahtarlarının değerlerine göre önbellekleme yapılır.
<%@OutputCache Duration=”300″ Location=”Any” VaryByParam=”*” %></DIV>
QueryString’den gelen tüm anahtarların değerine göre ayrı ayrı önbellekleme yapılır.
Fragment Caching(Belli bir kısmının önbelleklenmesi)
Sayfanın tamamı yerine sadece belli bir kısmının da güncellenmesini sağlayabiliyoruz demiştik. Örneğin bir haber sitemiz var. Ana sayfasında da anlık değişebilecek bölümler vardır. Fakat bazı bölümler de sabittir. İşte biz sadece sabit olan bölümleri önbelleğe almak istiyorsak bunun için Fragment Caching’i kullanmalıyız. Bunun için de bu bölümler için User Control yapıp, oluşturduğumuz User Control içerisinde önbellekleme işlemi yapacağız.
Şimdi bir User Control oluşturup, onu yeni bir sayfaya ekleyelim. UserControl içine de bir label ekleyelim. Son olarak da UserControl’ün direktiflerine OutputCache direktifini ekleyelim.
MyUserControl.ascx
<%@Control Language=”C#” AutoEventWireup=”true” CodeFile=”MyUserControl.ascx.cs” Inherits=” MyUserControl ” %>
<%@OutputCache Duration=”300″ VaryByParam=”none” Shared=”true”%>
<asp:LabelID=”Label1″ runat=”server” Text=”Label”></asp:Label></DIV>
Kod tarafında da o anki tarih ve saati Label’a atayalım.
MyUserControl.ascx.cs
protectedvoid Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTimeTime.Now.ToString();
}</DIV>
Şimdi UserControl’ü ekleyeceğimiz ASP.NET sayfasına geçelim. Bir label ekleyelim ve Page_Load eventin de o anki tarih ve saati label’a atayalım.
FragmentPage.aspx.cs
protectedvoid Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToString();
}</DIV>
Sayfaya gelen talepleri ve ekran dan çıkan saat bilgilerini inceleyelim.
| İlk İstek | 300 Sn içindeki istekler | 300 Sn Sonra | |
| Page | 2009-02-18 12:21:00 | 2009-02-18 12:22:01(Örneğin) | 2009-02-18 12:26:00 |
| UserControl | 2009-02-18 12:21:00 | 2009-02-18 12:21:00 | 2009-02-18 12:26:00 |
Yukarıdaki tabloda da görüldüğü gibi Page.aspx’ gelen tüm istekler önbellekleme yapılmadan kullanıcıya aktarılıyor. UserControl içinde ise ilk istek sonrasında 300 saniye boyunca önbellekteki veri kullanıcıya gösteriliyor. Önbellekleme süresi sona erdikten sonra da yeni çıktı oluşturuluyor.
UserControl nerelerde kullanılmışsa kullanıldığı her yer için ayrı ayrı çıktısı bellekte saklanır. Shared özelliğini True yaparak, tüm sayfalar için tek bir çıktı bellekte saklanır.
Substitution Caching(Önbelleklenen alanın dinamik hale getirilmesi)
Bazı durumlarda önbelleklenen bir sayfanın belli bir kısmının dinamik hale getirilmesi gerekir. Bunu yapabilmek için de Substitution Caching’i kullanıyoruz.
Önbellekleme yapılmış bir sayfa içinde dinamik alan oluşturabilmek HTML tarafında Substitution kontrolünü yada HttpResponse sınıfınınWriteSubSubstitution metodunu kullanmak zorundayız. Her ikisi de bizden, parametre olarak HttpContext sınıfını alan, geriye string döndüren static bir metot bekliyor.
Öncelikle Page_Load’da tarih ve saati ekrana yazdıralım, sonrasında ise Static olacak Tarih metodumuzu yazalım.
protectedvoid Page_Load(object sender, EventArgs e)
{
Response.Write(DateTime.Now.ToString());
} protectedstatic string Tarih(HttpContext context)
{
returnDateTime.Now.ToString();
}</DIV>
Şimdi HTML tarafında önbelleklenecek ve dinamik olacak alanımızı belirleyelim.
<%@Page Language=”C#” AutoEventWireup=”true” CodeFile=”SubstitutionCaching.aspx.cs” Inherits=”SubstitionCaching” %>
// Sayfa 300 saniye boyunca önbelleklenecek…
<%@OutputCache Duration=”300″ VaryByParam=”none” %>
<!DOCTYPEhtml PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<htmlxmlns=”http://www.w3.org/1999/xhtml”>
<headrunat=”server”>
<title>Substitution Caching</title>
</head>
<body>
<formid=”form1″ runat=”server”>
<div>
// Dinamik olacak alan, Substitution kontrolü dinamik içerik oluşturabilmek için static bir metot bekliyor. Bekleyen özelliği de MethodName’dir.
<asp:Substitution ID=”Substitution1″ runat=”server” MethodName=”Tarih”/>
// Yada
<%Response.WriteSubstitution(new HttpResponseSubstitutionCallback(Tarih)); %>
</div>
</form>
</body>
</html>
</DIV>
Şimdi de önbelleklenen ve dinamik hale getirilen alanların değerlerine bakalım.
| İlk İstek | 300 Sn içindeki istekler | 300 Sn Sonra | |
| Page | 2009-02-18 12:21:00 | 2009-02-18 12:22:00 | 2009-02-18 12:26:00 |
| DinamikAlan | 2009-02-18 12:21:00 | 2009-02-18 12:21:01(Örneğin) | 2009-02-18 12:26:00 |
Caching mekanizmasını kullanarak sayfalarımızın daha performanslı çalışmasını sağladık JMakalenin sonuna geldik, başka bir makalede görüşmek üzere…
Sem GÖKSU
www.semgoksu.com | www.yazilimgunlugu.com
sem.goksu@yazilimgunlugu.com
Kaynaklar
msdn.com
Microsoft Data Access Application Block
Giris
.Net Framework, veritabanı ile çalısmak için yazılım gelistiricelere ADO.NET’i sundu. ADO.NET bize veriyi görüntülemek ve veri üzerinde islemler yapmamızı saglar. Veritabnındaki bazı bilgilere erismek ve uygulama üzerinde bazı parametreleri kullanabilecegini göz önünde bulunduralım. Bu islemi 6-7 satır kod yazarak kolayca yapabiliriz. Fakat, 5-6 satır kodu tekrar tekrar yazmak zorunda kaldıgımızda bu islemi yapmak kolay olmayacaktır.
Microsoft bunun için, Daha az kod ile ortak isleri yapmak için kullanılabilen Data Access Application Block’u gelistirdi. Data Access Application Block’u asagıdaki adresten indirebilirsiniz.
http://msdn2.microsoft.com/en-us/library/ms954827.aspx
Microsoft .net Data Access Application Block Nasıl Kullanılır ?
Ilk olarak Data Access Application Block Version 2.0.(Daha eski/yeni versionda olabilir) indirip kuralım. Ilk olarak the Microsoft .net Data Access Application Block projesi için .dll dosyası olusturacagız. Projeyi build ettikten sonra kendi projemize basitçe ekleyebiliriz. Kendi projemize ekledikten sonra bin klasörü içindeki .dll dosyasınıda build edelim.
Data Access Application Block olmadan Dataya Erismek
Ilk olarak Application olmadan veriye nasıl erisildigine bakacagız. Asagıda veritabanına 2 parametre ekleyen basit bir örnek yapacagız.
string connectionString = (string)
ConfigurationSettings.AppSettings["ConnectionString"];
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand("INSERT_MUSTERI",connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("@Name",SqlDbType.NVarChar,50));
command.Parameters["@Name"].Value = txtName.Text;
command.Parameters.Add(new SqlParameter("@Surname",SqlDbType.NVarChar,10));
command.Parameters["@Surname "].Value = txt Surname.Text;
connection.Open();
command.ExecuteNonQuery();
connection.Close();
Görüldügü gibi veritabanına parametre eklemeye çalıstıgımızda 6-7 satır kod ile isimizi tamamladık. Fakat 10 yada daha fazla parametre eklemeye çalıstıgımızda gelistirme zamanı bir hayli uzayacaktı.
Simdi aynı islemi Microsoft .net Data Access Application Block kullanarak yapalım.
using Microsoft.ApplicationBlocks.Data;
SqlHelper.ExecuteNonQuery(connection,"INSERT_MUSTERI",new
SqlParameter("@Name",txtName.Text) ,new SqlParameter("@Surname",txt Surname.Text) );
Gördügünüz gibi 5-6 satır kod yazmak yerine isimizi tek satırda tamamladık.
Bu islemi SqlHelper classı ile yaptıgımız gördük. Peki bu SqlHelper nereden çıktı?
Projemizin namespacelerine <I>Microsoft.ApplicationBlocks.Data </I>eklersek SqlHelper Classına erisebiliriz. SqlHelper Classı veritabanına erismek için static metodlar içeren ve Microsoft tarafından gelistirilen bir classdır. Her hangi bir text editörü ile SqlHelper Classını açabilir ve inceleyebilirsiniz.
SqlHelper Class
SqlHelper’in içindeki static metodlar;
ExecuteNonQuery
ExecuteDataSet
ExecuteReader
ExecuteScalar
ExecuteXMLReader
Evet artık örnegimize geçebiliriz. Ilk olarak bir Windows Application açalım.
Simdi SqlHelper Classını projemize ekleyelim. (DLL olarak da ekleyebiliriz).
Simdi projemizin namespacelerine ApplicationBlocks.Datayı ekleyelim.
using Microsoft.ApplicationBlocks.Data;
Ekledikten sonra formumuzun üzerine 1 adet buton ve bir gridview ekleyelim.
Evet Simdi ExecuteDataseti çalıstıracak kodları yazalım.
string sqlstring = "Select * from Musteriler";
dataGridView1.DataSource = SqlHelpera.ExecuteDataset("Data Source=localhost; Initial Catalog=SemGoksuDB; trusted_connection=yes", CommandType.Text, sqlstring).Tables[0];
Simdi projeemizi çalıstıralım.
Projemizi çalıstırdıktan sonra kayıtlarımızı listeledik. Gördügünüz gibi çok kolay bir sekilde 1-2 satır ile isimizi yaptık.
Bu makalenin de sonuna geldik, baska bir makalede görüsmek üzere basarı ve iyi günler dilerim.
Sem GÖKSU
MCP | MCAD.NET | MCTS
Örnek Kodlar için mail adresimi kullanabilirsiniz
Kaynaklar
http://msdn.microsoft.com












