Bu site emekli olmuştur. Arşiv amaçlı olarak BT AKADEMİ sponsorluğunda yayın hayatına devam etmektedir.




C#nedir?com
 
YAZAR HAKKINDA
Süleyman Payaslı
Süleyman Payaslı
http://www.csharpnedir.com/
İletişme geçmek için tıklayın.
7 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler: banner bannerid degeri erisim gridview ilgili katmani katmanindan kontrol kullanarak nesnesi reklam uygulamasi verileri veritabani ASP.NET Süleyman Payaslı
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : Orta
Kategori : ASP.NET
Yayınlanma Tarihi : 8.5.2008
Okunma Sayısı : 59069
Yorum Sayısı : 7     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
emre TAŞ
Silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer
Conda install environment.yml Package 28.3.2024
Turhal Temizer
Mac OS/X Removing CUDA 28.3.2024
Burak Selim Şenyurt
Kurumsal Yazılımcının Oyun Geliştirme ile İmtihanı 28.3.2024
Burak Selim Şenyurt
Matematik ve Oyun Programlama - Missile Command - Final 28.3.2024
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
ASP.NET'de Business Object Layer ile Banner
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon

Bu makalemizde, ASP.NET'de iş katmanı (business object layer), veri erişim katmanı (data access layer) ve sunum katmanı (prsentation layer) kullanarak çok katmanlı bir uygulama geliştireceğiz. Bu katmanlı yapıyı daha iyi kavrayabilmek için örnek olarak bir banner uygulamasını ele alacağız. Örnek banner uygulamamızı önce XML üzerinden, daha sonra çok katmanlı modeli geliştirip veritabanı kullanarak gerçekleştireceğiz. Konunun daha iyi anlaşılabilmesi için bazı temel kavramları hatırlamakta fayda görüyorum. Banner nedir?
Web sitelerine reklam amaçlı olarak yerleştirilen pano, manşet veya tanıtıcı başlıklardır. Başka bir deyişle tanıtım için hazırlanmış hareketli veya hareketsiz reklam alanları ögeleridir. Kendi sitemizin reklamı olabileceği gibi başka bir sitenin de reklamı veya onunla ilgili bir haber olabilir. Siteye girenler reklamı izlemiş olurlar. Buna ilgi duyan ve detaylara ulaşmak isteyen ziyaretçi bu alana tıkladığında ilgili kısma yönlendirilir. Kendimize ait bannerlar tıklandığında belirlemiş olduğumuz başka bir sayfaya, reklam verene aitse ilgili ana sayfaya yönlendirme gerçekleştirilir. Başkalarına ait haberleri, başlıkları sitemize sosyal yardım amaçlı koyabileceğimiz gibi ticari amaçlı konulan reklam panolarından belli bir ücret alabiliriz.

Bannerlar genelde JPG, GIF veya .SWF uzantılarına sahip olurlar. Hareketli olanlar genel olarak gif veya flash animasyon şeklindedirler. Banner çeşitleri ve ölçüleri genellikle benzer olmakla beraber, siz kendi ihtiyaçlarınıza göre düzenleyebilirsiniz. Daha fazla etki yaratmak için sabit bir banner yerine birden çok banner konularak bunlar dönüşümlü olarak yayınlanabilir. Böylece daha fazla ziyaretçiye ve doğru kişilere ulaşılmış olur.

XML dosyası veri kaynağından banner gösterimi
Şimdi basit bir reklam banner uygulaması gerçekleştirmeye başlayalım: Daha önce hazırlanmış banner'ları web sayfamızda sabit veya reklamın önemiyle orantılı olarak dönüşümlü gösterebiliriz. Reklam bilgilerini bir XML dosyası içinde saklayalım. Örnek dosyamız (banners.xml) aşağıdaki gibi olacaktır:


Dosya içindeki reklam alanları şunlardır:

  • ImageUrl: Grafik resmin bulunduğu yer, URL.
  • NavigateUrl: Banner tıklanınca gösterilecek web sayfası.
  • AlternateText: Reklam görüntülenemediği zaman görünmesini istediğimiz yazı veya ipucu.
  • Impressions: Reklamın ne kadar sıklıkla gösterileceğini bildiren tamsayı.

XML dosyasını kendimize göre hazırladıktan sonra uygulamaya geçebiliriz. Visual Studio içinden, yeni bir ASP.NET Ajax-Enabled Web Site oluşturalım.


Projemizde App_Data klasörünün oluşturulduğunu göreceksiniz. Şimdi resim dosyaları için images adlı yeni bir klasör ekleyelim. App_Data klasörünün altına banners.xml dosyasını, images klasörünün altına da resim dosyalarını ekleyelim. Projemizin görüntüsü ve dosyalar aşağıdaki gibi olacaktır:

Default.aspx sayfamızı açtığımızda bir ScriptManager kontrolünün yer aldığını görürüz. Araç kutusundan bir UpdatePanel kontrolü alarak üzerine bırakalım. Şimdi araç kutusundan bir AdRotator bileşenini UpdatePanel içine ekleyelim. Karşımıza çıkan AdRotator Tasks penceresinden Choose Data Source için New data source... işaretleyelim.


Data Source Configuration sihirbazında uygulamanın veri kaynağını XML File seçip, veri kaynağını adlandırdıktan sonra OK basıyoruz.


Karşımıza veri dosyası yolunu ve adını gireceğimiz ayar penceresi gelir.


App_Data klasörünün altındaki banners.xml dosyasını seçelim.

OK düğmelerine basarak bu işlemi tamamlayalım. Böylece banners.xml dosyamızı AdRotator kontrolüne referans olarak vermiş bulunuyoruz. Bunun anlamı şudur: AdRotator kontrolü XML dosyasında yer alan banner bilgilerini, veri kaynağını kullanarak okur. Böylece AdRotator kontrolü XML dosyasına bağlanmış olur.

Banner'ların sayfada güncellenme süresi için bir zaman aralığı vermemiz gerekiyor. Araç kutusundan sayfamıza bir Timer kontrolü ekliyoruz. Timer kontrolünün Interval zaman aralığını istediğimiz gibi mili saniye cinsinden ayarlıyoruz. Tasarım aşamasındaki görünüm şu şekildedir:


Uygulamayı çalıştırdığımda kendi bilgisayarımdaki ekran görüntüsü aşağıdaki gibidir. Muhtemelen sizdeki farklı olabilir. XMLDataSource ile hemen hazırladığımız bu uygulamayı buradan indirebilirsiniz.

Veritabanı kullanarak banner gösterimi
Veritabanında hazır bir tablonuz varsa SqlDataSource kontrolünü kullanarak verileri çekebilirsiniz. Gerekli saklı yordamları yazdıysanız, isterseniz düzeltme ve silme işlemlerini de gerçekleştirebilirsiniz. Bu verileri bir GridView veya bir AdRotator kontrolüne de bağlayabilirsiniz. Yukarıdaki bölümde XML kaynak için gösterilen Data Source Configuration sihirbazından benzer adımları uygulayabilirsiniz. Buradaki tek fark eldeki tablonuzu veya istediğiniz saklı yordamları (stored procedure) seçmenizdir. Ayrıca ihtiyacınız yoksa, ekstra bir kod yazmanıza da gerek yoktur. SqlDataSource kullanımı ile ilgili kısmı burada sonlandırıp esas konumuz olan katmanlı mimariye geçmek istiyorum.

Temel Katlı Mimari Modeli
Temel katlı mimari modelinde üç katman bulunur: veri erişim katmanı, iş katmanı ve sunum katmanı. Bu modelde katmanların birbirinden ayrılması geleneksel mimariye göre daha esnek bir yapı sağlar. Daha modüler bir yapı olduğundan kolayca kontrol edilebilir ve taşınabilir özelliklere sahiptir. Kod kısmı daha kolay anlaşılabilir ve ihtiyaçlar doğrultusunda geliştirmeye açık olarak sürdürülebilir.

En üstte sunum katmanı bulunur. Bu bir windows veya web uygulaması olabilir. Örnek, ASP.NET ile yapacağımız banner uygulaması. Ortadaki iş katmanı ise sunum ve veri erişim katmanları arasında köprü vazifesi görür. Sunum katmanından gelen istekleri veri erişim katmanına gönderir. Böylece uygulamanın veritabanı ile doğrudan ilişkiye geçmesi önlenir. Bu arada gelen istekler iletilmeden önce kimlik doğrulaması yapılabilir. Hak sahibi olmayanlar geri çevrilir. Tahmin edebileceğiniz gibi veri erişim katmanından geriye dönen cevaplar, sunum tarafına gönderilir. Veri erişim katmanı veritabanı ile iletişim kurarak sql sorgusu çalıştırma, kayıt ekleme, güncelleme, silme, saklı yordam çalıştırma v.b. işlemleri yapar. İçindeki metodlarla DataSet, XML, generic List<> gibi veri türlerini geri döndürebilir. Diğer katmanlardan bağımsız olarak veritabanı yapılarını mantıksal bir biçimde soyutlar. Projelerde veri erişim katmanın bulunması, veritabanı güvenliği açısından performans, hız, güvenlik ve kod okunabirliği açısından avantajlar sağlar. Bir web uygulaması için geliştirdiğimiz katmanları başka uygulamalarda kullanabiliriz. Örneğin, sunum katmanından ASP sayfalarını kaldırıp yerine bir windows uygulaması için formlar koyabiliriz. Sunum katmanını istediğimiz gibi değiştirebiliriz. Bu durum diğer katmanlarda genel çalışmayı etkilemez ve büyük bir değişiklik yapmamıza gerek kalmaz. Benzer şekilde başka veritabanlarına geçildiğinde, örneğin SQL Server'dan Oracle'a geçerken, sadece veri erişim katmanı üzerinde değişiklikler yaparız. Geriye kalan katmanlar değişikliğe uğramadan kullanılabilir. Şimdi kullanacağımız banner uygulamasına geçebiliriz:


Uygulamamız SQL Server 2005 altında bir veritabanıyla çalışacak. Ayrı bir veritabanı oluşturabileceğiniz gibi "Northwind" veya "AdventureWorks" veritabanlarından birini de kullanabilirsiniz. Uygulama, ilk olarak "AdventureWorks" veritabanından “Banner” tablosundan verileri çekip bir GridView üstünde gösterecek. Kullanıcı kayıt ekleme, güncelleme ve silme işlemlerini yapabilecektir. Tablomuzun tasarımı aşağıdaki gibi olacaktır.

Şimdi Visual Studio içinden yeni bir ASP.NET AJAX-Enabled Web Site açalım ve kullanacağımız iş nesnelerini tasarlamaya başlayalım. İlk olarak banner nesne değerlerini tutacak bir sınıfa ihtiyacımız olacak. Aşağıdaki şekilde "Banner" adlı sınıfımızı görüyorsunuz:

"Banner" adlı sınıfımızın kodlarını yazalım:

using System;
 
namespace BannersBOWebApp.Business
{
    /// 
    /// Uygulamada kullanacağımız banner'ları simgeleyen, iş katmanını kullanacak sınıf.
    /// 
    public class Banner
    {
        //****************************************
        // Banner sınıfı değişken üyeleri
        //****************************************
        protected int m_bannerID;
        protected string m_bannerName;
        protected string m_imageUrl;
        protected short m_width;
        protected short m_height;
        protected string m_navigateUrl;
        protected bool m_isActive;
        protected int m_impressions;
        protected string m_alternateText;
    
        //****************************************
        // Banner sınıfı özellikleri
        //****************************************
        public int BannerID
        {
            get { return m_bannerID; }
            set { m_bannerID = value; }
        }
 
        public string BannerName
        {
            get { return m_bannerName; }
            set { m_bannerName = value; }
        }
 
        public string ImageUrl
        {
            get { return m_imageUrl; }
            set { m_imageUrl = value; }
        }
 
        public short Width
        {
            get { return m_width; }
            set { m_width = value; }
        }
 
        public short Height
        {
            get { return m_height; }
            set { m_height = value; }
        }
 
        public string NavigateUrl
        {
            get { return m_navigateUrl; }
            set { m_navigateUrl = value; }
        }
 
        public bool IsActive
        {
            get { return m_isActive; }
            set { m_isActive = value; }
        }
 
        public int Impressions
        {
            get { return m_impressions; }
            set { m_impressions = value; }
        }
 
        public string AlternateText
        {
            get { return m_alternateText; }
            set { m_alternateText = value; }
        }
 
        public Banner()
        {
            m_bannerID = 0;
        }
    }
}

Sunum katmanından gelen istekleri alıp veri erişim katmanına yollayan, "BannerBLL" adlı iş sınıfımız için aşağıdaki resime bakınız. Veri erişim katmanıyla ilgili sınıfımızı hazırladıktan sonra, bunun kodlarını daha sonra ele alacağız.

Veri erişim katmanı sınıfımızın (BannerManagement.cs) diyagramı aşağıdaki gibidir:

İş katmanı ile veri erişim katmanlarını ayrı klasörler altında tutmakta fayda vardır. Bunları App_Code klasörü altına alırsak daha uygun olur.

BannerManagement sınıfı, verileri okumak, veri listesi vermek, istenen bir kaydı getirmek, kayıt ekleme, güncelleme yapmak ve silme işlevlerini yerine getirecek metodları içermektedir. Bunlardan önce kullanılacak saklı yordamları hazırlamış olmamız gerekir.

Banner tablosunda bulunan verilerin tamamını çekmek için kullacağımız usp_GetAllBanners saklı yordamı oldukça basit bir biçimde yazılmıştır.

CREATE PROCEDURE dbo.usp_GetAllBanners 
AS
BEGIN
    SELECT BannerID, BannerName, ImageUrl, Width, Height, NavigateUrl,
           IsActive, Impressions, AlternateText
    FROM   Banner
END

Yeni kayıt girişi için usp_AddBanner saklı yordamı:

CREATE PROCEDURE dbo.usp_AddBanner
(
    @prmBannerName varchar(50),
    @prmImageUrl varchar(255),
    @prmWidth smallint, 
    @prmHeight smallint,
    @prmNavigateUrl varchar(255),
    @prmIsActive bit,
    @prmImpressions int,
    @prmAlternateText varchar(255),
    @prmReturnVal int OUTPUT
)
AS
BEGIN
    -- Banner adı daha önce girilmiş mi?
    IF (EXISTS (SELECT BannerName
                FROM dbo.Banner
                WHERE BannerName = @prmBannerName))
    BEGIN
        -- Banner adı bulunuyor
        SET @prmReturnVal = -1
    END
    ELSE
    BEGIN
        -- Yeni Banner girişi
        BEGIN TRANSACTION
            
            INSERT INTO dbo.Banner
                         (BannerName,
                          ImageUrl,
                          Width,
                          Height,
                          NavigateUrl,
                          IsActive,
                          Impressions,
                          AlternateText)
                 VALUES
                         (@prmBannerName,
                          @prmImageUrl,
                          @prmWidth,
                          @prmHeight,
                          @prmNavigateUrl,
                          @prmIsActive,
                          @prmImpressions,
                          @prmAlternateText)
                
            -- Hata kontrolü?
            IF (@@ERROR = 0)
            BEGIN
                SET @prmReturnVal = 0
                COMMIT TRANSACTION
            END
            ELSE
            BEGIN
                SET @prmReturnVal = -1
                ROLLBACK TRANSACTION
            END
    END
        
    RETURN @prmReturnVal
END

Diğer saklı yordamları örnek proje içinde bulabilirsiniz. BannerManagement sınıfını yazmaya başlayabiliriz:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using BannersBOWebApp.Business;
 
namespace BannersBOWebApp.DAL
{
    /// 
    /// BannerManagement: Veri erişim katmanını temsil eden sınıfımız.
    /// Veritabanı ile bağlantı kurarak veri çekme, kayıt ekleme, güncelleme ve
    /// kayıt silme işlemlerini yapar.
    /// Veritabanı ile iş katmanına uygun olacak ilişkileri düzenler.
    /// 
    public class BannerManagement
    {
        // Ayar dosyasındaki bağlantı bilgisini verir (salt okunur özellik).
        private static string ConnString
        {
            get
            {
                // Ayar dosyasından "AdventureWorksConn" anahtarındaki bilgiyi alır.
                // Bağlantı cümlesini kendi sisteminize göre değiştiriniz!
                return ConfigurationManager.ConnectionStrings["AdventureWorksConn"].ConnectionString;
            }
        }
 
        /// GetBannerList metodu geriye banner nesneleriyle doldurulmuş
        /// generic bir List koleksiyonu döndürür.
        /// 
        /// Generic List koleksiyonu
        public static List GetBannerList()
        {
            // Generic List koleksiyonu oluştur.
            List bannerList = new List();
 
            //SQL Server'a bağlantı oluştur.
            using (SqlConnection sqlcon = new SqlConnection(ConnString))
            {
                // SqlCommand nesnesini
                using (SqlCommand sqlcmd = new SqlCommand("usp_GetAllBanners", sqlcon))
                {
                    sqlcmd.CommandType = CommandType.StoredProcedure;
                    sqlcon.Open();
                    // SqlDataReader nesnesini yarat.
                    using (SqlDataReader reader = sqlcmd.ExecuteReader())
                    {
                        // SqlDataReader nesnesinin Read metodunu çalıştırarak
                        // veri olup olmadığını kontrol et.
                        while (reader.Read())
                        {
                            bannerList.Add(LoadDataRecord(reader));
                        }//while
                        // SqlDataReader nesnesini kapat.
                        reader.Close();
                    }//SqlDataReader
                    // Bağlantıyı kapat.
                    sqlcon.Close();
                }//SqlCommand
            }//SqlConnection
 
            return bannerList;
        }
      
        /// 
        /// Veritabanına bir banner ekleyen metodumuz.
        /// 
        ///  Eklenecek Banner nesnesi örneği
        /// Saklı yordam çalışmasından sonra, geriye bir tamsayı döner
        public static int AddBanner(Banner banner)
        {
            int returnValue;
 
            using (SqlConnection sqlcon = new SqlConnection(ConnString))
            {
                using (SqlCommand sqlcmd = new SqlCommand("usp_AddBanner", sqlcon))
                {
                    sqlcmd.CommandType = CommandType.StoredProcedure;
                    // SqlParameter nesneleri tanımlayıp, parametre değerlerini
                    // Banner sınıfı alanları üzerinden aktarıyoruz.
                    sqlcmd.Parameters.Add(new SqlParameter("@prmBannerName", banner.BannerName));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmImageUrl", banner.ImageUrl));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmWidth", banner.Width));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmHeight", banner.Height));
                    if (! String.IsNullOrEmpty(banner.NavigateUrl))
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmNavigateUrl", banner.NavigateUrl));
                    }
                    else
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmNavigateUrl", DBNull.Value));
                    }//if
                    sqlcmd.Parameters.Add(new SqlParameter("@prmIsActive", banner.IsActive));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmImpressions", banner.Impressions));
                    if (!String.IsNullOrEmpty(banner.AlternateText))
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmAlternateText", banner.AlternateText));
                    }
                    else
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmAlternateText", DBNull.Value));
                    }//if
                    // Saklı yordamın dönüş değeri parametresi veriliyor.
                    SqlParameter paramRet = sqlcmd.Parameters.Add("@prmReturnVal", SqlDbType.Int);
                    paramRet.Direction = ParameterDirection.Output;
 
                    sqlcon.Open();
                    // Saklı yordamı ExecuteNonQuery metoduyla çalıştır.
                    sqlcmd.ExecuteNonQuery();
                    sqlcon.Close();
                    // Saklı yordam çalıştırıldıktan sonra dönüş değerini alıyoruz.
                    returnValue = (int) paramRet.Value;
                }//SqlCommand
            }//SqlConnection
 
            return returnValue;
        }//AddBanner
 
        /// 
        /// Veritabanında bulunan bir banner'ı güncelleyen metodumuz.
        /// 
        ///  Güncellenecek Banner nesnesi örneği
        /// Geriye bir tamsayı döner
        public static int UpdateBanner(Banner banner)
        {
            int returnValue;
 
            using (SqlConnection sqlcon = new SqlConnection(ConnString))
            {
                using (SqlCommand sqlcmd = new SqlCommand("usp_UpdateBanner", sqlcon))
                {
                    sqlcmd.CommandType = CommandType.StoredProcedure;
                    sqlcmd.Parameters.Add(new SqlParameter("@prmBannerID", banner.BannerID));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmBannerName", banner.BannerName));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmImageUrl", banner.ImageUrl));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmWidth", banner.Width));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmHeight", banner.Height));
                    if (! String.IsNullOrEmpty(banner.NavigateUrl))
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmNavigateUrl", banner.NavigateUrl));
                    }
                    else
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmNavigateUrl", DBNull.Value));
                    }//if                    
                    sqlcmd.Parameters.Add(new SqlParameter("@prmIsActive", banner.IsActive));
                    sqlcmd.Parameters.Add(new SqlParameter("@prmImpressions", banner.Impressions));
                    if (!String.IsNullOrEmpty(banner.AlternateText))
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmAlternateText", banner.AlternateText));
                    }
                    else
                    {
                        sqlcmd.Parameters.Add(new SqlParameter("@prmAlternateText", DBNull.Value));
                    }//if
                    SqlParameter paramRet = sqlcmd.Parameters.Add("@prmReturnVal", SqlDbType.Int);
                    paramRet.Direction = ParameterDirection.Output;
 
                    sqlcon.Open();
                    sqlcmd.ExecuteNonQuery();
                    sqlcon.Close();
 
                    returnValue = (int) paramRet.Value;
                }//SqlCommand
            }//SqlConnection
 
            return returnValue;
        }//UpdateBanner
 
        /// 
        /// Veritabanında bulunan bir banner'ı silen metodumuz.
        /// 
        ///  Silinecek Banner nesnesi örneği
        /// Geriye bir tamsayı döner
        public static int DeleteBanner(Banner banner)
        {
            int returnValue;
 
            using (SqlConnection sqlcon = new SqlConnection(ConnString))
            {
                using (SqlCommand sqlcmd = new SqlCommand("usp_DeleteBanner", sqlcon))
                {
                    sqlcmd.CommandType = CommandType.StoredProcedure;
                    sqlcmd.Parameters.Add(new SqlParameter("@prmBannerID", banner.BannerID));
                    SqlParameter paramRet = sqlcmd.Parameters.Add("@prmReturnVal", SqlDbType.Int);
                    paramRet.Direction = ParameterDirection.Output;
 
                    sqlcon.Open();
                    sqlcmd.ExecuteNonQuery();
                    sqlcon.Close();
 
                    returnValue = (int)paramRet.Value;
                }//SqlCommand
            }//SqlConnection
 
            return returnValue;
        }//DeleteBanner
 
        /// 
        /// Banner sınıfına ait bir nesne örneklenerek IDataRecord'dan gelen
        /// değerlerle doldurulur.
        /// 
        /// 
        /// Banner tipinden nesne
        private static Banner LoadDataRecord(IDataRecord myDataRecord)
        {
            // Banner() sınıf nesnesi tanımla.
            Banner myBanner = new Banner();
 
            // Banner sınıfının özelliklerini bulunan verilerle doldur.
            myBanner.BannerID = (int)myDataRecord["BannerID"];
            myBanner.BannerName = (string)myDataRecord["BannerName"];
            myBanner.ImageUrl = (string)myDataRecord["ImageUrl"];
            myBanner.Width = (short)myDataRecord["Width"];
            myBanner.Height = (short)myDataRecord["Height"];
            myBanner.IsActive = (bool)myDataRecord["IsActive"];
            myBanner.Impressions = (int)myDataRecord["Impressions"];
 
            // Boş değerleri kontrol ediyoruz...
            if (myDataRecord["NavigateUrl"] != DBNull.Value)
            {
                myBanner.NavigateUrl = (string)myDataRecord["NavigateUrl"];
            }
 
            if (myDataRecord["AlternateText"] != DBNull.Value)
            {
                myBanner.AlternateText = (string)myDataRecord["AlternateText"];
            }
 
            return myBanner;
        }//LoadDataRecord
    }//BannerManagement class
}

Buraya kadar yazdığımız metodlar veri listesi çekme, kayıt ekleme, güncelleme ve silme işlemleri için şimdilik yeterlidir. Veri erişim sınıfına tekrar geri döneceğiz. Bundan sonra iş katmanının diğer bir sınıfı olan BannerBLL' i yazmaya başlayabiliriz.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Web.UI.WebControls;
using BannersBOWebApp.DAL;
 
namespace BannersBOWebApp.Business
{
    /// 
    /// Business (iş) sınıfımız, sunum katmanından gelen istekleri alıp veri erişim katmanına yollar.
    /// Banner nesneleri ile veritabanı arasındaki köprüyü sağlar.
    /// 
    [DataObjectAttribute]
    public class BannerBLL
    {
        // Banner nesneleri yüklü generic listeyi geri döndüren iş katmanı metodu.
        [DataObjectMethod(DataObjectMethodType.Select, true)]
        public static List GetBannerList()
        {
            return BannerManagement.GetBannerList();
        }
        
        // Veritabanına banner ekleyen iş katmanı metodu.
        [DataObjectMethod(DataObjectMethodType.Insert, true)]
        public static int AddBanner(Banner myBanner)
        {
            return BannerManagement.AddBanner(myBanner);
        }
 
        // Veritabanındaki bir banner'ı güncelleyen iş katmanı metodu.
        [DataObjectMethod(DataObjectMethodType.Update, true)]
        public static int UpdateBanner(Banner myBanner)
        {
            return BannerManagement.UpdateBanner(myBanner);
        }
 
        // Banner nesnesi parametresini alarak bir banner'ı silen iş katmanı metodu.
        [DataObjectMethod(DataObjectMethodType.Delete, true)]
        public static int DeleteBanner(Banner myBanner)
        {
            return BannerManagement.DeleteBanner(myBanner);
        }
 
        // Banner tipinden nesnelerden oluşmuş generic bir List<> koleksiyonu
        // GridView kontrolüne bağlanıyor.
        public static void BindBannerList(GridView myGridView)
        {
            // GridView kontrolüne GetBannerList metodundan dönen
            // generic bir List koleksiyonunu bağla.
            myGridView.DataSource = GetBannerList();
            myGridView.DataBind();
        }
    }
}

Buraya kadar yaptıklarımızla hemen basit bir web formu tasarımıyla beraber iş nesneleriyle ilk denemelerimizi gerçekleştirebiliriz. Şimdi default.aspx sayfası tasarımına geçelim ve araç kutusundan bir adet GridView kontrolünü alıp bırakalım. Daha sonra GridView veri kaynağını ObjectDataSource olarak seçelim. Kullanacağımız iş nesnesi (business object) için seçim yapalım:

Daha sonra veri işlemleri için metodlarımızı seçelim. İş katmanı içinden uygun metodları listeden seçerek Finish düğmesine basıyoruz. İş metodlarının başında DataObjectMethod nitelemesi olanların listede olduklarını görüyoruz.

İsteğe bağlı olarak GridView üzerinde bazı özellikler değiştirilebilir ve görsel ayarlamalar yapılabilir. Bazı alanları görüntülemek istemeyebilir veya başlıklarını yeniden yazabilirsiniz. Burada, GridView Task penceresinden, Enable Editing ve Enable Deleting kutularını işaretliyoruz. Ayrıca AutoGenerateColumns özelliğinin False, BannerID alanının ReadOnly olmasına dikkat ediniz. Alan adları ototmatik olarak geldiği için kendinize uygun biçimde özelleştirebilirsiniz.

Uygulamayı çalıştırdığımda kendi bilgisayarımdaki ekran görüntüsü aşağıdaki gibidir:



Hazırladığımız sınıfları kullanarak bu aşamaya kadar geldik. Yazdığımız sınıflarla, üstelik çok basit bir tasarımla, sunum katmanı için ayrı bir kod yazmamıza gerek kalmadan hemen uygulamaya geçebildik. Bu uygulama iş ve veri erişim katmanlarına basit bir örnek oluşturmaktadır. Sunum katmanından gelen isteklerin, iş katmanı kullanılarak işlenip geriye bir nesne döndürme işlemlerinden başka bir şey değildir.

İş nesneleriyle (Business Objects) banner web uygulaması geliştirme
Bu bölümde, iş nesnelerini kullanarak web uygulamamızı biraz daha geliştireceğiz. Bir web sayfasında GridView kontrolüyle banner verileri listelemenin ötesinde, ayrı bir sayfada banner ekleme, bir banner kaydını güncelleme ve silme işlerini yapacağız. Banner yönetimi için ObjectDataSource kullanmayacağız. Verileri GridView' e bağlarken, bir kaydı silerken ayrı metodlar kullanacağız. Bunun için iki yeni web formu tasarlayacağız. İlk önce örnek web sitemizde admin adlı yeni bir kalsör oluşturuyoruz. Şimdi, bu klasörün altında bannerList adında yeni web formumuzu ekliyoruz. Bu formun üzerine UpdatePanel, GridView, düğme, etiket, LinkButton v.b. kontrollerini bırakıyoruz. GridView kontrolünde görünmesini istediğimiz alanlar için Fields editörü yardımıyla DataBound alanlar oluşturuyoruz. Bunların alacağı DataField değerlerini de veritabanındaki tabloya uygun olarak giriyoruz. Diğer görsel düzenlemeler kullanıcının arzusuna göre yapılabilir.

Güncelleme ve silme işlemleri sırasında, her satır için Edit Delete gibi linkler kullanmayacağız. GridView' deki bir satırı seçebilmek için yeni bir TemplateField alanı oluşturuyoruz. Her satırın başında bir radyo düğmesi görünecek. Kullanıcı bu düğmeyi fare ile işaretleyince bu satırın BannerID alan değeri okunacak. Yani, uygulama hangi kayıt numaralı satırın seçilmiş olduğunu anlayacak. Tabloda BannerID alanının tekil indeks olduğuna dikkat ediniz. ASP sayfamızın kaynak kodları içindeki Columns kısmında bulanan TemplateField içerisine, şu satırları ekliyoruz:


   
       
   

Sayfamızın tasarım aşamasındaki görünümü aşağıdaki gibidir:

Bu sayfanın BannerID değerini hedef sayfada kullanabilmek için genel bir özellik tanımlamak ve PreviousPage referansını vermemiz gerekir.

Sayfanın kodları aşağıdaki gibidir:

using System;
using System.Data;
using System.Web;
using System.Web.UI;
using System.Collections.Generic;
using BannersBOWebApp.Business;
 
public partial class bannerList : System.Web.UI.Page
{
    // Seçilen banner ID'sini tutan üye.
    private int m_bannerID;
 
    protected void Page_Load(object sender, EventArgs e)
    {
        // Sayfanın PostBack (geri gönderim) ile gösterilip gösterilmediğini
        // kontrol ediyoruz. Sayfa ilk kez gösteriliyorsa false değeri alır.
        if (!Page.IsPostBack)
        {
            // Banner veri kümesini GridView1 kontrolüne bağlamak için
            // iş katmanından BindBannerList metodunu çağır.
            BannerBLL.BindBannerList(GridView1);
        }
    }
    
    protected void btnNew_Click(object sender, EventArgs e)
    {
        // Veri girişi sayfasına (hedef) yönlendir.
        Server.Transfer("~/admin/addUpdateBanner.aspx");
    }
 
    protected void btnEdit_Click(object sender, EventArgs e)
    {
        int bannerId = GetSelectedID();
 
        if (bannerId > 0)
        {
            // Veri güncelleme sayfasına (hedef) yönlendir.
            Server.Transfer("~/admin/addUpdateBanner.aspx");
        }
        else
        {
            lblMessage.Text = "Bir kayıt seçiniz!";
        }//if
    }
 
    protected void btnDelete_Click(object sender, EventArgs e)
    {
        // Seçilen banner kayıt nosu değişkene atanıyor.
        int bannerId = GetSelectedID();
 
        // Seçilen kayıt numarası, ID sıfırdan büyük mü?
        if (bannerId > 0)
        {
            // Eğer büyükse, iş katmanından silme işlemini yapacak
            // olan DeleteBanner metodunu çağır.
            int retVal = BannerBLL.DeleteBanner(bannerId);
 
            // Metod çağrısından dönen değeri kontrol ediyoruz:
            if (retVal == 0)
            {
                // Silme başarıyla tamamlandıktan sonra
                // GridView kontrolüne verileri tekrar yükle.
                BannerBLL.BindBannerList(GridView1);
            }
            else
            {
                // Bir hata oluştu.
                lblMessage.Text = "Kayıt silme işleminde hata oluştu!";
            }//if retVal
        }
        else
        {
            // Kayıt seçilmemiş ve boşsa uyarı yaz.
            lblMessage.Text = "Bir kayıt seçiniz!";
        }//if
    }
 
    /// 
    /// GridView üzerinde radyo düğmesiyle seçilen banner'ın kayıt nosunu verir.
    /// Bu metod güncelleme ve silme işlemi yapılmak istendiğinde çağrılır.
    /// 
    /// Seçilen kaydın ID'si olan bir tamsayı
    private int GetSelectedID()
    {
        // GridView üzerindeki, radyo düğmesi işaretli, satırın [BannerID] alan
        // değeri bir değişkene string olarak atanıyor.
        string strID = Request.Form["RadioButtonBannerID"];
 
        if (!String.IsNullOrEmpty(strID))
        {
            m_bannerID = Convert.ToInt32(strID);
        }
        else
        {
            m_bannerID = 0;
        }
 
        return m_bannerID;
    }
 
    // Seçilen banner ID'sine ait public özellik.
    public int BannerID
    {
        get { return m_bannerID; }
    }
}

Seçili bir kaydı silmek istediğimizde aşağıda gösterildiği gibi önce bir uyarı mesajının gelmesi gerekir.

Bunu yapabilmek için Silme tuşunun OnClientClick özelliğine şunları girmemiz gerekir:

return confirm('Bu kaydı silmek istediğinizden emin misiniz?');

Veri girişi ve düzeltme için addUpdateBanner adlı yeni web formunu tasarlamaya başlayabiliriz. Bu formun üzerine bir tablo, metin kutuları, düğmeler, etiketler, bir kaç validator kontrolleri yerleştiriyoruz. Tasarım şu şekildedir:

Bu web formun Page_Load ve Kaydet düğmesine basılma olayları için kodlarımızı yazalım:

using System;
using System.Data;
using System.Web;
using System.Web.UI;
using BannersBOWebApp.Business;
 
public partial class addUpdateBanner : System.Web.UI.Page
{
    // Kaynak sayfadaki BannerID özelliğine erişilerek alınacak
    // değeri tutacak değişken (banner kayıt nosu).
    protected static int bannerId;
 
    protected void Page_Load(object sender, EventArgs e)
    {
        // Postback işlemi kontrolü
        if (!Page.IsPostBack)
        {
            // PreviousPage tipinin null olup olmadığı kontrol edilmesi.
            if (PreviousPage != null)
            {
                // Kaynak sayfadaki BannerID özelliğine erişim.
                bannerId = PreviousPage.BannerID;
                
                // Banner'a ait ID sıfırdan büyük mü? Kontrol edelim:
                // Eğer büyükse, güncelleme için sayfa kontrollerini hazırla
                // yoksa bu bir yeni kayıt ekleme işlemi olacaktır.
                if (bannerId > 0)
                {
                    // Gönderilen bannerID parametresine göre:
                    // Banner nesne örneği yarattıktan sonra, bu sınıfa ait özellikleri
                    // GetBanner metoduyla dolduruyoruz.
                    Banner myBanner = BannerBLL.GetBanner(bannerId);
                    // Banner nesne örneği boş mu?
                    if (myBanner != null)
                    {
                        // Sınıf alanlardan alınan değerleri sayfa kontrollerine yüklüyoruz.
                        txtBannerName.Text = myBanner.BannerName;
                        txtImageUrl.Text = myBanner.ImageUrl;
                        txtWidth.Text = myBanner.Width.ToString();
                        txtHeight.Text = myBanner.Height.ToString();
                        txtNavigateUrl.Text = myBanner.NavigateUrl;
                        dropActive.SelectedIndex = Convert.ToInt16(myBanner.IsActive);
                        txtImpressions.Text = myBanner.Impressions.ToString();
                        txtAlternate.Text = myBanner.AlternateText;
                    }//if myBanner
                }
                else
                {
                    // Yeni kayıt ekleme için istediğimiz sayfa kontrollerini ayarlıyoruz.
                    dropActive.SelectedIndex = 1;
                }//if bannerID
                // Banner kayıt nosunu sayfada göster.
                lblBannerID.Text = bannerId.ToString();
                txtBannerName.Focus();
            }
            else
            {
                // PreviousPage tipi null değer almışsa kaynak sayfaya yönlendir.
                Response.Redirect("~/admin/bannerList.aspx");
            }//if previouspage
        }//if IsPostBack
    }
 
    protected void btnSave_Click(object sender, EventArgs e)
    {
        // İş katmanındaki AddBanner ve UpdateBanner metodlarına yapılacak
        // çağrılardan dönecek sayı değerini tutmak için bir değişken tanımlıyoruz.
        int retVal = 0;
        // Banner nesne örneği yaratalım.
        Banner banner = new Banner();
        // Banner sınıfının BannerID özelliğine atama yapıyoruz.
        banner.BannerID = bannerId;
        // Sayfa kontrollerinden girilen değerleri Banner sınıfının alanlarına yüklüyoruz.
        banner.BannerName = txtBannerName.Text;
        banner.ImageUrl = txtImageUrl.Text;
        banner.Width = Convert.ToInt16(txtWidth.Text);
        banner.Height = Convert.ToInt16(txtHeight.Text);
        banner.NavigateUrl = txtNavigateUrl.Text;
        banner.IsActive = Convert.ToBoolean(dropActive.SelectedIndex);
        banner.Impressions = Convert.ToInt32(txtImpressions.Text);
        banner.AlternateText = txtAlternate.Text;
        // Banner kayıt değeri sıfırdan büyük mü?
        if (bannerId > 0)
        {
            // Eğer büyükse, iş katmanından güncelleme yapacak
            // olan UpdateBanner metodunu çağır.
            retVal = BannerBLL.UpdateBanner(banner);
        }
        else
        {
            // İş katmanından kayıt ekleme işlemini yapacak
            // olan AddBanner metodunu çağır.
            retVal = BannerBLL.AddBanner(banner);
        }//if
 
        // Veritabanına banner ekleyen veya güncelleyen metodlardan herhangi birinden
        // dönen değeri kontrol ediyoruz:
        if (retVal == 0)
        {
            // İşlem başarıyla tamamlandı. Kaynak sayfaya yönlendir.
            Response.Redirect("~/admin/bannerList.aspx");
        }
        else
        {
            // Bir hata oluştu.
            lblMessage.Text = "Hata oluştu!";
        }//if retVal
    }//btnSave_Click
}

Veri girişi sayfasının Page_Load olayına yakından inceleyecek olursak, PreviousPage ile bir önceki sayfadan BannerID özelliğinden kayıt numarası alınıyor. Bu sayı sıfırdan büyükse, sayfa güncelleme için hazırlanıyor. Bu numara için bir Banner nesne örneği çıkartılıyor ve iş katmanından GetBanner metoduyla bir istek yapılıyor. Böylece dönen nesne yardımıyla ilgili alanların doldurulması tamamlanıyor. Aksi halde, BannerID pozitif bir sayı değilse, bunun bir yeni kayıt isteği olduğuna karar veriliyor. Böylece iş katmanına gidilmiyor. Save düğmesi olayında da aynı mantık kullanılmaktadır. Banner kayıt sayısı sıfırdan büyükse güncelleme, aksi durumda iş katmanından kayıt ekleme yapacak metodlardan biri çağrılacaktır. Daha sonra iş katmanından dönen değer kontrol edilerek gerekli yönlendirme veya uyarı yapılıyor.

BannerID kayıt numarasına göre arama ve silme operasyonları için veri erişim katmanına, yani BannerManagement sınıfına geri dönerek aşağıdaki metodları ekleyelim:

/// 
/// Gönderilen bir banner ID parametresine göre çekilen verileri
/// bir Banner nesnesine yükleyip geriye veren metod.
/// 
///  Banner'a ait ID, benzersiz sayı
/// Banner nesne örneği
public static Banner GetBanner(int bannerID)
{
    // Banner() sınıf nesnesi tanımla.
    Banner myBanner = new Banner();
    //SQL Server'a bağlantı oluştur.
    using (SqlConnection sqlcon = new SqlConnection(ConnString))
    {
        // SqlCommand nesnesini
        using (SqlCommand sqlcmd = new SqlCommand("usp_GetBannerByID", sqlcon))
        {
            sqlcmd.CommandType = CommandType.StoredProcedure;
            sqlcmd.Parameters.Add(new SqlParameter("@prmBannerID", bannerID));
            sqlcon.Open();
            // SqlDataReader nesnesini yarat.
            using (SqlDataReader reader = sqlcmd.ExecuteReader())
            {
                // SqlDataReader nesnesinin Read metodunu çalıştırarak
                // veri olup olmadığını kontrol et.
                if (reader.Read())
                {
                    // Banner sınıfının özelliklerini bulunan verilerle doldur.
                    myBanner = LoadDataRecord(reader);
                }//if
                // SqlDataReader nesnesini kapat.
                reader.Close();
            }//SqlDataReader
            // Bağlantıyı kapat.
            sqlcon.Close();
        }//SqlCommand
    }//SqlConnection
 
    return myBanner;
}//GetBanner
 
 
/// 
/// Veritabanında bulunan bir banner'ı silen metodumuz.
/// 
///  Silinecek banner ID'si, benzersiz sayı
/// Geriye bir tamsayı döner
public static int DeleteBanner(int bannerID)
{
    int returnValue;
 
    using (SqlConnection sqlcon = new SqlConnection(ConnString))
    {
        using (SqlCommand sqlcmd = new SqlCommand("usp_DeleteBanner", sqlcon))
        {
            sqlcmd.CommandType = CommandType.StoredProcedure;
            sqlcmd.Parameters.Add(new SqlParameter("@prmBannerID", bannerID));
            SqlParameter paramRet = sqlcmd.Parameters.Add("@prmReturnVal", SqlDbType.Int);
            paramRet.Direction = ParameterDirection.Output;
 
            sqlcon.Open();
            sqlcmd.ExecuteNonQuery();
            sqlcon.Close();
 
            returnValue = (int) paramRet.Value;
        }//SqlCommand
    }//SqlConnection
 
    return returnValue;
}//DeleteBanner

Şimdi iş katmanına, yani BusinessBLL sınıfına geri dönerek aşağıdaki metodları ekleyelim:

// Banner entity tipini verilen banner ID’sine göre yükleyen ve
// geri döndüren bir iş katmanı metodu.
public static Banner GetBanner(int _bannerID)
{
    return BannerManagement.GetBanner(_bannerID);
}
 
// Bir banner ID'sini parametre alarak bir banner'ı silen iş katmanı metodu.
public static int DeleteBanner(int _bannerID)
{
    return BannerManagement.DeleteBanner(_bannerID);
}

Nihayet uygulamamızı denemenin zamanı geldi. Banner' ların listelendiği sayfayı açtığımda kendi bilgisayarımdaki ekran görüntüsü aşağıdaki gibidir:

Bir kaydı seçip düzeltme yapacağımızı varsayıyorum. Gerekli düzeltmeleri yaptıktan sonra Kaydet düğmesine basılması yeterlidir. Kayıt girişi veya güncellemeyi iptal durumunda ise Vazgeç düğmesine basılır. Veritabanında hiç bir ekleme veya değişiklik yapılmadan bir önceki sayfaya dönülür.

Sonuç:
Makalemizde bir XML dosyasından veri alarak basit bir banner örneği yaptık. Büyük ölçekli projeler için XML dosyasını veri kaynağı olarak kullanmanın zorluğu çok açıktır. Daha sonra çok katmanlı mimariyi inceledik. Bu uygulamayı veritabanında yapabilmek için bir tablo ve saklı yordamlar hazırladık. Veri erişim katmanı ve iş katmanlarını hazırladıktan sonra ObjectDataSource kullanarak .NET içinde ne kadar çabuk uygulama gerçekleştirilebileceğini gördük. Son olarak daha kolay, kullanıcı dostu olan bir banner yönetimi için iki ayrı web formu hazırladık ve gerekli kodları yazdık.

Makalemin sizlere yararlı olması dileklerimle, hoşçakalın...

Business Objects uygulaması için tıklayın.

Süleyman Payaslı
[email protected]

Kaynaklar:
MSDN Library - Creating a Business Logic Layer
Yaşar Gözüdeli - Nesneye Dayali Programlama, 3 Katman Mimarisi ve ASP.NET
Burak Selim Şenyurt - Data Access Application Block Nedir?
Süleyman Payaslı - C# ile Veri Erişim Katmanı Geliştirme
Burak Selim Şenyurt - Cross-Page Postback Paradigması
MSDN Library - AdRotator Class
Sem Göksu - ASP.NET 2.0 da AdRotator Nesnesi
MSDN: David Berry - Creating a Banner Ad System

Makale:
ASP.NET'de Business Object Layer ile Banner ASP.NET Süleyman Payaslı
  • Yazılan Yorumlar
  • Yorum Yaz
TEM
13
2008
datareader herzaman daha hizlidir ve performansi arttirmak icin tercih edilir. Eger amaciniz sadece veriyi dbden alip gostermek ise datareader kullanip veriyi collection nesnesine atmak en mantikli yontemdir. Dataset her ne kadar icinde cok fazla ozellik barindirsa da eger bu ozellikleri kullanmiycaksaniz datasetden uzak durun
TEM
1
2008
c# egitimimi henuz tamamladım ve programatik acıdan tam olarak bir altyapı secebilmis degilim bir islemin bir cok yolla yapıldıgını dusunursek acık konusmak gerekirse en iyi yontemi sorgulamaktayım bu aralar csharpnedir.com daki ASP.NETde Business Object Layer ile Banner makalenizde DataAccessLayer uzerinde bulunan public static ListBanner GetBannerList() metodunda tum datayı once bir list kolleksiyonuna datareader ile aktarılıyor private static Banner LoadDataRecord(IDataRecord myDataRecord) uzerindede datareaderla alınmıs olan kaydı list kollesiyonu banner nesnesi olarak ekleniyor. dataset kullanmak yerine bu sekilde kullanmanın ne gibi farklılıkları olabilir veya performans acısından ne gibi fayda zarar saglar. paylaşımınız için tekrardan teşekkur eder iyi çalışmalar dilerim.
Sayfalar : 1 
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • Eklenen Son 10
  • Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor