SQL Server 2008 Yenilikleri - 1 (SQL Server 2008 Giriş)

by Administrator 15. Şubat 2009 16:17

Artık SQL Server 2008 yazma zamanı geldi. :) SQL Server 2008 yeniliklerini makale serisi şeklinde yazmaya çalışacağım. Öncelikle SQL Server versiyonlarına ve gereksimlerine bir göz atalım. Sonra SQL Server 2008 yeniliklerine değinelim.

Microsoft SQL Server Versiyonları :

· SQL Server 1.0 (1989): OS/2 için Microsoft, Sybase ve Ashton-Tate tarafından geliştirilmiştir.

· SQL Server 4.2 (1992): Windows NT 3.1 için geliştirilmiştir.

· SQL Server 6.0 (1995): Windows NT için belirli bir biçimde tasarlanmış ve planlanmış ilk versiyondur.

· SQL Server 7.0 (1999): Ölçeklenirlik ve performansı geliştirmek için tasarlanmış kod tabanlı SQL Server versiyonudur

· SQL Server 2000: Performans, Ölçeklenirlik ve Güvenilirlik için geliştirilmiş bir diğer versiyondur.

· SQL Server 2005: Yeni ve geliştirilmiş özellikler içerir. Geliştirilmiş özelliklere Integration Service, Analysis Service, Notification Service, Reporting Service, XML desteği sayılabilir.

Microsoft SQL Server 2008 Edition’ları

Enterprise:

Geniş ölçekli ve iş-kritik (business critical) uygulamalar için kullanılır. Aşağıdaki bileşenleri içerir.

· İş Kritik(Business Critical)

· Geniş düzeyde Online Transaction Processing (OLTP) desteği

· Geniş düzeyde raporlama

· İleri düzey mantıksal analiz

· Data Warehouse

Standart:

Orta ve küçük ölçekli departman uygulamaları için kullanılır. Aşağıdaki bileşenleri içerir.

· Departmanlar için tercih edilir.

· Orta ve Küçük düzeyde Online Transaction Processing (OLTP) desteği

· Raporlama ve Analiz Desteği

Workgroup:

Küçük ölçekli şube uygulamaları için kullanılır. Veri yönetimi, Raporlama fonksiyonları, Güvenlik ve Uzak senkronizasyon desteği sağlar. Aşağıdaki bileşenleri içerir.

· Şube uygulamaları için veri depolama

· Şube uygulamaları için raporlama

· Uzak senkronizasyon

Express:

Bağımsız Yazılım Geliştiricilerin(Independent Software Vendors –ISV) kullandığı ücretsiz SQL Server 2008 edition’ı dır.

 

Compact:

Embedded(gömülü) sistemlerde Embedded veritabanları için kullanılan ücretsiz SQL Server 2008 edition’ı dır. Mobile Cihazlar, Desktop Bilgisayarlar ve Web Client’ların veritabanı uygulamalarında kullanılır.

Developer:

Uygulama geliştirme ve test amaçlı kullanılır. SQL Server 20008 Enterprise ile aynı fonksiyonlara sahiptir.

SQL Server 2008 yeniliklerini aşağıdaki gibi sayabilirim.

· Configuration Servers

· Policy-Based Management

· Resource Governor

· Data Collector

· Plan Freezing

· Transparent Data Encryption

· Auditing All Actions

· FILESTREAM Data Type

· Spatial Data

· Hot Add CPU

· Conflict Detection

· Change Data Capture

· MERGE Statement

· Report Designer

· Analysis Services Wizards

Diğer makalelerimde bu yenilikleri tek tek anlatacağım.

Kaynak : 6158B- Updating Your SQL Server 2005 Skills to SQL Server 2008 (Beta,Early Release)

RESİM ÜZERİNE YAZI YAZMA

by Administrator 15. Şubat 2009 16:14

 

 

Hepiniz çoğu sitede, güvenlik kodu doğrulama olayını görmüşsünüzdür. Arka planda var olan bir resmin üzerine değişik karakterler yazılarak oluşturulur.

Bizde buna benzer bir uygulama ile resim üzerine nasıl yazı yazdıracağımızı göreceğiz.

 

1. Öncelikle WebSite / Add New Item menüsünden yeni bir Web Form açıp ismini Guvenlik.aspx olarak kaydediyoruz.

2. Üzerine yazı yazılmak üzere kendi zevkimize göre bir resim hazırlıyoruz. Aşağıda bizim kullanacağımız örnek resim bulunmaktadır.

3. Gerekli olan namespace tanımlamalarını yapıyoruz.

 

C#

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Drawing.Imaging;

using System.Drawing.Text;

 

Vb

 

Imports System.Drawing

Imports System.Drawing.Drawing2D

Imports System.Drawing.Imaging

Imports System.Drawing.Text

 

 

4. Page Load eventine kodlarımızı yazıyoruz.

 

C#

 

a) Bitmap ArkaPlanImage = new Bitmap(Server.MapPath("GuvenlikBg.jpg"));

b) Graphics GuvenlikKodu = Graphics.FromImage(ArkaPlanImage);

c) GuvenlikKodu.SmoothingMode = SmoothingMode.AntiAlias;

d) Random RastGele = new Random();

e) string Kodumuz = Convert.ToString(RastGele.Next(10000,99999));

f ) GuvenlikKodu.DrawString(Kodumuz, new Font("Monotype corsiva", 25, FontStyle.Italic), SystemBrushes.WindowText, new Point(10, 3));

g) Response.ContentType = "image/jpeg";

h) ArkaPlanImage.Save(Response.OutputStream, ImageFormat.Gif);

i) GuvenlikKodu.Dispose();

j) ArkaPlanImage.Dispose();

 

Vb

 

a) Dim ArkaPlanImage As New Bitmap(Server.MapPath("GuvenlikBg.jpg"))

b) Dim GuvenlikKodu As Graphics = Graphics.FromImage(ArkaPlanImage)

c) GuvenlikKodu.SmoothingMode = SmoothingMode.AntiAlias

d) Dim RastGele As New Random

e) Dim Kodumuz As String = Convert.ToString(RastGele.Next(10000, 99999))

f) GuvenlikKodu.DrawString(Kodumuz, New Font("Monotype corsiva", 25, FontStyle.Italic), SystemBrushes.WindowText, New Point(10, 3))

g) Response.ContentType = "image/jpeg"

h) ArkaPlanImage.Save(Response.OutputStream, ImageFormat.Gif)

i) GuvenlikKodu.Dispose()

j) ArkaPlanImage.Dispose()

 

 

Kodlarımızı yazdık şimdi açıklamaya geçelim.

a) Arka planda kullanacağımız resmi seçiyoruz.

b) Seçtiğimiz resmi grafik nesnesine atıyoruz.

c) Grafiğimizin kalitesini belirliyoruz. AntiAlias olan değerimizi HighQuality, Default, HighSpeed, Invalid yapabiliriz.

d) Rastgele sayı oluşturmak için Random nesnemizi oluşturuyoruz.

e) 10000 ile 99999 arasında bir sayı üretip Kodumuz adlı değişkene aktarıyoruz. Sayıyı istediğiniz aralıkta belirtebilirsiniz.

f) Resmimizin üzerine yazılacak olan değeri, yazı tipini, boyutunu, stilini ve değerin, resmin hangi x,y koordinatlarından yazılmaya başlanacağını belirtiyoruz.

g) Sayfa çıktısını image/jpeg olarak ayarlıyoruz.

h) Resmimizi gif formatında ekrana yazıyoruz.

i) GuvenlikKodu isimli Graphics nesnemizi kapatıyoruz.

j) ArkaPlanImage isimli Bitmap nesnemizi kapatıyoruz.

 

5. Web Site / Add New Item Menüsünden yeni bir sayfa daha açıyoruz.

6. Html kontrollerinden Image kontrolü ekleyip kaynağına Guvenlik.aspx dosyasını belirtiyoruz. Guvenlik.aspx sayfasının çıktısı image/jpeg formatında olduğu için image kontrolümüzde resmimiz görünecektir.

 

<img src="GuvenlikKodu.aspx" />

 

 

 

SQL Server 2005: Uzaktan Bağlantı

by Administrator 1. Şubat 2009 08:22
Bir SQL Server Instance' ına uzaktan bağlanma konusunda gerek forumlardan gerekse habergruplarından çok soru geliyor. En güzeli bu konuda bir yazı yazmak dedim ve bu makaleyi klavyeye(!) (kaleme?) aldım.

Bir SQL Server Instance' ına uzaktan bağlanabilmeniz için, kurulu olan SQL Server Instance' ının sürüm (Edition) bilgisi, SQL Server Instance' ının üzerinde kurulu olduğu İşletim Sistemini bilgisi öncelikle dikkate almanız gereken bilgilerdir.

Peki neden? Çünkü, meselâ SQL Server 2005' in Express Edition ve Developer Edition' larında, uzaktan bağlantı için kullanılabilecek TCP/IP ve Named Pipes protokolleri kapalıdır. Bu protokoller konusunda daha fazla bilgi almak için Bağlantı Protokolleri isimli yazımı okuyabilirsiniz.

Windows XP SP2 ve Windows' un daha sonraki sürümlerinde ise Windows Güvenlik Duvarı vardır ve bu uygulama etkin olduğunda SQL Server 2005 Instance' ınıza uzaktan erişimi engeller. Çünkü varsayılan olarak SQL Server' ın kullandığı portlar Windows Güvenlik Duvarında açık değildir.

Uzaktan Bağlantı için Yapılması Gerekenler
1 - SQL Server Instance' ınızın ilgili protokolünün yapılandırılması,
2 - Eğer varsa ve etkinse, Windows Güvenlik Duvarının yapılandırılması
3 - SQL Server' ınıza bağlanabilmeniz için kullanacağınız Login.

1- SQL Server Protokollerinin Yapılandırılması:
SQL Server 2005 Instance' ınız için hangi protokolü kullanacağınızı belirledikten sonra, bu protokolün yapılandırmasını gerçekleştirirsiniz. SQL Server protokollerinin yapılandırılması işlemleri için SQL Server 2005 ile birlikte gelen SQL Server Configuration Manager' ı kullanabilirsiniz. (Başlat\Programlar\Microsoft SQL Server 2005\Configuration Tools) Konuya örnek olması için aşağıda TCP/IP protokolünün nasıl yapılandırılabileceğini anlatacağım.

TCP/IP Yapılandırması Örneği:
SQL Server 2005 Instance' ınıza uzaktan yapılacak bağlantılarda kullanılacak TCP/IP protokolünü yapılandırmak için SQL Server Configuration Manager' ı başlatın.

Daha sonra, Şekil-1' de de gösterdiğim gibi SQL Server 2005 Network Configuration düğümü altından uzaktan bağlantı kurulmasını istediğiniz SQL Server 2005 Instance' ınızı seçin. Benim örneğimde bu, TEST2 Instance' ı olacak.


Şekil-1


TCP/IP protokolünü etkinleştirmek veya etkin olduğundan emin olmak için, Şekil-1' de de gösterildiği gibi Protocol Name alanındaki TCP/IP protokolünün Status değerine bakabilirsiniz. "Enabled" etkin olduğu anlamına gelir, "Disabled" ise etkin değil demektir. Bu değeri değiştirmek için TCP/IP protokolünün üzerinde fare ile çift tıklayın veya TCP/IP protokolünün üzerinde farenin sağ tuşuna tıklayarak, açılan menüden "Properties" seçeneğine tıklayarak "TCP/IP Properties" penceresini açın.

Şekil-1' de gösterildiği gibi "TCP/IP Properties" penceresi açılacaktır. TCP/IP protokolünü etkinleştirmek için, "TCP/IP Properties" penceresindeki "Protocol" isimli sekmede bulunan "Enabled" etiketinin karşısındaki aşağı açılır listeden "Yes" değerini seçin.

"Protocol" sekmesindeki "Listen All" seçeneği önemli bir seçenek bu nedenle buna da değinmek istiyorum. "Listen All", bilgisayara bağlı tüm Ağ Kartlarının (Örn:Ethernet) IP adreslerinin SQL Server tarafından dinlenip dinlenmeyeceğini belirler. Eğer bu seçeneğin değeri "No" yapılırsa, biraz sonra da değineceğim gibi "IP Addresses" sekmesindeki her IP adresini tek tek yapılandırmanız gerekir ve gene aynı sekmede bulunan "IPAll" seçeneklerinin herhangi bir geçerliliği kalmaz. Eğer değeri "Yes" yaparsanız, o zaman gene "IP Addresses" sekmesindeki "IPAll" seçenekleri etkinleşir ve diğer tüm IP adreslerine uygulanır. "Listen All" u etkinleştirdikten sonra "IPAll" seçeneğindeki ayarların, diğer ayarları bastıracağı unutmayın, yoksa ileriki paragraflarda aklınız karışabilir.

TCP/IP protokolünün IP adresi veya Port ayarlarını yapılandırmak için, gene "TCP/IP Properties" penceresinde bulunan "IP Addresses" isimli sekmeye tıklayın. (Bakınız: Şekil-2)


Şekil-2

Bu listede her Ağ Adaptörünüz için bir IP ayar bölümü listelenecektir.

Hangisinin etkinleştirilmesini istiyorsanız, onun "Active" ve "Enabled" ayarlarının karşısındaki değerleri "Yes" durumuna getirin. "Active", o IP adresinin dinleneceğini belirtir. "Enabled" ise o IP adresinin kullanılıp kullanılmayacağını. "IP Address" bölümde ise IPv4 veya IPv6 değeri yer alır. Eğer "TCP Dynamic Ports" etiketinin değeri "0" ise, bunun anlamı bu IP adresi için kullanılacak portun dinamik bir şekilde belirleneceğidir. Bu durumda SQL Server, bu IP adresi için müsait olan bir port numarası atayacaktır.

Meselâ Şekil-2' deki örnekte, TEST2 SQL Server Instance' ı, Dinamik Port olarak atanan 51495 portunun tüm IP' ler tarafından dinlenilmesi için yapılandırılmış. (Bu örnekte, "Protocol" sekmesindeki  "Listen All" değerinin "Yes" olduğunu Şekil-1' den anımsayın, aksi takdirde IPAll değerlerinin bir geçerliği olmadığını daha önceki paragraflarımdan hatırlıyor olmalısınız.) Eğer tüm IP' lerin durağan bir IP kullanmasını isteseydik, o zaman "TCP Dynamic Ports" un değerini boş bırakıp, TCP Port' un değerine, kullanılmasını istediğimiz IP numarasını yazacaktık. Bu amaçla, 65535' e kadar müsait bir port numarası seçebilirsiniz.

Şimdi aklınıza şu da takılıyor olabilir, "biz dinamik port kullanacağımız zaman TCP Dynamic Port' s 0 yazıyoruz, nasıl oluyor da orada şimdi 51495 yazıyor?" Çünkü SQL Server bu IP' ye bir dinamik IP atadığı zaman, 0 yerine bu dinamik IP' yi görüyorsunuz.

Şekil-2' de gördüğünüz gibi 192.168.2.2 numaralı IP için iki tane port numarası kullanılmış. Eğer bir IP' nin birden çok port kullanmasını istiyorsanız, o zaman birden çok Port numarasını virgüllerle ayırarak yazabilirsiniz. Bu IP' ye Port numaraları yazılmış, ama peki IPAll' da da dinamik port (51495) kullanıyoruz? Hangisi geçerli olacak? Hemen bir kaç paragraf önceki yazımdan da hatırladığınızı varsayıyorum! Neydi? Eğer "Protocol" sekmesindeki "Listen All" un değeri "Yes" ise, o zaman IPAll' da yazan değerler, diğer değerleri bastırırdı. Yani bu durumda, eğer "Listen All" un değeri "No" olsaydı, 192.168.2.2 numaralı IP, 51495 numaralı dinamik portu değil, 16666 ve 46123 numaralı statik portları kullanacaktı. Bu kadar örnekten sonra bu kavramların oturtuğunu varsayıyorum. 

SQL Server Instance' ınıza uzaktan bağlanabilmek için size durağan (Static) portları kullanmanızı tavsiye ederim. Bu nedenle, Şekil-2 deki "TCP/IP Properties" penceresindeki ilgili IP' nin "TCP Dynamic Ports" etiketinin değerini boş bırakmanızı tavsiye ederim. Yani orada ne "0" ne de başka bir değer yazmasın ve gene aynı penceredeki "TCP Port" etiketinin değerine müsait bir port numarası girin ve bu ayarların geçerli olabilmesi için, protokolün ait olduğu SQL Server Instance' ının SQL Server servisini durdurup tekrar başlatın.

Peki SQL Server Instance' ınızın hangi port numarasını dinlediğini nasıl teyit edeceksiniz? Bunun için Komut İstemcisi (Command Prompt) u kullanabilirsiniz. Komut İstemcisini çalıştırın (Başlat\Çalıştır ve tırnak içindeki komutu yazın "cmd" ve çalıştırın.)

O anki TCP/IP bağlantılarını ve protokol istatistiklerini görüntüleyebilmemiz için Komut İstemcisinde Netstat komutunu kullanabiliriz. Hangi Protokolün ve IP numarasının hangi portu kullandığını ve durumunu görüntülemek için "Netstat -a" komutunu kullanacağız. Bu komut hakkında daha fazla bilgi alabilmek için Komut İstemcisindeyken "Netstat -?" komutunu çalıştırabilirsiniz.

Aşağıdaki Şekil-3' te "Netstat -a" komutunu çalıştırdıktan sonra nasıl bir görüntüyle karşılaşacağınızı görebilirsiniz.


Şekil-3

Beyaz çerçeve ile işaretlediğim aralıkta, 192.168.2.2 IP numaralı SQL Server sunucumuzun 16666 ve 46123 numaralı portları dinlediğini (LISTENING) görebilirsiniz.


2 - Windows Güvenlik Duvarının Yapılandırılması:
Bu konuda Microsoft tarafından yazılmış bir makale zaten mevcut için benim bu konuda daha fazla bir şey yazmama gerek kalmıyor. Buraya tıklayarak bahsini ettiğim makaleye ulaşabilirsiniz.

Ahh ama bir şey de eklemeden edemeyeceğim! Bazı durumlarda bu işlemleri yapmanın da yetersiz kaldığını gördüm. Meselâ bir müşterimiz tüm bunları yaptığı halde gene de uzaktaki SQL Server sunucusuna bağlanamıyordu. Nedeni ise, modemindeki Güvenlik Duvarı ve kısıtlamalardı. Yani, modeminizdeki yapılandırmayı da gözden geçirmenizde yarar var. Aksi takdirde günlerce uğraşır sorunu çözemezsiniz...

3- Login:
Çoğunuzun bildiği gibi SQL Server' da Authentication Mode (Yetkilendirme Modu) olarak iki adet seçeneğimiz bulunuyor. Birisi Windows Authentication, diğeri ise SQL Authentication (veya Mixed Authentication).

Windows Authentication' ı sadece güvenilir ortamlarda kullanabilirsiniz. Nedir güvenilir ortamlar? Meselâ aynı Domain' in parçasıysanız güvenik ilişkisi olan bir ortamdasınızdır. Eğer yetkileriniz izin veriyosa, kendi Domain hesabınızla aynı Domain' in parçası olan diğer kaynakları kullanabilirsiniz. Bizim konumuzla alâkalı bir örnek vermek gerekirse, SQL Server Instance' ınıza bir Domain Güvenlik Grubunun bir üyesi olarak veya bir Domain hesabıyla bağlanabilirsiniz. SQL Server için herhangi bir şifre girmenize de gerek kalmaz. Mümkün olan her senaryoda bu Authentication Mode' unu kullanmanızı tavsiye ederim. SQL Authentication' dan çok daha güvenlidir. Zaten Microsoft' da bunu tavsiye eder ve dokümanlarında da SQL Authentication' ı sadece geriye destek için hâlâ barındırdıklarını söylüyorlar.

SQL Login deyince benim aklıma hemen "sa" geliyor. Çünkü kullanıcıların yaptığı bu yanlışı o kadar çok gördüm ki...

Arkadaşlar! Lütfen her şey için "sa" hesabını kullanmayın! KULLANMAAAAYIN! Çünkü "sa" hesabı "sysadmin" sabit sunucu rolü üyesi (ve bu rolden çıkarılamaz) bir hesaptır.

SQL Server 2005 Instance' ınızı kurarken Authentication Mode olarak eğer Windows Authentication' ı seçmiş iseniz, o zaman "sa" hesabı otomatik olarak kullanılamaz olacaktır. Tabi ta ki siz onu etkinleştirip, Authentication Mode' unu da Mixed Authentication yapmadığınız sürece. Eğer SQL Server 2005 Setup' taki Authentication Mode bölümünde Mixed Authentication' ı işaretlediyseniz, o zaman "sa" hesabı kullanılabilir olacaktır.

"sa" hesabını neden kullanmamalıyız konusuna SQL Server 2008: Güvenlik ile ilgili değişiklikler isimli yazımda deyinmiştim. Tekrar tekrar aynı şeyleri yazmanın gereği yok, o yüzden ilgilenenler, o yazımdaki "sa" hesabıyla ilgili yazdıklarımı okuyabilirler.

Eğer bağlanacağınız SQL Server Instance' ı ile güvenilir bir ortamda değilseniz, o zaman SQL Authentication yoluyla bir SQL Login kullanarak bağlanabilirsiniz.

Login hakları ise bu konunun ötesinde bir konu.

Tags:

SQL

Domain'de Bulunan Bilgisayarların Listesini Almak

by Administrator 31. Ocak 2009 17:03

Aşağıda bulunan kod parçaları sayesinde bir domainde bulunan bilgisayarlara ait listeyi almak mümkündür. Bu metodları kullanmak için System.DirectoryServices namespace'inin projenizde referans olarak ekli olması gerekmektedir. 

public List<string> GetComputersInDomain(string domainName)
        {
            DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName);
            DirectorySearcher searcher = new DirectorySearcher(entry);
            searcher.Filter = "(objectClass=computer)";
            List<string> result = new List<string>();
            foreach (SearchResult sr in searcher.FindAll())
            {
                result.Add(sr.GetDirectoryEntry().Name.ToString());
                
            }
            return result;
        }

Tags:

Csharp

T.C. Kimlik Numarası Doğruluk Kontrolü

by Administrator 31. Ocak 2009 17:01

Aşağıda bulunan kod parçacığı sayesinde uygulamalarınızda kullanıcı tarafından girilen bir TC Kimlik numarasının doğru olup olmadığını kontrol edebilirsiniz. 

private bool ValidateNumber(string parNumber)
        {
            for (int i = 0; i < parNumber.Length; i++)
            {
                if (!(char.IsNumber(parNumber[i]))) return false;
            }
            return true;
        }


        public void ValidateTCIdentityNumber(string TCIdentityNumber)
        {
            if (ValidateNumber(TCIdentityNumber.Trim()))
            {
                if (TCIdentityNumber.Trim().Length < 11)
                {
                    throw new Exception("T.C. Kimlik Numarası 11 karakterden az olamaz. Lütfen kontrol ediniz.");
                }
                else
                {
                    decimal identityNumberDecimal = Convert.ToDecimal(TCIdentityNumber.Trim());
                    decimal temp = Math.Floor(identityNumberDecimal / 100);
                    decimal temp1 = Math.Floor(identityNumberDecimal / 100);
                    int[] D = new int[10];
                    for (int n = 9; n >= 1; n--)
                    {
                        D[n] = (int)temp1 % 10;
                        temp1 = Math.Floor(temp1 / 10);
                    }
                    int oddSum = D[9] + D[7] + D[5] + D[3] + D[1];
                    int evenSum = D[8] + D[6] + D[4] + D[2];
                    int total = oddSum * 3 + evenSum;
                    int ChkDigit1 = (10 - (total % 10)) % 10;
                    oddSum = ChkDigit1 + D[8] + D[6] + D[4] + D[2];
                    evenSum = D[9] + D[7] + D[5] + D[3] + D[1];
                    total = oddSum * 3 + evenSum;
                    int ChkDigit2 = (10 - (total % 10)) % 10;
                    temp = (temp * 100) + (ChkDigit1 * 10) + ChkDigit2;
                    if (temp != identityNumberDecimal)
                    {
                        throw new Exception("T.C. Kimlik Numaranızı kontrol ediniz.");
                    }
                }
            }
            else
            {
                throw new Exception("T.C. Kimlik Numarası yalnızca rakamlardan oluşmalıdır. Lütfen kontrol ediniz.");
            }
        }

Tags:

Csharp

Thumbnail Oluşturmak

by Administrator 31. Ocak 2009 16:59

Bu kod parçasını uygulamalarda kullanıcılar tarafından yüklenen resimlerin thumbnail lerini otomatik olarak oluşturmak için kullanabilirsiniz.  

public void SaveThumbnail(string path,string thumbnailPath,int newWidth,int newHeight)
        {
            System.Drawing.Image i = System.Drawing.Image.FromFile(path);
            System.Drawing.Image thumbnail = new System.Drawing.Bitmap(newWidth, newHeight);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(thumbnail);
            g.DrawImage(i, 0, 0, newWidth, newHeight);
            thumbnail.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg);
        }

Tags:

Csharp

LINQ : Daha Fazla Sorgu

by Administrator 31. Ocak 2009 16:56
 

Bu günlerde hepimiz .Net Framework 3.0 ve getirileri üzerine yoğunlaşmış durumdayız. Özellikle mimari anlamda yapılan köklü değişimler söz konusu. Bu köklü değişiklikler; Windows uygulamalarının yeni yüzü olan WPF (Windows Presentation Foundation) ve XAML (eXtensible Application Markup Language), dağıtık mimariyi tek çatı altında toplamayı başaran WCF (Windows Communication Foundation), akış şemaları ve iş süreçlerinin .Net plaformuna dahil edilmesini sağlayan WF(Workflow Foundation) ve CardSpace olarak sıralanabilir. Ancak bunların dışında Microsoft’ un gelecek vizyonu içerisinde yer alan en önemli konulardan biriside C# 3.0 konusudur. Bildiğiniz gibi C#, sıfırdan geliştirilmiş ve atası olan nesne yönelimli dillerin en iyi özelliklerini bünyesinde birleştirerek bunu güçlü bir Framework üzerinde kullanabilmemizi sağlayan bir dildir. Zaman içerisinde C# 2.0 ile gelen yenilikler şu anda tüm C# geliştiricilerin hayatının bir parçası haline gelmiştir. Şimdi herkesin gözü C# 3.0 üzerinde.

C# 3.0, beraberinde LINQ (Language Integrated Query), DLINQ (Database Language Integrated Query) ve XLINQ (Xml Language Integrated Query) gibi yeni teknolojileride getirmekte ve desteklemektedir. Biz bu makalemizde daha fazla LINQ ifadesi yazmaya çalışacağız. Onbir basit LINQ ifadesi ile dil tabanlı sorguları daha yakından tanımaya başlıyacak ve elimizdeki gücün farkına varacağız. Bildiğiniz gibi LINQ (Language Integrated Query) özellikle dil içerisinde, Sql tarzı sorgular yazabilmemizi ve bunları var olan IEnumerable<T> türevli tipler üzerinde kullanabilmemizi sağlamaktadır. Ancak özellikle LINQ içerisinde kullanılabilen operatörler göz önüne alındığında, oldukça etkili sonuçlar alabileceğimiz  ortadır. Temel olarak LINQ içerisindeki operatörler aşağıdaki başlıklar altında toplanmıştır. (Elbetteki bu bilgiler hala deneme aşamasında olan bir sürece aittir ve değişebilir.)

  • Kısıtlama Operatörleri (Restriction Operators) -> Where
  • Gruplama Operatörleri (Grouping Operators) -> Group
  • Sıralama Operatörleri (Ordering Operators) -> OrderBy, ThenBy, Reverse
  • Bölümleme Operatörleri (Partitioning Operators) -> Take, Skip, TakeWhile, SkipWhile
  • Seçme Operatörleri (Projection Operators) -> Select
  • Set Operatörleri (Set Operators) -> Distinct, Union, Intersect, Except
  • Dönüştürme Operatörleri (Conversion Operators) -> ToArray, ToList, ToDictionary, OfType
  • Eleman Operatörleri (Element Operators) -> First, FirstOrDefault, ElementAt
  • Üretim Operatörleri (Generation Operators) -> Range, Repeat
  • Gruplama Fonksiyonu Operatörleri (Aggregate Operators) -> Count, Sum, Min, Max, Averaga, Fold
  • Ölçüm Operatörleri (Quantifiers Operators) -> Any, All
  • Çeşitli Operatöler (Miscellaneous Operators) -> Concat, EqualAll
  • Özel Seri Operatörleri (Custom Sequence Operators) -> Combine

Şimdi gelin bu operatörlerin bir kısmını incelemeye çalışalım. Öncesinde program ortamında ele alabileceğimiz bazı veri kümelerine ihtiyacımız olacak. Bu veri kümeleri tamamıyla test amaçlı olacaktır. Bunun için AdventureWorks veritabanında yer alan Product ve ProductSubCategory tablolarından faydalanabiliriz. Amacımız ilk olarak buradaki tablolardan test amacıyla kullanabileceğimiz veri kümelerini program ortamı içerisinde yer alan generic koleksiyonlara aktarmaktır. LINQ konusu söz konusu olduğu içinde, C# 3.0 dili özelliklerinden de faydalanmaya çalışacağız.
 

Var olan Visual Studio 2005 sürümünde LINQ projeleri yazmak ve test edebilmek için LINQ Preview proje şablonunu kullanamız gerekmektedir. Özellikle C# 3.0 yenilikleri ile ilişkili olarak Sefer Algan’ ın konu ile ilgili makalesinden faydalanabilirsiniz.

Yardımcı sınıfımızın kodları aşağıdaki gibidir.

Product Sınıfı;
 

public class Product
{
    public int ProductId;
    public string Name;
    public double ListPrice;
    public DateTime SellStartDate;
    public DateTime SellEndDate;
    public int ProductSubCategoryId;

    public override string ToString()
    {
        return ProductId.ToString() + " " + Name + " " + ListPrice.ToString("C2") + " " + SellStartDate.ToString() + " " + SellEndDate.ToString() + " " + ProductSubCategoryId.ToString();
    }
}

ProductSubCategory Sınıfı;
 

public class ProductSubCategory
{
    public int ProductSubCategoryId;
    public string Name;

    public override string ToString()
    {
        return ProductSubCategoryId.ToString() + " " + Name;
    }
}

Product ve ProductSubCategory sınıflarımızda dikkat ederseniz özellik (Property) kullanmadık. Ayrıca içerideki elemanlara ilk değerlerini kolayca atayabilmek için yapıcı metod (constructor) da yazmadık. Burada C# 3.0 ile gelen nesne başlatıcılarını (object initializers) kullanacağımız için özellike ve yapıcı metod kullanımını terk ettik. Şimdi bu tiplerden üyelere yükleme yapacak olan Helper sınıfımızın kodlarınıda aşağıdaki gibi geliştirelim.

Helper.cs
 

public class Helper
{
    public static List<Product> UrunleriYukle()
    {
        List<Product> urunler = new List<Product>();
        using (SqlConnection conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated security=SSPI"))
        {
            SqlCommand cmd = new SqlCommand("SELECT ProductID, Name, ListPrice, SellStartDate, SellEndDate, ProductSubcategoryID FROM Production.Product WHERE (Name IS NOT NULL) AND (ListPrice IS NOT NULL) AND (SellStartDate IS NOT NULL) AND (SellEndDate IS NOT NULL) AND (ProductSubcategoryID IS NOT NULL)", conn);

            conn.Open();
            SqlDataReader dr=cmd.ExecuteReader();
            while (dr.Read())
            {
                // Object Initializers kullanarak nesneye ilk değerlerini atıyoruz.
               
Product urn=new Product{ProductId=Convert.ToInt32(dr["ProductID"]),Name=dr["Name"].ToString(),ListPrice=Convert.ToDouble(dr["ListPrice"]),SellStartDate=Convert.ToDateTime(dr["SellStartDate"]),SellEndDate=Convert.ToDateTime(dr["SellEndDate"]),ProductSubCategoryId=Convert.ToInt32(dr["ProductSubCategoryId"])};
                urunler.Add(urn);
            }
        }
        return urunler;
    }

    public static List<ProductSubCategory> AltKategorileriYukle()
    {
        List<ProductSubCategory> altKategorileri = new List<ProductSubCategory>();
        using (SqlConnection conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated security=SSPI"))
        {
            SqlCommand cmd = new SqlCommand("SELECT ProductSubCategoryId,Name From Production.ProductSubCategory", conn);

            conn.Open();
            SqlDataReader dr=cmd.ExecuteReader();
            while (dr.Read())
            {
                // Object Initializers kullanarak nesneye ilk değerlerini atıyoruz.
               
ProductSubCategory subCat=new ProductSubCategory{ProductSubCategoryId=Convert.ToInt32(dr["ProductSubCategoryId"]),Name=dr["Name"].ToString()};
                altKategorileri.Add(subCat);
            }
        }
        return altKategorileri;
    }
}

UrunleriYukle ve AltKategorilerYukle isimli metodlarımız sadece bize yardımcı olacak üyelerdir. Dikkat ederseniz her ikiside generic List koleksiyonu tipinden değişkenler döndürmektedirler. Biz bu koleksiyonlar üzerinde LINQ sorgularımızı denemeye çalışacağız. Testleri daha kolay yapabilmek için şimdilik bir Console uygulamasından devam edeceğiz. Dilerseniz ısınma turlarımızda basit Select ve Where kullanımları ile başlayalım.

Sorgu 1: Ürünlerden belirli bir alt kategoride olanların bulunması.
 

var products = Helper.UrunleriYukle();
var subCategories=Helper.AltKategorileriYukle();

Console.WriteLine("\nProductSubCategoryId’ si 1 olan Urunler\n");

var resultSet=
from p in products
                          where p.ProductSubCategoryId==1
                            select p;


foreach(Product prd in resultSet)
    Console.WriteLine(prd.ToString());

İlk olarak kaynak verilerimizi Helper sınıfı içerisine dahil ettiğimiz static metodlarımız yardımıyla yüklüyoruz. (Buradan sonraki örnek kodlarımızda products ve subCategories isimli değişkenlerin taşıdığı koleksiyon verilerini kullanacaktır.) Bu işlemler sırasındada veri tipini kolayca kullanabilmek için var anahtar sözcüğünden faydalanmaktayız. Sorgu ifademiz içerisinde select, where ve from anahtar sözcükleri kullanılmaktadır. İfademize göre products isimli koleksiyon içerisindeki her bir nesne örneği p adıyla tanımlanmaktadır. Sonrasında ise bu p adlı nesnelerden ProductSubCategoryId özelliğinin değeri 1 olanların çekilmesi sağlanmıştır. Dikkat ederseniz, p nesnesinin işaret ettiği tür Product tipi olduğu için p.ProductSubCategoryId gibi bir ifade yazılabilmiştir. Uygulamamızı çalıştırdığımızda aşağıdaki ekran görüntüsüne benzer bir sonuç alırız.

Şimdi elimizde LINQ gibi bir seçenek olmadığını düşünelim. Bu durumda yukarıdaki ihtiyacı karşılamak için aşağıdakine benzer bir kod parçası yazabilirdik. Önce, generic koleksiyon içerisinde dolaşır, her bir Product nesnesinin ProductSubCategoryId değerine bakar ve 1 olanları, başka bir generic List koleksiyonu içerisinde toplardık.
 

List<Product> urunler = new List<Product>();

foreach (Product prd in products)
    if (prd.ProductSubCategoryId == 1)
        urunler.Add(prd);

Lakin daha karmaşık sorgulama ifadeleri göz önüne alındığında durum dahada zorlaşabilir. İmkansız değildir ama daha fazla kod yazmamızı, efor sarfetmemizi ve zaman zaman optimizasyonu zor olacak kodlar üretmemize neden olacak durumlarla karşılaşabiliriz. Örneğin, Alt Kategorilerin ve Urunlerin birbirleriyle birleştirileceğini, birleştirilen küme üzerinde gruplama yapılacağını ve hatta bu gruplamalara göre toplam fiyat, toplam ürün sayısı gibi değerlerin elde edileceğini düşünebiliriz. (Bu pek çok Sql programcısına tanıdık gelecek bir ihtiyaçtır.) Bu tarz bir ihtiyacı karşılayacak kod parçasını elbetteki yazabiliriz. Ama LINQ ile bunu ve benzerlerini çok daha basit bir biçimde, tek satırlık ifadelerde gerçekleştirme şansına sahibiz. Dilerseniz yeni örnekler ile alıştırmalarımıza devam edelim.

Sorgu 2: Liste fiyatı 3000 birimin üzerinde olan ürünleri isimlerine göre tersten sıralı olacak şekilde elde etmek.
 

var resultSet2=from p in products
                       
where p.ListPrice>=3000
                           
orderby p.Name descending
                               
select p;

Console.WriteLine("\nFiyatı 3000’ den büyük olan Urunler. Name alanına göre tersten sıralı. \n");

foreach(Product prd in resultSet2)
    Console.WriteLine(prd.ToString());

Dikkat ederseniz Liste fiyatına göre kontrol işlemini gerçekleştirmek için yine where operatöründen faydalanıyoruz. Sıralamayı Product tipindenki Name alanına göre tersten sıralatmak istediğimiz içinde, orderby  ve descending anahtar sözcüklerinden faydalanmaktayız. Kodu bu şekilde denediğimizde aşağıdaki gibi bir ekran çıktısını elde ederiz.

Sorgu 3: Fiyatı 1000 ile 1500 birim arasında olan ürünleri isimlerine göre tersten sıralayarak elde etmek.
 

Console.WriteLine("\nFiyatı 1000 ile 1500 arasında olan ürünlerin Name alanına göre tersten sıralanmış listesi\n");

var resultSet3=
from p in products
                       
where p.ListPrice>=1000 && p.ListPrice<=1500
                           
orderby p.Name descending
                               
select p;

foreach(Product prd in resultSet3)
    Console.WriteLine(prd.ToString());

Sorgu 2’ dekine benzer şekilde yazılan bu kod parçasında tek fark && (ve) operatörünün kullanılmasıdır. Kod çalıştırıldığında aşağıdaki ekran görüntüsündekine benzer bir sonuç elde ederiz. Bu seferki sorgu cümlemiz ListPrice alanı için bir değer aralığı belirlemekte ve bu kritere uyan tüm ürünleri elde etmemizi sağlamaktadır.

Sorgu 4: Urunler listesindeki elemanları elde ederken isimsiz bir tipten yararlanmak.

C# 3.0 beraberinde isimsiz tip (Anonymous Type) adı verilen yeni bir kavram ile birlikte gelmektedir. Diyelim ki LINQ ifadesi sonrasıda çekilen veri kümesi içerisindeki elemanları taşıyan yeni bir tipi kullanmak istemiş olalım. Çok doğal olarak, sorgulamak istediğimiz veri kümesi ne olursa olsun, önceden planlamadığımız şekilde bir tipe ihtiyacımız olması doğaldır. İşte isimsiz tip bize bu konuda yardımcı olabilmektedir. Örneğimizde bunun basit bir kullanımı gösterilmektedir. Dikkat ederseniz, Product tipine ait Name ve ListPrice alanlarını sırasıyla UrunAdi ve Fiyat olarak taşıyan yeni bir tip tanımlanmış ve foreach iterasyonu içerisinde kullanılmıştır. (İsimsiz tipler aslında tanımlandıkları yerde oluşturulan tipler olarak da düşünülebilir. Dolayısıyla proje derlendiğinde aşağıda karşılaşılan satır için yeni bir tip CIL tarafına yazılmaktadır.)
 

Console.WriteLine("\nSelect sorgularında Anonymous Type Kullanımı\n");

var resultSet4=
from p in products
                       
select new {UrunAdi=p.Name,Fiyat=p.ListPrice.ToString("C2")};

foreach(var prd in resultSet4)
    Console.WriteLine(prd.UrunAdi+" "+
prd.Fiyat);

Örneğimizi çalıştırdığımızda aşağıdakine benzer bir sonuç elde ederiz.

Sorgu 5: Sql’ de Join sorgusu olurda LINQ içerisinde olmaz mı?

Hepimiz Sql tarafında farklı tabloları birleştirmek için Join ifadelerinden faydalanırız, faydalanmaktayız. Aynı özellik LINQ ile, .Net platformuna da taşınmıştır. İşte aşağıda örnek bir sorgu. Bu sorguda products ve subCategories isimli değişkenlerde tutulan koleksiyonların içerdikleri verileri ProductSubCategoryId alanlarının değerlerine göre birleştiriyoruz. Elde edilen sonuç kümesinde, her iki koleksiyonda da var olan özelliklerden kombine edilecek yeni bir tip olsa hiç de fena olmaz aslında. İşte isimsiz tipimizin devreye gireceği yer burası olacaktır. (Bu tip bir ihtiyacı birde LINQ eklentilerini kullanmadan yapmayı denersek, sorgu ifadelerinin gelecekte hayatımızı oldukça kolaylaştıracağını daha kolay anlayabiliriz.) Birleştirme operasyonu için join anahtar kelimesinden yararlanılmaktadır. on anahtar kelimesinden sonra ise bildiğimiz kriter uygulaması gerçekleştirilmektedir.
 

var resultSet6=from prd in products
                        
join ctg in subCategories
                            
on prd.ProductSubCategoryId equals ctg.ProductSubCategoryId
                                
select new{prd.ProductId,prd.Name,prd.ListPrice};
 
 foreach(var p in resultSet6)
     Console.WriteLine(p.ToString());

Programımızın ekran çıktısı aşağıdakine benzer olacaktır.

Ekrandaki çıktı tesadüf değildir. İsimsiz tiplerin ToString metodunun bir sonucudur.
 
Bir isimsiz tip tanımlandığında bu tip için CIL tarafına eklenen kodlar içerisinde ToString metodu ezilip yukarıdakine benzer bir string döndürmesi sağlanmıştır. Bu kodu herhangibir decompiler aracı ile açtığınızda da görebilirisiniz.

Sorgu 6: Urunler listesini alt kategorilere göre gruplamak, her bir gruptaki toplam ürün sayısı, ortalama, en yüksek, en düşük fiyatları bulmak.

Böyle bir sorgu için öncelikle ürünleri, alt kategorilerine göre gruplamamız gerekmektedir. Sonra gruplanan veri kümesi üzerinde bazı gruplama fonksiyonlarını kullanmalıyız. Bu cümleleri sarfettikçe aslında bir T-Sql sorgusunu ifade etmeye çalıştığımı düşünüyorum. Ama artık Sql değil LINQ tarafında ve daha tanıdık topraklardayız. Öyleyse hiç vakit kaybetmeden örnek kodumuzu aşağıdaki gibi geliştirelim.
 

var result7=from prd in products
                    
group prd by prd.ProductSubCategoryId into g
                        
orderby g.Key
                            
select new{
                                
Kategori=g.Key
                                
,UrunSayisi=g.Count()
                                
,ToplamFiyat=g.Sum(prd=>prd.ListPrice)
                                
,EnDusuk=g.Min(prd=>prd.ListPrice)
                                
,EnYuksek=g.Max(prd=>prd.ListPrice)
                                
,OrtalamaFiyat=g.Average(prd=>prd.ListPrice)
                            
};
 foreach(var result in result7)
 {
     Console.WriteLine("Kategori Id {0}",result.Kategori.ToString());
     Console.WriteLine("\t Toplam Ürün Sayısı {0}",result.UrunSayisi.ToString());
     Console.WriteLine("\t Toplam Birim Fiyat {0}",result.ToplamFiyat.ToString("C2"));
     Console.WriteLine("\t En Düşük Birim Fiyat {0}",result.EnDusuk.ToString("C2"));
     Console.WriteLine("\t En Yüksek Birim Fiyat {0}",result.EnYuksek.ToString("C2"));
     Console.WriteLine("\t Ortalama Fiyat {0}",result.OrtalamaFiyat.ToString("C2"));
     Console.WriteLine();
 }

İlk olarak group anahtar sözcüğünü kullanarak products içerisindeki Product tiplerini ProductSubCategoryId alanlarına göre gruplayacağımızı ve grupladığımız verileri g takma isimli tip içerisinde saklayacağımızı belirtiyoruz. Hatta elde edilen sonuç kümesini, grupladığımız verilerin Key özelliğine göre (ki burada Key özelliği ProductSubCategoryId alanının değerini işaret etmektedir) sıralatmaktayız. Sıralatma işlemi için bildiğimiz orderby anahtar kelimesinden faydalanıyoruz. Sonrasında ise yine bir isimsiz tip karşımıza çıkıyor ki sonuç kümesinde üretilen satırları farklı bir nesne örneği olarak kullanabilmek için tam aradığımız yapı.

Burada dikkate değer bazı noktalar da vardır. Özellikle gruplama fonksiyonlarının nasıl kullanıldığına dikkat edelim. Burada => gibi bir operatörle karşılaşmaktayız. Bu operatör Lambda operatörü olarak adlandırılan ve C# 3.0 ile birlikte gelen bir yeniliktir. Gruplama fonksiyonları aslında, elde edilen küme içerisindeki elemanları dolaşıp bunlar üzerinde gerekli fonksiyonları çalıştıracak şekilde tasarlanmışlardır. Örneğin g.Sum(prd=>prd.ListPrice) çağrısı, sonuç kümesindeki prd takma isimli her bir Product tipini dolaşıp ListPrice alanlarını toplayarak bir sonuç üretmek üzere tasarlanmıştır. Diğer gruplama fonksiyonlarıda buna benzer şekilde çalışmaktadır. Sonuç olarak örnek kodumuz çalıştırdığımızda aşağıdakine benzer bir ekran çıktısı elde ederiz.

Sorgu 7: Urunler içerisinde baş harfi H olanların liste fiyatına göre tersten sıralanmış halini seçip bir diziye taşımak.

Sanırım, LINQ ifadeleri sonrası elde edilen sonuç kümelerini işe yarayabilecek başka tipte nesnelere aktarabilmek oldukça işe yarar bir fonksiyonellik olurdu. LINQ bu amaçla elde edilen sonuçların bir diziye (Array), List veya Dictionary koleksiyonlarına aktarılmasını sağlayan fonksiyonelliklerde içermektedir. Örneğin aşağıdaki kod parçası, products koleksiyonunda baş harif H olan ürünlerin liste fiyatına göre tersten sırlanmış halinin bir diziye aktarılmasını sağlamaktadır. Baş harfe göre karşılaştırma yapabilmek için indeksleyici operatörünü Name alanı üzerinde nasıl kullandığımıza dikkat edelim. Sonuçta Name alanı string tipte bir değişkendir ve bir karakter dizisini işaret etmektedir. Bu nedenle C# dilinin tüm sürümlerinden bildiğimiz gibi 0 indisli eleman aslında Name alanının işaret ettiği verinin birinci karakteri olacaktır.
 

var result8=from prd in products
                   
where prd.Name[0]==’H’
                       
orderby prd.ListPrice descending
                           
select prd;

var result9=result8.
ToArray();

for(int i=0;i<result9.Length;i++)
    Console.WriteLine(result9
[i].ToString());

Burada başrol oyuncumuz ToArray metodudur. ToArray metodu, elde edilen sonuç kümesinin bir diziye aktarılmasını sağlar. Böylece sonuç kümesindeki elemanlara indeks numaraları yardımıyla erişmemizde mümkün olmaktadır. Diğer taraftan bir dizinin sunacağı avantajları değerlendirme şansınada sahip olabiliriz. Aynı işlemleri LINQ olmadan yapmaya çalışırsak, yukarıdaki kod parçasına dair yüzümüzde bir tebessüm oluşmaması için hiç bir neden kalmayacaktır. Uygulamanın çalışmasının sonucunda aşağıdakine benzer bir ekran görüntüsü elde ederiz.

Sorgu 8: Join ile birleştirilmiş bir sorgu sonucunu generic Dictionary koleksiyonuna aktarmak.

Join sorgusu ile urunler ve altKategorileri birleştirdiğimizi düşünelim. Bu sonuç kümesinde ProductSubCategoryId alanı Key ve Product nesne örnekleride Value olacak şekilde bir Dictionary koleksiyonu oldukça işimize yarayabilir. Bildiğiniz gibi Dictionary bazlı koleksiyonlar (Hashtable<>, Dictionary<>, Hashtable vb...) verileri key-value çiftleri şeklinde tutmaktadırlar. Dolayısıyla özellikle birleştirilmiş veri kümelerinde elde edilen verileri key ve value olacak şekilde tutmak işe yarayabilir. Bunu gerçekleştirmek için aşağıdaki gibi bir kod parçasını kullanabiliriz.
 

var result11=from prd in products
                       
join ktg in subCategories
                           
on prd.ProductSubCategoryId equals ktg.ProductSubCategoryId
                               
select new {Kategori=ktg.Name,Urun=prd};

var result12=result11.
ToDictionary(ktgName=>ktgName.Urun.ProductId);

IEnumerator<int> numerator=result12.Keys.GetEnumerator();
while(numerator.MoveNext())
{
   
var currentProduct=result12[numerator.Current];
    Console.WriteLine(
currentProduct.Urun.ProductId.ToString()+" "+currentProduct.Urun.Name+" "+currentProduct.Urun.ListPrice.ToString("C2")+" "+currentProduct.Kategori);
}

Bu sefer başrol oyuncumuz ToDictionary metodudur. Yanlız metodumuz parametresine dikkat edelim. Burada ktgName adıyla her bir urunun ProductId değerleri alınmakta ve Dictionary bazlı koleksiyonun içerisindeki anahtarlara (key) atanmaktadır. Değer (Value) kısmında ise sorgu sonucu elde edilen tipler yani Kategori ve Urun alanlarından oluşan isimsiz tiplerimiz eklenmektedir. Son olarak test amacıyla elde edilen Dictionary koleksiyonu içerisindeki anahtarlarda bir numarator yardımıyla dolaşılmaktadır. Burada bildiğimiz ileri yönlü iterasyon deseni uygulanmaktadır. Aslında uygulamayı debug edersek ve result12 değişkenine QuickWatch penceresinden bakarsak, sorgu sonuçlarının gerçektende key-value çiftleri şeklinde eklendiği generic bir Dictionary koleksiyonu ile karşılaşmış oluruz.

Uygulamamızı çalıştırdığımızda ise aşağıdakine benzer bir çıktı elde ederiz.

Sonuç kümelerini Dictionary koleksiyonlarına nasıl alabiliyorsak List tipinden generic koleksiyonlarada alabiliriz. Tek yapılması gereken başrol oyuncusunu değiştirmek olacaktır. Yani ToDictionary yerine ToList metodunu kullanamak.

Sorgu 9: Ürünler içerisinde kaç farklı liste fiyatı olduğunu bulup bunları küçükten büyüğe doğru elde etmek.

Eminimki Sql bilen herkes bu iş için distinct operatörünün kullanılması gerektiğini söyleyecektir. Aynı operatör LINQ içerisinde yer almaktadır. Örneğin, ürünlerin tutulduğu koleksiyon içerisindeki liste fiyatlarını tekrarsız olarak elde etmek istediğimizi düşünecek olursak aşağıdaki kod parçasından faydalanabiliriz.
 

var result13=(from prd in products
                       
orderby prd.ListPrice
                           
select prd.ListPrice).Distinct();

foreach(var result in result13)
    Console.WriteLine(result.ToString());

Dikkat ederseniz Distinct metodunu kullanmadan önce, tüm LINQ ifadesi paranetez içerisine alınmıştır. Nitekim Distinct operasyonu elde edilen sonuç kümesi üzerinden uygulanmaktadır. Kodun çalışması sonucu programın çıktısı aşağıdaki ekran görüntüsündekine benzer olacaktır.

Sorgu 10: Ürünleri önce adlarına göre küçükten büyüğe sonrada liste fiyatlarına göre büyükten küçüğe sıralatarak elde etme.

Tipik olarak bahsettiğimiz, birden fazla alan üzerinde Order By işlemini uygulamaktan başka bir şey değildir. Bunu gerçekleştirmek için, LINQ ifadelerinde orderby operatöründen faydalanabiliriz. Aşağıdaki kod parçası bu işlemi gerçekleştirmektedir.
 

var result17=from prd in products
                       
orderby prd.Name,prd.ListPrice descending
                           
select prd;

foreach(var result in result17)
    Console.WriteLine(result.ToString());

Dikkat ederseniz orderby anahtar kelimesinden sonra, sıralama için ele alınacak alanlar virgül ile ayrılarak yazılmıştır. Bununla birlikte liste fiyatına göre tersten sıralatma yaptırmak istediğimiz için descending anahtar sözcüğünden yararlanılmıştır. Özellikle kendi geliştirdiğimiz tipleri bir koleksiyonda kullandığımızda ve bu koleksiyon içerisindeki elemanları sıralatmak istediğimizde, genellikle IComparer yada IComparable gibi arayüzlerin ilgili sınıflara uygulanmasını sağlamamız gerekir. Oysaki LINQ ile bu tarz bir ihtiyaç çok daha kolay bir şekilde ele alınabilmektedir. Programı çalıştırdığımızda aşağıdakine benzer bir ekran çıktısı elde ederiz. Dikkat ederseniz her ürün alfabetik olarak sıraya dizildikten sonra her ürün için ilk harflerine göre kendi içerisinde liste fiyatına göre tersten sıralanmıştır.

Sorgu 11: Ürünlerin isimlerini karakter uzunluklarına göre tersten sıralayarak elde etme.

Bu oldukça enteresan olacak. products koleksiyonu içerisindeki her bir Product tipinin Name alanlarını ele alacağız. Bunların karakter uzunluklarına göre tersten sıralatacağız. İşte bu eğlenceli sorgunun LINQ karşılığı.
 

var result18=from prd in products
                       
orderby prd.Name.Length descending
                           
select new{UrunAdi=prd.Name,ListeFiyati=prd.ListPrice};

foreach(var result in result18)
    Console.WriteLine(result.UrunAdi);

Dikkat ederseniz tek yaptığımız orderby anahtar kelimesinden sonra prd örneklerinin Name alanlarının Length özelliklerini ele almak. descending anahtar kelimeside tersten sıralatma işleminin gerçekleştirilmesini sağlıyor. Kodu çalıştırdığımızda gerçektende isimlerin uzunluklarına göre azalan bir formasyonda sıralandığını görebiliriz.

Bu makalemizde 11 değişik sorguda LINQ’ yu daha yakından tanımaya çalıştık. Makalemizin başında belirttiğimiz gibi LINQ içerisinde oldukça fazla sayıda operatör yer almaktadır. Anders Hejlsberg, LINQ teknolojilsini özellikle veritabanı programcılığı yapanların dil içerisindede aynı felsefeyi kullanabilmeleri için geliştirildiğini belirtmiştir. Gerçektende yukarıdaki dil içi sorgular buna verilebecek örneklerden sadece bir kaçıdır. İlerleyen makalelerimizin birisinde diğer operatörleride ele almaya çalışacağız. Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşmek dileğiyle hepinize mutlu günler dilerim.

Örnek Uygulama İçin Tıklayınız.

Tags:

Asp.Net

Microsoft'tan yeni sertifika: MCA

by Administrator 31. Ocak 2009 16:22
Microsoft, geçtiğimiz günlerde yaklaşık 1 yıldır test etmekte olduğu yeni bir sertifika programını açıkladı. MCA (Microsoft Certified Architect) adı verilen sertifika programı, 7 yetkinlik derecesine sahip olan bir sisteme dayanıyor. Yapılan açıklamada, Microsoft'un farklı bir yöntem üzerinde çalıştığı ve adayların yeteneğini diğer kişilerin performanslarına göre değil, ideal olan performansa göre ölçen bir sistem geliştirmenin asıl hedef olduğu söyleniyor.

Bu yeni sertifikasyon programıyla Microsoft, endüstri uzmanı It uzmanlarını kendi çatısı altında toplamayı hedefliyor. Bu IT uzmanlarının en az 10 yıllık bir IT deneyimine sahip olması gerekiyor. Yani her isteyen bu programa katılamayacak demek oluyor. Ayrıca, 10 yıllık geçmişe sahip olmanın yanında bu uzmanlar güçlü teknik, liderlik ve karar alma becerilerine de sahip olmak zorunda. Diğer sertifkasyon sistemlerinden farklı olarak bu sertifikasyona katılan adaylar teknik, liderlik ve karar alma becerilerini, önceden Architect ünvanı olan bir komiteye karşı sergilemek zorundalar. Bu zorlu programı geçen uzmanlar çok saygın bir ünvana da sahip olmuş olacaklar.

7 derece
Programda ölçülen 7 yetenek ise şu şekilde;

 

- Teknik derinlik
- Teknik genişlik
- İletişim
- Kurumsal dinamikler
- Liderlik
- Strateji ve taktik

 

Bu programa katılan kişiler uzun saatler boyunca sürebilen bir müzakereye katılıyorlar. Bu müzakereler boyunca ise katılımcılar, bir geliştiriciden mimara, mimardan ise yüksek mimara kadar büyüyebiliyorlar.

Microsoft bu sertifika programından sonra şu programları da açmayı planlamaktadır:

- MCPM: Microsoft Certified Project Manager
- MCD: Microsoft Certified Director
- MCB: Microsoft Certified Boss
- MCS: Microsoft Certified Sector
- MCE: Microsoft Certified Economy
- MCC: Microsoft Certified Country

Bu sertifika programı hakkında detaylı bilgiyi şu linkden edinebilirsiniz;
http://www.microsoft.com/learning/mcp/architect/default.mspx

‘Önce’ye Bakış

by Administrator 31. Ocak 2009 16:21

Şimdi’ye gelmeden önce başlangıç noktamızı belirleyelim… Her şey nasıl başladı? Nasıl bu gün, bu “akıl almaz” teknolojiye ulaştık? İşte bizim referans noktamız bu. Teknoloji dediğimiz kavramın aslında ihtiyaçlarımızın bir sonucu olduğunu biliyoruz.Gelin bu durumu kronolojik bir merceğin altına alalım.

 

 

Her yüzyılda, belirli bir sektörün, diğer sektörlere oranla çok daha fazla kazandırdığını söylemek çok mu yanlış olur?

 

Yakın tarihten günümüze kadar olan birkaç gelişmeyi incelediğinizde, bu genellemeye sizde ulaşabilirsiniz…

 

 

Sözgelimi 16. – 17. yüzyıllar arasında Avrupa’da en fazla kazandıran sektörün parfümeri ve temizlik ürünleri olduğunu görüyoruz… Bu sektörün içerisinde üretici olarak yer alan şirketlerin ve bu şirketlerin en yoğun olduğu ülkelerin o yüzyılın en zenginleri arasında yer aldığı da aşikardır… Yine aynı yüzyılda, Osmanlı Devleti’nin lale devrini yaşaması bunun örneklerinden biri olarak verilebilir…

 

 

Fakat, bir yüzyıl sonraya baktığınızda, değişim rüzgarlarının kendini göstermiş olduğunu fark edersiniz. 17 – 18. yüzyıllar arasında, neredeyse tüm ülkelerde, savunma sektörüne bir yatırım söz konusu olmaya başlamıştır… Açıkça söylemek gerekirse ola gelen bu durum, içinde bulunduğu yüzyılı aşarak 20. yüzyıla kadar ulaşmıştır.

 

 

20. Yüzyıla gelindiğinde ise, savunma sektörünün bu kadar gelişmesine, farklı ideolojilerin doğumu eklenince, “soğuk savaş” adı verilen bir döneme daha girilmiş ve belki de diğer yüzyıllardan çok farklı olarak; ülkeler en iyi teknolojiyi üretme, en iyi kültürel aktivitelerde bulunma, her konuda “en iyi” olma uğruna çok sert bir rekabete girişmişlerdir. Uzun bir süre, Amerika, Rusya ve Japonya arasında cereyan eden bu rekabetin neler doğurduğunu çoğumuz biliyoruz. Ama konumuz bu değil tabii ki…

 

 

Buraya kadar geçtiğimiz yüzyılları incelediğimizde çok genel hatlarıyla bunları tespit edebiliyoruz. Fakat biraz daha derine indiğinizde, tüm bu gelişmelerin temelinde; kelimenin tam anlamıyla bir ‘kriz’ yattığının ayırtına varabiliyoruz. Örneğin, 16 – 17. yüzyıllar arasında dikkati çeken parfümeri ve temizlik ürünleri sektörlerinin zirveye oturmasından önce Avrupa’da veba salgınının meydana geldiğini biliyoruz. Bir sonraki yüzyılda ise, Fransız İsyanının (1789) meydana gelmesi ile milliyetçi akımın yayılışını, bu nedenle diğer ülkelerin savunma sektörüne yatırım yaptığını görebiliyoruz.

 

 

Yani, o yüzyılların önemli krizleri, arkalarından mutlaka bazı sektörlerin canlanmasını hatta, zirveye oturmasını sağlıyor.

 

 

Peki, 21. yüzyılda hangi sektörün zirveye oturacağını ve yalnızca parasal açıdan değil çalıştırdığı insan faktörü açısından da çok

 

kazandıracağını söyleyebilir miyiz? İşte bu makalenin bu sitede bulunmasının sebebi tamamen bu… Birazdan burada okuyacaklarınız size kısaca şunu söylüyor olacak; 21. Yüzyılın parlayan sektörü yazılımdır…

 

 

İç içe geçmiş tek sektör : Yazılım

 

 

Yazımızın bir önceki kısmında, önceki yüzyılların bir numaradaki sektörlerinin temelinde büyük çapta (çoğu toplumsal) krizlerin yattığını söylemiştim… Oysaki yazılım, bu tarz bir krizin sonucunda oluşmuş bir sektör değildir. Aksine özgür ekonomiye sahip ülkelerin şirketlerinin bir ihtiyacına yönelik olarak doğmuş bir sektördür yazılım. Bu açıdan baktığımızda, bir gerçeği daha tespit etmekte zorlanmıyoruz; yazılımın tüm sektörlerin içerisinde bulunduğu gerçeğini…

 

 

Evet… Bu önemli farka bir kez daha dikkat çekmek istiyorum; kozmetikten savunmaya, uzay araştırmalarından tıp bilimine, devlet yönetiminden özel sektöre yazılımın ve doğal olarak bilgisayarın içinde bulunmadığı tek bir sektör yok. Bu durum, yazılım kavramının tek bir yönünden kaynaklanıyor; her duruma uyarlanabilirlik…

 

 

Yazılımla neler yapılabildiğini bilmek neler yapılabileceğini görmek için kullanılan bir teleskoptur. Bu felsefeyle düşünürsek, gelecekte meydana gelecek birçok teknolojik atılımın temelinde de yazılımın olduğunu göreceğiz…

 

 

İsterseniz, bu durumu biraz daha açalım… Yazılım ürünleri, tüm sektörlerde öncelikli olarak kullanılan ve ‘vazgeçilmez’ olan bir kavram. Bu şunu doğuruyor; X bir sektör, kendisine göre kurgulanmış bir yazılım ürününe ihtiyaç duyuyor. Bir yazılım şirketi bu ihtiyacı görüyor ve bir çözüm üretiyor. Üretilen bu çözüm eğer başarıya ulaşırsa, söz konusu yazılım şirketi, benzer çözümleri arttırmak için kendi içerisinde bir yatırıma gidiyor ve bu ihtiyaç sahibi sektörü, kendisinin uzmanlık alanı haline getiriyor. Böylece minimum maliyet – maksimum fayda ilkesinin en ideal oluşumunu örneklemiş oluyor.

 

 

Bilindik mekanik fizikten işletme kuramlarına oturtulan terimlerden biri olan feed – back (geri besleme) bakın burada nasıl devasa boyutlarda… Dünyanın dört bir yanındaki milyonlarca irili ufaklı yazılım şirketi, sektörlerin ihtiyaçlarına çözüm geliştiriyor ve geliştirilen bu çözümlerin hemen ertesinde kazanımlarını, ürünleri daha ileriye taşıyacak ve daha kalıcı çözümler üretecek şekilde yatırım yapıyorlar. Yani yazılım, kullanıldıkça artan yeni bir yakıt türünü kullanan bir tren gibi hızlanarak dünyayı turlamaya devam ediyor.

 

 

Tüm bu bulgulardan şunu gözlemek hiç de zor değildir. Dünyanın ekonomik geleceğini görmek için medyum olmaya gerek yok. Yazılıma gereken önemi verecek olan toplumlar, geleceğin ekonomik liderleri olacaklardır…

 

 

 

 

 

 

Yazılım Sektörünün Belirteçleri: Yazılım Geliştiriciler

 

 

Yukarda temel olarak oluşturduğumuz modelde görüyoruz ki; diğer sektörlerin artan yazılım ürünleri ihtiyacı, yazılım sektörünü hızla pompalamaktadır. Bu durumda, yazılım sektörünün en temel ihtiyacının, daha fazla fikir üretebilecek ve çözüm sunabilecek çalışan, yani yazılım geliştiriciler olduğunu söylemek pek de abartı olmayacaktır. Peki bu yeterli mi ? Elbette hayır.. Yazılım geliştiricilerin yanında bir de yazılım tekniklerinin gelişmesi şart. Ama bu da zaten yine bir ‘yazılım geliştirici’ nin işi…

 

 

Yazılım tekniklerinin gelişmesi demek; daha kısa sürede proje bitirmek olarak özetlenebilir belki. Ancak, bu ifadenin ardında bambaşka taraflara dikkat çekilmektedir. Bu detay da şudur; daha kısa sürede, bir öncekiden daha gelişmiş bir yazılım ürünü geliştirmek.

 

 

Bunu çok basit bir örnekle irdeleyelim. Büyük bir yazılım projesinin bir yılda tamamlandığını varsayalım. Bu bir yıl sonunda, ürün piyasaya gözlerini açtığında üretici şirket, ürünü geliştirmeye ve yeni versiyonlar / eklentiler yapmaya devam edecektir. Belki de ikinci yılın sonunda ürünün daha gelişmiş bir versiyonunu piyasaya sunacaktır. Yani totalde iki yıllık bir süre içinde, iki versiyon çıkaran bir ürünün kazandıran bir ürün olduğunu çok rahat ifade edebiliriz. Fakat bir de şunu düşünün… Bu projenin aynısının bundan 5 yıl sonra kullanılacak olan bir yazılım tekniği ile oluşturulduğunu kurgulayalım. Ürünün ilk versiyonu (yazılım tekniği daha hızlı olduğundan) altı ayda tamamlansın. İkinci versiyonu bir altı ay daha… Tam bir yıl sonunda; ilk projemizin bulunduğu duruma geldik. Bir yıl kardayız… Ama bu ‘bir yıl tatil yapmak’ demek değil. İki versiyonu daha o bir yıl içinde çıkarmak demek!

 

 

Söz yazılım tekniklerine gelmişken, bu gün yazılım geliştiriciler arasında yaşanan, yazılımla ilgilenen herkesin bildiği bir rekabet var… Genel adıyla Soft Coder – Hard Coder, Türkçe ifadesiyle; sürükle bırakçı – her şeyi kodla yazıcı olarak esprili bir şekilde adlandırabileceğimiz bu iki taraf, yıllar boyudur tartışmaya devam ediyor. Ben burada şu görüşü savunuyorum; mümkün olduğunca pratik çözüm, yazılım geliştiricinin, asıl sorunun çözümüne daha fazla zaman ayırmasını sağlayacaktır…

 

 

Bunu, yine basit bir örnekle irdeleyelim. Birçoğumuz, her gün işine giderken trafik sıkıntısını yaşıyor. Bu sıkıntıyı yaşayan herkes, bu durumu ‘zaman kaybı’ olarak görüyor ve bundan dolayı da strese giriyor… İşte, yazılımda da, toolbox’ tan sürüklenip bırakılabilecek bir butonu, kodla oluşturmak bana bu trafik sorunundan çok farklı gözükmüyor. Ben işimde zamanında olmayı yani asıl sorunla ilgilenmeyi tercih ediyorum.

 

 

Yazılım geliştiricilerde olması gereken bir başka nitelikte, araştırmacılıktır. Sektör, bugün ve her zaman, teknolojinin bir adım bile gerisinde durmaması gerektiğini bilen kişileri ön planda tutacaktır. Bu da, sıkı bir internet okuru olunması gerektiğini göstermektedir. Aynı zamanda yazılım tekniği kadar yazılımcının da hızlı çözüm üretebilen ve pratik olması da aranan kriterlerden biri olmayı sürdürecektir.

 

 

Buraya kadar ele aldığımız konularda, yazılım sektörünün şimdisini geleceğini modellemeye çalıştık ve gördük ki; ihtiyaçlar arttıkça yazılım ürünleri, yazılım ürünleri arttıkça da, yeni yazılım tekniklerine ve işgücüne ihtiyaç da artıyor… Bu makale, makale dizimizin ilk kısmını oluşturan parçaydı. Bundan sonraki makalemizde de yazılımın geleceği üzerine konuşmaya devam edeceğiz…

 

 

İyi Çalışmalar

Bir Saldırının Anatomisi ve Application Domain Sınıfı-1

by Administrator 31. Ocak 2009 16:18

Bu yazı gerçek bir hikâyeden alınmıştır, Kişilerin takma adları kullanılmıştır.

Dromedary o gece sabaha karşı uymuştu ve şimdi uyanmak oldukça zor geliyordu, oda tıpkı diğer yazılımcılar gibi geceleri çalışmayı seven biriydi. Sabah güçlüklede olsa yatağından doğruldu ve hızlıca hazırlanıp evden çıktı. Şirkete geldiğinde mesai henüz başlamamıştı. Masasına geçip bilgisayarını açtı ve sistemi kontrol etti, herşey yolundaydı . Dromedary CSoft’da yazılım uzmanı olarak çalışıyordu.Bir ekip olarak, Visual Studio 2005 üzerinde C# ile geliştirdikleri tedarik zinciri projesi test aşamasına gelmişti ve bazı kullanıcılılar tarafından gerçek verilerle test edilmekteydi. Bu yüzden, düzenli olarak her sabah uygulamanın kullandığı DataBase Server’i kontrol ediyordu.

Saat öğlene yaklaştığında test kullanıcılarından biri server’a login olurken hatayla karşılaştığını ve ani bir yavaşlama yaşadığını raporetti. Dromedary hemen server hareketlerini tekrar gözden geçirdi ve logları inceledi. Test kullanıcısın hesabıyla oturum açılmış görünüyordu hesabı düşürüp tekrar bağlanmasını sağladı. Fakat dikkatini çeken bir durum daha vardı. Gece geç saatlerde bir hareketlilik yaşanmıştı ve istemci olarakta geliştirdkleri program görünüyordu. Programın kaynak kodlarını incelemeye başladı fakat herşey normal görünüyordu. Önemsiz olabileceğini düşündü ve bunu not edip rutin işlerine geri döndü.

Akşam çıkış saatine doğru öğlen yaşanan olayla ilgili kafasında tekrar soru işaretleri oluştu ve kalıp DataBase Server’ı izlemeye karar verdi. Saat oldukça geç olmuştu ama olağan dışı bir durum yaşanmamıştı. Kalkıp bir kahve aldı ve tekrar masısına oturup DBTracer programını açtı, tam bu sırada bir hareketlilik yaşandı. Geliştirdikleri Uygulama üzerinden Server’a bir bağlantı yapılmıştı veriler inceleniyordu, kayıtlara bakılıyordu. İstemcilerin bağlantı bilgilerinin tutulduğu tabloyu açıp IP adresi ve kullanıcı adı bilgilerine baktığında test kullanıcılarından biri olduğunu farketti. IP adresini araştırdığında adresin Bağcılar çıkışlı olduğunu gördü. Oysa bu kullanıcı hesabı Kadıköy’dek bir şirkete aitti. Kesinlikle bu başka biriydi ve Geliştirilen uygulame ile birlikte kullanıcı bilgilerinide ele geçirmişti.

Server’da tutulan bilgiler, test amaçlı olduğu için çok önemli değildi fakat gerçek verilerle örtüşen kayıtlarda yer almaktaydı Bağlanan kişiyi farkettiğini belli etmemek için server’ı farklı bir adrese yönlendirdi. Aynı kullanıcı yaklaşık bir hafta önce uygulamanın hatalar ürettiğni rapor etmişti. Bu sorun, direk Dromedary’a rapor edilmemişti ve başka bir arkadaşı uygulamayı yeniden kurup çalışır hale getirmişti. Hemen geçen hafta kullanıcı pc’sine uygulamayı tekrar kuran arkadaşı Barış’ı aradı. Uygulama dizininde bir anormallikle karşılaşıp karşılaşmadığını sordu. Barış, sadece uygulamanın kullandığı CheckPoint.dll dosyasının zarar gördüğünü, onarmak için tekrar kurduğunu söyledi.

Bu bilgiden sonra Dromedary incelemelerini tamamen bu dll üzerine yoğunlaştırdı. Bu dll dosyası uygulama her çalıştırıldığında ilk çağrılan, içerisinde bir çok Class yeralan bir dll’di ve tabiki kendileri yazmıştı. Yavaş yavaş işi anlamaya başlıyordu, ve tahmin ettiği gibi DLL dosyası üzerinden kendi uygulamaları kullanılarak sisteme sızılmıştı. Dromedary sonradan öğrenecekti, aslında bu işi yapan kişi merXas’tan başkası değildi

merXas sadece uygulamanın kullandığı CheckPoint.dll dosyasını kendi istediği işleri yapıcak bir hale getirmiş ve uygulamayının referanslarında yer alan orjinal dll ile değiştirmişti. Bu sayede uygulama , kendisine ait olan bir dll’e, bir proxy dll üzerinde ulaşıyordu. Bu tüm akışın izlenmesini ve istenilen verilerin elde edilmesini sağlamıştı tıpkı kullanıcı adı ve şifrelerin alındığı gibi,

 

OrjinalConst.JPG

Şekil-1 : Uygulamanın Orjinal Hali

 

HookConst.JPG

Şekil-1 : Uygulamanın proxy dll ile bozulmuş hali

Peki böyle bir açık kapatılamazmıydı, evek kesinlikle kapatılabilirdi. Zaten merXas ’da, uygulamayı incelerken uygulamanın AppDomain sınıfını kullanmadığını, yani program içerisinde kullanılan Assemblylerin izole edilmediğini ve güvenlik seviyelerinin ayarlanmadığını farkettikten sonra, bu yöntemi kullanmaya karar vermişti. Peki nedir bu AppDomain sınıfı ve güvenlik seviyeleri;

AppDomain sınıfı .Net uygulamalarında, uygulamaların diğer .Net uygulamlarından ve kendi içerisinde kullandığı Assemblyleri bir birinden izol etmek için kullanılan bir sınıfdır. Bu sınıfda Application Domainler yer alır. Application Domainler Assemblyler’i yalıtmak için kullanılan sınırlayıcılar gibi düşünülebilir. Aşağıdaki şekilde görüldüğü gibi uygulamanın ADMain isminde bir Application Domaini ve bunun içerisinde yer alan diğer Application Domainler ve her domainin içerisinde yer alan Assembly’leri bulunuyor.

 

 

İşte böyle bir yapı kurulmadan oluştulan Csoft projesinde merXas bu açığı sömürerek uygulamayı kendi istediği işleri yapıcak şekilde revize etmişti. Peki Dromedary bunu nasıl kullanmalıydı, yapıcağı işlem aslında oldukça basitti bir domain oluturup güvenlik seviyesi belirlemek, şöyleki;

Herhangi bir proje içerisinde kullanılacak her nesne, yeni olluşturulacak her nesne bir domain üzerinden instance edilmeli, bunu için her class MarshalByRefObject sınıfından türemiş olmalıdır.

Yani Dromedary CheckPoint Clasını şu şekilde yazmış olsaydı;

 

namespace CheckPoint

 

{

 

public class CheckPoint : MarshalByRefObject

 

{

 

 

//CSoft projesindeki, uygulama ve db arasındak yapılanmayı sağlıyan

 

//ve uygulamayı kullanıma hazır hale getiren bir methodu inceleyelim

 

public void StartInterraction()

 

{

 

//burada çalıştılmak istenen kodlar

 

}

 

 

}

 

}

Class yukarıdaki gibi düzenlendikten sonra, şöyle çağırlmalıydı

//Class’ ın instance edileceği domain

 

AppDomain ad = AppDomain.CreateDomain("CheckPoint");

 

//instance edilen clasın ObjectHandle bilgisi tutulacak

 

ObjectHandle objHandle;

 

//nesne instance ediliyor ve instance edilen objenin handle adresi

 

objHandle = ad.CreateInstance("CheckPoint", "CheckPoint.CheckPoint");

 

//instance edilen nesnenin .StartInterraction() metodu çağrılıyor

 

((CheckPoint.CheckPoint)objHandle.Unwrap()).StartInterraction();

Buraya kadar yaptıklarımız , AppDomain sınıfını sadece yalıtım seviyesinde kullanmaktı. Burası önerilen bir yönetem değildir. Güvenlik seviyesiyle kullanılması daha sağlıklı olacaktır. Günvelik seviyesinde kullanmak içinde tasarım iyi yapılmalı.

Burada çok önemli iki ayrım söz konusu, güvenlik sınırlamaları assembly seviyesindemi olacak domain seviyesindemi !!, Tavsiyem domain seviyesnde olmasıdır. Böylece genel bir kontrol sağlanmış olur. Aynı zaman güvenlik seviyesi düşük yada bulunmayan bir Application Domain’den assembly lerin sızması önlenmiş olur. Ununtmadan aynı zamanda bir Application Domain içerisinde hem domaine hemde assembly’e ayrı ayrı güvenlik seviyeleri uygulanabilir.

/* güvenlik seviyesi için gerekli bilgiler oluşturuluyor */

 

// Assembly'nin çalışacağı ortam

 

Zone bolge = new Zone(SecurityZone.Internet);

 

//ortam dışında bilgiler varsa bunlarda izinler dizisine aktarılabilir

 

object[] izinler = new object[1];

 

izinler[0] = bolge;

 

//güvenlik bilgileri Evidence nesnesne aktarılıyor

 

Evidence guvenlik = new Evidence(izinler, null);

 

//clasın instance edileceğii domain

 

AppDomain ad = AppDomain.CreateDomain("CheckPoint", guvenlik);

 

//instance edilen clasın ObjectHandle bilgisi tutulacak

 

ObjectHandle objHandle;

 

//nesne instance ediliyor ve instance edilen objenin handle adresi

 

objHandle = ad.CreateInstance("CheckPoint", "CheckPoint.CheckPoint");

 

//instance edilen nesnenin .StartInterraction() metodu çağrılıyor

 

((CheckPoint.CheckPoint)objHandle.Unwrap()).StartInterraction();

Artık yeni oluşturduğumuz nesnemiz sadece İnternet ortamında çalışacak seviyede ayarlandı, bunun avantaji yerel sisteme hiç bir şekilde müdahele edememesidir. Böylece bilgisayardan kullanıcının yetkisi olmadan hiç bir veri okuyamaz hiç bir yere kayıt yapamaz daha güvenli bir ortam sağlanmış oldu.

Bu uygulamları yapabilmek için projeye aşağıdaki NameSpacelerin dahil edilmesi gereklidir

using System.Runtime.Remoting;

 

using System.Security;

 

using System.Security.Policy;

CSoft böyle bir kaç güvenlik önemlemiyle bu sıkıntıdan kurtulabilirdi, peki bizler herşeyiyle güvenli tasarlanmış bir uygulama nasıl geliştirebilriiz ? Bununla ilgili detaylı örneği Applicatin Domain ve Günvelik konulu yazıda bulacaksınız

 

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

Calendar

<<  Mayıs 2012  >>
PaSaÇaPeCuCuPa
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar