ASP.NET Dynamic Data – Gelişmiş Scaffolding

30 Nisan 2010

Merhabalar, daha önce ASP.NET Dynamic Data(yazının devamında DD kısaltmasını kullanacağım) hakkında bazı bilgileri yayınlamıştım. Yeni bir makale konusunda düşünürken makale konusu olarak gerçek bir DD projesinde kullanıcı tarafından gelebilecek isteklerin hızlı bir şekilde nasıl karşılanabilineceğinden bahsetmenin uygun olduğuna karar verdim.
Yazılımcı gözüyle değerlendirmek gerekirse kullanıcı gereksinimleri konusunda gözden kaçan bir çok gereksinimi görülmeyebilir.  Örneğin bir tablo içindeki kayıtların listelenmesi yazılımcı için gayet yeterlidir ancak kullanıcı gözüyle bakıldığında her şeyin listelenmesi çoğu zaman gereksiz olacaktır. Bu kapsamda kullanıcı isteklerine karşılık sorun çözümüyle alakalı makalele dizisinin ilkini yazmaya başlıyorum. Daha önceki makalelerde bahsettiğim isimlendirme, biçimlendirme vb. gibi temel işlemlere bu makalede değinmeyeceğim.

Kullanıcı tarafında tablo üzerindeki her alanın(column) görüntülenmesi istenmeyebilir. Bazı durumlarda ise tüm kayıtların listelenmesi kullanım kolaylığı açısından sıkıntılı olabilir.

Scaffolding tekniğiyle istenilen alanların tüm şablonlarda görüntülenmesini engelleyebiliyoruz. Özellikle listeleme sayfalarında tüm alanların sayfada görünür halde olması yatay olarak uzayan bir sayfaya neden olur ancak bu alanları klasik scaffolding tekniği ile gizlersek diğer şablonlardanda kayboluverir.  İşte burada asıl sorun ortaya çıkıyor: Gizlenen alanların kullanıcı tarafından düzenlenmesi gerekiyorsa yada detaylı görüntüleme şablonunda tüm alanların görüntülenmesi gerekiyorsa ne yapacağız?

  Aletleri geliştirmek DD için her zaman kazanımdır. Bu senaryoda scaffolding tekniğini sayfa şablonlarına göre nasıl özelleştirebileceğimizi öğreneceğiz.

Kullanabileceğimiz veri bileşenleri(GridView, FormView, DetailsView vb.) veri listeleme sırasında listeleme işlemi için IAutoFieldGenerator arayüzünü uygulayan bir sınıf ile veri alanları üzerindeki kararını verir. Varsayılan alan oluşturucularda verideki tüm alanlar DD bildirimleri uygunlandıktan sonra(scaffolding gibi kısıtlamalar vb.) listelenir. Yapılması gereken şey ise veri listeleme işini gerçekleştirme görevini yazacağımız bir sınıfın üstlenmesidir.

IAutoFieldGenerator arayüzünü uygulayan sınıfımız:

namespace Eposta.Core.CustomFieldGenerator{    using System.Collections.Generic;    using System.Web.UI;    using System.Web.DynamicData;     

    /// <summary>    /// Bu sınıf veri listelemesini işlemlerini    /// özelleştirmek amacıyla yazılmıştır.     /// </summary>    public class CustomColumnGenerator : IAutoFieldGenerator    {        /// <summary>        /// Veri listelemesi için incelenecek        /// tablo değişkenini tutar        /// </summary>        protected MetaTable mTable = null;        #region IAutoFieldGenerator Members        /// <summary>        /// Listeleme işlemini gerçekleştirecek method        /// </summary>        /// <param name="control"></param>        /// <returns></returns>        public System.Collections.ICollection GenerateFields(Control control)        {            // Uygun kolonların biriktirildiği koleksiyon            List<DynamicField> dynFieldList = new List<DynamicField>();            // MetaTable atanmışsa            if (mTable != null)            {                // Her bir MetaColumn için                foreach (MetaColumn mColumn in this.mTable.Columns)                {                    // Scaffolding ataması yapılmışsa koleksiyona eklenmesi                    // uygun değildir. Eğer bu kontrol yapılmazsa ilgili                    // alan görüntülenecektir. Çünkü tüm sorumluluğu almış                    // bulunuyoruz                    if (                            !mColumn.Scaffold                        )                        continue;                     DynamicField dynField = new DynamicField();                    dynField.DataField = mColumn.Name;                    dynFieldList.Add(dynField);                }            }            return dynFieldList;        }        #endregion    }}

Scaffolding tekniğini denetleyerek görüntüleme işlemini üstlenen sınıfımız artık hazır. Şimdi sıra şablonlara göre bu denetleme işlemine geldi. Varsayılan şablonlar için bir enum tanımlayıp GenerateFields methodunda şablona görede bir denetleme yapmamız gerecektir.

namespace Eposta.Core.Enums{    public enum PageTemplateType    {        Details,        Edit,        Insert,        List,        ListDetails    }}

Özelleştirme işlemlerinin uygulanabilmesi için özel bir öznitelik geliştirip bildirimlerin bu öznitelik üzerinden gerçekleştirmesi gerekiyor bunun için aşağıdaki sınıfı kullanabiliriz.

[more]

using System;using Eposta.Core.Enums;

namespace Eposta.Core.CustomAttributes{    [AttributeUsage(AttributeTargets.Property)]    public class CustomHiddenColumnAttribute : Attribute    {        /// <summary>        /// İlgili alanın gizlenmesi gereken sayfa şablonları belirleniyor        /// </summary>        public PageTemplateType[] PageTemplateTypes { get; private set; }        /// <summary>        /// Parametresiz bir constructor yazılması mecburi ancak        /// kullanılmaması için hata fırlatılması daha uygun        /// </summary>        public CustomHiddenColumnAttribute()        {            throw new InvalidOperationException();        }        /// <summary>        /// Sayfa şablonlarının atama işleminin kolaylaştırılması        /// nedeniyle params yöntemi kullanılmıştır. Öznitelik         /// tanımlamasında AllowMultiple=true atamasıda yapılabilir        /// </summary>        /// <param name="PageTemplateParams"></param>        public CustomHiddenColumnAttribute(params PageTemplateType[] PageTemplateParams)        {            this.PageTemplateTypes = PageTemplateParams;        }    }}

Bu özniteliğin örnek tanımlaması aşağıdaki gibidir. Daha öncede belirttiğim gibi öznitelik yazmayı çok severim :) Bundan böyle sadece aşağıdaki kodu kullarak tüm kodu yazmadan işimizi halledebiliriz.

[CustomHiddenColumn(        PageTemplateType.List, PageTemplateType.ListDetails)]public string SmtpHost { get; set; }

Madem bu kadar kod yazdık birde MetaColumn nesneleri için genişletilmiş bir method yazarak kolonda ve şablona göre gizlilik bildirimi yapılmışmı diye kontrol edelimki her seferinde bir yığın kod yazmaktan kurtulalım.

using System.Linq;using Eposta.Core.CustomAttributes.UIHint;using Eposta.Core.CustomAttributes;using Eposta.Core.Enums;/// <summary>/// Ömer Faruk ZORLU/// </summary>namespace Eposta.Core.Extentions{    public static class MetaColumnExtentions    {        /// <summary>        /// Sayfa şablonuna göre alanın gizlilik durumunu dönderir        /// </summary>        /// <param name="mColumn"></param>        /// <param name="pTemplateType"></param>        /// <returns></returns>        public static bool IsHidden(this System.Web.DynamicData.MetaColumn mColumn, PageTemplateType pTemplateType)        {            // Kolon üzerinde atanmış ustomHiddenColumn özniteliği alınıyor            // Eğer çoklu tanımlama(AllowMultiple) ya izin verilmişse bir            // döngü içerisinde kontrol edilmesi gerekir            CustomHiddenColumnAttribute chCAttr =                mColumn.Attributes.OfType<CustomHiddenColumnAttribute>().FirstOrDefault();               //  Herhangi bir öznitelik ataması yoksa gizli değildir            if (chCAttr == null)                return false;             // İlgili alan için yapılan gizlilik bildirimleri parametrede            // gönderilmiş sayfa şablonunu içeriyorsa gizlidir            return chCAttr.PageTemplateTypes.Contains(pTemplateType);;        }    }}

Artık daha önce yazdığımız alan oluşturucu sınıf üzerinde özel gizleme yapımızı denetleyen kodlar yazabiliriz. Yukarıda yazdığımız sınıfa yeni eklenen kodlar kalın olarak yazılmıştır.

 

using System.Collections.Generic;using System.Web.DynamicData;using System.Web.UI;using Eposta.Core.Extentions;using Eposta.Core.Enums; namespace Eposta.Core.CustomFieldGenerator{    /// <summary>    /// Bu sınıf veri listelemesini işlemlerini    /// özelleştirmek amacıyla yazılmıştır.     /// </summary>    public class CustomFieldGenerator : IAutoFieldGenerator    {        /// <summary>        /// Veri listelemesi için incelenecek        /// tablo değişkenini tutar        /// </summary>        protected MetaTable mTable = null;

        protected PageTemplateType pTemplateType;         #region ctor         public CustomFieldGenerator(MetaTable _mTable, PageTemplateType _pTemplateType)        {            this.mTable = _mTable;            this.pTemplateType = _pTemplateType;        }         #endregion         #region IAutoFieldGenerator Members        /// <summary>        /// Listeleme işlemini gerçekleştirecek method        /// </summary>        /// <param name="control"></param>        /// <returns></returns>        public System.Collections.ICollection GenerateFields(Control control)        {            // Uygun kolonların biriktirildiği koleksiyon            List<DynamicField> dynFieldList = new List<DynamicField>();            // MetaTable atanmışsa            if (mTable != null)            {                // Her bir MetaColumn için                foreach (MetaColumn mColumn in this.mTable.Columns)                {                    // Scaffolding ataması yapılmışsa koleksiyona eklenmesi                    // uygun değildir. Eğer bu kontrol yapılmazsa ilgili                    // alan görüntülenecektir. Çünkü tüm sorumluluğu almış                    // bulunuyoruz                    if (                            !mColumn.Scaffold                        )                        continue;                     // List ve ListDetails şablonları için IsHidden                    // genişletilmiş methodu ve IsLongString methodunu                    // kontrol ediyoruz ancak Details şablonu için                    // IsLongString methodunu kontrol edip gizlersek                    // uzun metin alanlar görüntülenmeyecek yani ufak bir                    // bug oluşacaktır.                    switch (this.pTemplateType)                    {                        case PageTemplateType.Details:                            if (mColumn.IsHidden(this.pTemplateType))                                continue; // foreach                            break;                        case PageTemplateType.List:                            if (mColumn.IsHidden(this.pTemplateType) ||                                    mColumn.IsLongString)                                continue; // foreach                            break;                        case PageTemplateType.ListDetails:                            if (mColumn.IsHidden(this.pTemplateType) ||                                    mColumn.IsLongString)                                continue; // foreach                            break;                        default:                            break;                    }                     // Varsayılan şablonların haricinde uzun metinlerin                    // görüntülenmesini engellemek amacıyla bu kontrol                    // yapılıyor                    if (mColumn.IsLongString)                        continue;                     DynamicField dynField = new DynamicField();                    dynField.DataField = mColumn.Name;                     dynFieldList.Add(dynField);                }            }            return dynFieldList;        }        #endregion    }}

Son adımında ise ilgili veri kontrolüne veri listeleme işlemini bizim üstleneceğimizi bildirmek gerekiyor. GridView nesnesi için ColumnGenerator DetailsView içinse RowGenerator parametresi kullanılıyor. Son haliyle List.aspx.cs ve Details.aspx.cs şablon kodları aşağıdaki gibi tanımlanmalıdır.

 

List.aspx.cs kodları:

using System;using System.Web.DynamicData;using Eposta.Core.CustomFieldGenerator;using Eposta.Core.Extentions; public partial class List : System.Web.UI.Page{    protected MetaTable table;    protected void Page_Init(object sender, EventArgs e)    {        DynamicDataManager1.RegisterControl(GridView1, true /*setSelectionFromUrl*/);        table = GridDataSource.GetTable();        GridView1.ColumnsGenerator = new CustomFieldGenerator(table, Eposta.Core.Enums.PageTemplateType.List);    }    protected void Page_Load(object sender, EventArgs e)    {        Title = table.DisplayName;        InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert);         // Disable various options if the table is readonly        if (table.IsReadOnly)        {            GridView1.Columns[0].Visible = false;            InsertHyperLink.Visible = false;        }    }    protected void OnFilterSelectedIndexChanged(object sender, EventArgs e)    {        GridView1.PageIndex = 0;    }}


Details.aspx.cs kodları:

using System;using System.Linq;using System.Web.DynamicData;using System.Web.UI.WebControls;using Eposta.Core.CustomFieldGenerator;using Eposta.Core.CustomAttributes; public partial class Details : System.Web.UI.Page {    protected MetaTable table;    protected void Page_Init(object sender, EventArgs e) {        DynamicDataManager1.RegisterControl(DetailsView1);    }    protected void Page_Load(object sender, EventArgs e) {        table = DetailsDataSource.GetTable();        DetailsView1.RowsGenerator = new CustomFieldGenerator(table, Eposta.Core.Enums.PageTemplateType.Details);

        Title = table.DisplayName;

        ListHyperLink.NavigateUrl = table.ListActionPath;    }    protected void DetailsView1_ItemDeleted(object sender, DetailsViewDeletedEventArgs e) {        if (e.Exception == null || e.ExceptionHandled) {            Response.Redirect(table.ListActionPath);        }    }}

Çözüm itibari ile Grup tablosunda yapılan tanımlalarla listeleme sayfa şablonlarında bazı alanların gizlenmesini güncelleme ve detaylı görüntüleme sayfa şablonlarında ise kullanıcının verileri görüntülemesine ve düzenlemesine imkan tanımış olduk. Ekran görüntüleri aşağıdaki gibidir.

Güncelleme ekranı:

Listeleme ekranı:

Bir yazının daha sonuna geldik. Kullanıcı gereksinimleriyle alakalı makaleler devam edecektir. Bir sonraki makalede görüşmek üzere. Yaşasın dinamizm!

Ömer Faruk ZORLU

ASP.NET ,

“ExtJS, Coolite ne ola ki? ” Yazı Dizisi Vol.1

30 Nisan 2010

Günümüz Web programcılığı alanında vazgeçemeyeceğimiz bir istemci-taraflı
yorumlanan script dilidir JavaScript. Hayatımıza 1995'de Netscape 2.0 ile
birlikte giren , önceleri  Mocha daha sonra
LiveScript
ve en son JavaScript adını alan (Sun
Microsystems'ın Java sıyla bir alakası yok.)
müthiş buluş diye
tanımlayabiliriz bence JavaScript'i. Web ile uğraşan herkes, en azından bir kere
kullanmıştır eminim. Özellikle görsel sunum tarafında, çok fazla varyasyon elde
etmemize yardımcı oluryor. Hatırlıyorum da , küçükken bir site tasarımıyla
uğraşıyordum ve sitede havai fişek gösterisi olsun istemiştim. O zamanlar da
hazır JavaScript kodu bulabileceğimiz çok kaynak vardı. Birkaç saniye içinde,
web sitesinde havai fişek gösterisi efektini yakalayabilmiştim. Hiç unutmam
içimden : "Allah JavaScript'i başımızdan eksik etmesin!" demiştim.

Sadece görsellik ile bitmiyor JavaScript'in bu kadar popüler olmasındaki
etmenler. AJAX(Asynchoronous JavaScript And XML) kavramının temeli,
isminin açılımından da anlaşılacağı üzere, JavaScript'tir. XMLHttpRequest
objesiyle (IFRAME de kullanılabilir) yapılan bilgi transferi sonrasında, bu
bilgiyi dinamik bir şekilde kullanıcıya sunmak ve bilgiyle etkileşim halinde olmak için
JavaScript kullanırız.

JavaScript'in yukarıda saydığım özelliklerini ve gücünü göz önüne alan
firmalar, açık kaynaklı JavaScript kütüphaneleri oluşturdular. Bu çalışmaların
en çok göz önünde olanı jQuery oldu. AJAX kullanımının artmasıyla jQuery
kullanımı da arttı. Hakkında birçok makale ve kitap yazıldı.
İlgilenenler jQuery.com adresinde, BOOKS ABOUT JQUERY bölümünü inceleyebilirler.
Uğur Umutluoğlu'nun da "ASP.NET’te
jQuery ile AJAX İşlemleri
" başlıklı bir makalesi var.

jQuery'nin yanı sıra, Türkiye'de hakkında pek konuşulmayan; ama üstüne birçok
firmanın framework'ler geliştirdiği bir kütüphane var :
ExtJS
. Şans eseri varlığından haberim oldu
aslında. İş görüşmesine gittiğim firmada (şuan çalıştığım firma), görüşme
sırasında adı geçti. Biraz ARGE çalışmasından sonra aslında ne kadar kullanışlı
bir kütüphane olduğunun farkına vardık.

Tam JS kodlarına gömülmeye hazırlandığım sırada karşıma
Coolite
adında,
efsane, birşey çıktı. Efsane olmasının nedeni .Net'de Markup kodu yazarak Ext objeleri yaratma gücü
veren bir framework olmasıydı. Hatta, yarattığımız objelere C# ya da VB kodu
yazarak ulaşma yolunu sunuyordu. Aramızda kalsın, JS kodu yazmaktansa C#
ya da VB kodu yazmayı tercih ederim.

Bugün yaptığım bir araştırmaya göre de, TURKCELL TEKNOLOJIlabs ExtJS
kütüphanesini referans alarak, Java için açık kaynaklı  bir framework
geliştirmişler. Adı da ISOLA.
Coolite'ın Java versiyonu. Güzel tarafı Türkcell'in bu framework'ü open source
dağıtması. Coolite'ın ücretli bir framework olduğunu düşünürsek, bu nokta
ISOLA'yı daha üstün kılıyor bence.

Tüm bu gelişmeler beni bu konularda makaleler dizisi yazmaya itti ve işte
burdayız.

Genel akış içinde ExtJS ve Coolite nedir, kullanım alanları nelerdir, nasıl
kullanırız, Sıkça Sorulan(bilecek) Sorular başlıklarının altına dallanarak
gelişicek konularımız. Şuan kafamda oluşan plana göre, yazı dizisini yine geniş
bir video dizisi seyredicek.Isola hakkında da yazmak isterdim; fakat Java
konusunda okadar bilgiye sahip değilim ne yazık ki.

Yukarıdaki bölüm sadece giriş paragraflarından oluşuyor. Artık derinlere
inmenin zamanı geldi.

Not (1) : JavaScript ve Ajax'ı bildiğinizi varsayarak başlıyorum. Eğer onları
da yazmaya kalkarsam çok ama çok uzun bir yazı dizisi olur. Bu kavramlar
hakkında bilgisi olmayan arkadaşlara Daron
Yöndem
'in ASP.NET AJAX ve ASP.NET 3.5 AJAX adlı kitaplarını öneririm.

Bölüm 1 : ExtJS'e Giriş

Kısaca tanımlamak gerekirse ExtJS, çoklu browser destekli, güçlü kullanıcı
arayüzleri programlamanıza yardımcı, Ajax işlemlerini yapmanızı çok
kolaylaştıran, Open Source ve Ticari lisansları olan bir JavaScript kütüphanesi.

Lisanslamalarına da dikkat çektim; çünkü eğer ticari bir ürün yaratmak için
kullanmak istiyorsanız Ext kütüphanesini, ücretini verip almanız gerekiyor.

Çoklu Browser(cross-browser) destekli dedim; peki hangi browserları
destekliyor diye bakıcak olursak,

  • Internet Explorer 6 ve sonraki sürümler
  • Firefox 1.5 ve sonraki sürümler
  • Safari 3 ve sonraki sürümler
  • Opera 9 ve sonraki sürümler

Bu maddelere ek olarak Google Chrome'da da güzel bir performans
sunuyor.(Bizzat kendim denedim)

Çoklu Browser desteği özelliğini test ettiğimde (Puanlar 5 üzerindendir) :

  • Internet Explorer 8 'de 4 puanlık
  • Mozilla Firefox 3.5 'da 5 puanlık
  • Google Chrome 'da 4 puanlık

randıman aldım.Diğer browserları deneme şansım olmadı.Eğer siz denerseniz
sonuçları benimle de paylaşın lütfen.

Arayüz programlama konusunda ise gerçekten çok geniş bir yelpaze sunuyor bize
ExtJS kütüphanesi. Benim Ext'e, tabir yerindeyse, aşık olmamı sağlayan bir örnek
vereyim size :
Desktop
örneği.

İşte Desktop

Bu görüntüyü elde etmek için yapmanız gerekenleri, yazmanız gereken JS
kodlarını, bir sonraki makalemizde inceleyeceğiz.

Tanımda bahsettiğim bir başka nokta ise AJAX işlemlerini kolaylaştırdığıydı.
Aşağıdaki örneklerden de anlaşılacağı üzere, jQuery ve Ext deki AJAX işlemleri
çok da farklı değil. Hangi sayfaya istekte bulunacağını, işlem tamamlandığında
hangi fonksiyona gideceğini, işlem tamamlanamadığında hangi fonksiyona
gideceğini, varsa parametreleri tanımlayıp işlemi bitiriyoruz.

 [ExtJS]

Ext.Ajax.request({

          
url: 'sayfa.aspx',

          
success: fonksiyon1,

          
failure: fonksiyon2,

          
params: { ID: '1' }

});

 

 [jQuery]

 

       
$.ajax({

           
type: 'GET',

           
url: 'sayfa.aspx',

           
success: fonksiyon1

           
},

           
error: fonksiyon2

           
}

        );

 

Böylece bu uzun soluklu yazı dizimizin ilk bölümünün sonuna geldik. 2.Bölüm '
de UI tasarlarken ne yapmalıyız, ExtJS 'nin bize sunduğu UI objelerini
kullanarak neler yapabiliriz konuları üzerinde duruyor olacağız.

Temelde ExtJS kullanımını konuşucağız bir süre. Bu konulara hakim olduktan
JS kodları arasında boğulmadan Coolite ile .NET tarafında ne sihirbazlıklar
yapabiliceğimizi göreceğiz.

Merak etmeyin arayı soğutmayacağım, bu aralar müsaitim bol bol yazarım.

Bir sonraki bölümde görüşmek üzere.

 

Bu makalemde " ExtJS ve Coolite ne ola ki? " yazı dizisinin devamı olarak
ExtJS objelerinden "Grid" objesini nasıl kullanırız?, datada grid üzerinden
nasıl değişiklik yaparız? ana başlıkları altında bir çok kavrama değineceğim. 

Lafa başlamadan önce iki makale arasında bu kadar ara verdiğim için herkesten
özür dilerim. Okul ve iş yoğunluğu arasında boğulmakla uğraştığımdan makaleye
zaman ayıramadım. Bu aksaklığı telafi etmeye çalışacağıma söz veriyorum.

ExtJS' nin genel hatlarının üstünden geçmiştik. Şimdi ise birçok konuyu
harmanlayan bir senaryo üzerinden devam edelim. Amacımız, ExtJS objelerini
kullanarak hem güzel bir UI elde etmek, hem de nasıl data işlemleri yaparız
sorusunun cevabını aramak olacak. Senaryomuz da şu olsun : Biz bir meyve
üreticisiyiz. Ürettiğimiz meyveleri görmek, kayıtlarının üstünde değişiklik
yapmak ve onları satmak istiyoruz.

Senaryomuzu hayata geçirmeye başlamadan önce yapmamız gereken bazı önemli
şeyler var :

  1. ExtJS' nin güncel kütüphanesini (versiyon 3.1.1)

    indirmek
  2. HTML ve JavaScript kodlarımızı düzenlemek için uygun bir editör seçmek:
    Visual Studio ortamını kullanabilirsiniz.

Bu iki öngereksinimi de gerçekleştirdikten sonra projemize başlamamız için
önümüzde bir engel kalmıyor. Visual Studio' da bir "Web Site" oluşturarak
başlayabiliriz.

Projeyi oluşturduktan sonra indirdiğimiz ExtJS kütüphanesinden bir kaç
dosyayı projemize dahil etmeliyiz. Bunun için site içinde "extLib" adlı bir
dosya oluşturduktan sonra ExtJS kütüphanesinin kök dosyasından yola çıkarak,

  1. ext-all.js javascript dosyasını,
  2. "adaptor" klasörünü,
  3. "resources" klasörünü,
  4. "examples/ux" klasörünü,
  5. "examples/shared" klasörünü,
  6. "examples/grid/grid-example.css" stil dosyasını

oluşturduğumuz klasöre kopyalayalım. Neden bu dosyaları ve klasörleri
kopyaladığımıza gelicek olursak; içlerinde bize lazım olan temel ext javascript
dosyaları ve css dosyaları bulunuyor. Bu yüzden bu öğeleri projemize dahil
etmemiz gerekiyor.

İşlemlerden sonra oluşması gereken ekran görüntüsü

Kodlama kısmına yavaş yavaş geçerken neler yapmamız gerektiğine adım adım
bakarsak,

1) <head></head>  tagları arasına gerekli olan referanlarımızı eklemeliyiz. Bahsettiğim
javascript ve css referansları aşağıdaki gibidir.

   
<!–JS dosyaları–>

    <script
type="text/javascript"
src="extLib/adapter/ext/ext-base.js"></script>

    <script
type="text/javascript"
src="extLib/ext-all.js"></script>

    <script
type="text/javascript"
src="extLib/ux/RowEditor.js"></script>

 

   
<!–CSS dosyaları–>

    <link
rel="stylesheet"
type="text/css"
href="extLib/resources/css/ext-all.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/grid-examples.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/shared/examples.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/ux/css/RowEditor.css"
/>

 

    <style
type="text/css">

       
.icon-user-add {

           
background-image:
url(extLib/shared/icons/fam/user_add.gif)
!important;

        }

       
.icon-user-delete {

           
background-image:
url(extLib/shared/icons/fam/user_delete.gif)
!important;

        }       

    </style>

 

Bu noktada "ext-base.js" ve "ext-all.js" dosyalarının bizim için vazgeçilmez
olduğunu vurgulamakta fayda var. Her ne yapıyor olursak olalım, bu iki dosyayı
mutlaka referans almalıyız. Onların yanında kullandığımız ekstra özellikleri
içeren JavaScript dosyalarını da projeye dahil etmeliyiz. Örneğin, benim
örneğimde RowEditor kullanıldığından, aynı isimli JavaScript dosyasını da
projeye dahil ettim.

2) Eklememiz gereken bütün dosyaları
projemize referans aldıktan sonra, bütün işlemlerimizi yapacağımız JavaScript
kodumuzu oluşturmaya geçebiliriz.

Uygulamada kullanacağımız dataların şablonunu hazırlamalıyız. 

         
var Urun = Ext.data.Record.create([{

             
name: 'ad',

             
type: 'string'

         
}, {

             
name: 'tip',

             
type: 'string'

         
}, {

             
name: 'uretim',

             
type: 'date',

             
dateFormat: 'n/j/Y'

         
}, {

             
name: 'adet',

             
type: 'integer'

         
}, {

             
name: 'fiyat',

             
type: 'integer'}]);

Yukarıda da gördüğünüz gibi Ext.data.Record.create metodunu kullanarak; alan
adları ad, tip, uretim, adet ve fiyat olan bir tablo oluşturduk ve adına da
"Urun" dedik.

Doğal olarak bu şablonu kullanarak data oluşturmamız gerekmektedir. Ben bu
örnek için istemci-taraflı data oluşturup oynamaları o datanın üstünde yaparız
diye düşündüm. Bir sonraki makalemde sunucu-taraflı dataları çekip istemci
tarafında oynamaları yapıp değişikliklerin kaydedilmesi için yine sunucu
tarafına göndermeyi nasıl yapıcağımıza göz atacağız. Dediğim gibi kayıt
oluşturmak için bir metoda ihtiyacımız var.

         var
genData = function() {

            
     var data = [];

                 
var s = new
Date(2007, 0, 1);

                 
var now = new
Date(), i = -1;

                 
while (s.getTime() < now.getTime()) {

                     
var ecount = Ext.ux.getRandomInt(0, 1);

                     
for (var
i = 0; i < ecount; i++) {

                         
var name = Ext.ux.generateName();

                         
data.push({

                             
uretim: s.clearTime(true).add(Date.DAY,
Ext.ux.getRandomInt(0, 27)),

                             
ad: name,

                             
tip: 'Meyve',

                             
adet: Ext.ux.getRandomInt(10, 100),

                             
fiyat: Ext.ux.getRandomInt(10, 100)

                         
});

                     
}

                     
s = s.add(Date.MONTH, 1);

                 
}

                 
return data;

             
}

Bu fonksiyon bizim işimizi görür. Nasıl işlediğine biraz göz atalım : 2007
den başlayarak günümüze kadar düzgün devam etmeyen bi döngü var. Her bir turda
oluşturduğumuz diziye, alan değerleri gelişi güzel olan yeni bir kayıt
ekliyoruz. Bu sayede yaklaşık on yedi adet, birbirinden farklı kayıt elde etmiş
oluyoruz.

 Bir sonraki adımda oluşan bu kayıtları grid objemize nasıl bağlayacağız
sorunu ortaya çıkıyor. Tabii ki imdadımıza yetişen bir Ext objesi var :
Store.
Store objesi, bizim datalarımızı, üstünde yapılan
değişiklikleri, son halini kısaca herşeyi barındıran, çok özel bir nesne.
Kullanımı ise çok kolay.

             
var store = new
Ext.data.GroupingStore({

                 
reader: new Ext.data.JsonReader({ fields:
Urun }),

                 
//datayı nereden alıcagını belirttik.

                 
data: genData(),

                 
sortInfo: { field: 'uretim', direction:
'ASC' }

             
});

Store nesnesi kayıtları json halinde saklıyor. Bu yüzden hangi tip kayıtları
okuyacağını belirtmemiz gerekiyor. Ayrıca bir çok başka özelliği daha var.
Yukarıda örnek olarak sortInfo özelliğine hangi alanı ne tipte
sıralayacağını belirtmişim. API dökümantasyonunu incelerseniz, bu güzel nesnenin
bir çok farklı özelliğe sahip olduğunu göreceksiniz.

Sıra geldi Grid nesnemizi yaratmaya.

//gridimizi yaratalım

             
var grid = new
Ext.grid.GridPanel({

                 
//grid oluştururken 'store' degerini vermeyi
unutmayınız.

                 
store: store,

                 
width: 600,

                 
region: 'center',

                 
margins: '0 5 5 5',

                 
autoExpandColumn: 'ad',

                 
plugins: [editor],

                 
view: new Ext.grid.GroupingView({

                     
markDirty: false

                 
}),

                 
// 'topbar' daki butonlarımızı oluşturuyoruz.

                 
tbar: [{

                     
iconCls: 'icon-user-add',

                     
text: 'Urun Ekle',

                     
handler: function() {

                         
var e = new
Urun({

                             
ad: 'Meyve Adi',

                             
tip: 'Meyve',

                             
uretim: (new Date()).clearTime(),

                             
adet: 1,

                             
fiyat: 10

                         
});

                         
editor.stopEditing();

                         
store.insert(0, e);

                         
grid.getView().refresh();

                         
grid.getSelectionModel().selectRow(0);

                         
editor.startEditing(0);

                     
}

                 
}, {

                     
ref: '../removeBtn',

                     
iconCls: 'icon-user-delete',

                     
text: 'Urun Sil',

                     
disabled: true,

                     
handler: function() {

                         
editor.stopEditing();

                         
var s =
grid.getSelectionModel().getSelections();

                         
for (var
i = 0, r; r = s[i]; i++) {

                             
store.remove(r);

                         
}

                     
}

                 
}, {

                     
ref: '../removeBtn',

                     
iconCls: 'icon-user-delete',

                     
text: 'Urun Sat',

                     
disabled: true,

                     
handler: function() {

                         
editor.stopEditing();

                         
var s =
grid.getSelectionModel().getSelections();

                         
for (var
i = 0, r; r = s[i]; i++) {

                             
if (r.data['adet']
== 1) {

                                 
para = para + r.data['fiyat'];

                                 
store.remove(r);

                                 
Ext.MessageBox.alert('Satis',
'Satis Islemi tamamlandi. Urun kalmadi!Suan '
+ para + ' kadar paraniz var.');

                             
}

                             
else {

                                 
para = para + r.data['fiyat'];

                                 
r.set("adet",
r.data['adet'] – 1);

                                 
r.commit();

                                 
Ext.MessageBox.alert('Satis',
'Satis Islemi tamamlandi. Suan ' + para
+ ' kadar paraniz var.');

                             
}

                         
}

                     
}

}],

                     
//Kolonlarımızı özellestirelim.

                     
columns: [

       
new Ext.grid.RowNumberer(),

        {

           
id: 'ad',

           
header: 'Meyve Adi',

           
dataIndex: 'ad',

           
width: 220,

           
sortable: true,

           
editor: {

               
xtype: 'textfield',

               
allowBlank: false

           
}

        }, {

           
header: 'Tip',

           
dataIndex: 'tip',

           
width: 150,

           
sortable: true,

           
editor: {

               
xtype: 'textfield',

               
blankText: "Bos Birakma!",

               
allowBlank: false

           
}

        }, {

           
xtype: 'datecolumn',

           
header: 'Uretim Tarihi',

           
dataIndex: 'uretim',

           
format: 'm/d/Y',

           
width: 100,

           
sortable: true,

           
groupRenderer: Ext.util.Format.dateRenderer('M
y'
),

           
editor: {

               
xtype: 'datefield',

               
allowBlank: false,

               
blankText: "Bos Birakma!",

               
maxValue: (new Date()).format('m/d/Y')

           
}

        },

        {

           
header: 'Adet',

           
dataIndex: 'adet',

           
minValue: 1,

           
width: 50,

           
sortable: true,

           
editor: {

               
xtype: 'numberfield',

               
blankText: "Bos Birakma!",

               
allowBlank: false

           
}

        },

        {

           
header: 'Fiyat',

           
dataIndex: 'fiyat',

           
minValue: 1,

           
width: 50,

           
sortable: true,

           
editor: {

               
xtype: 'numberfield',

               
allowBlank: false

           
}

}]

                 
});

Öncellikle Grid' imizin store özelliğine değer atamamız gerekiyor.
Bu değer tabii ki bizim oluşturduğumuz store nesnesinin adı olacak.

Bu noktada size Grid nesnesinin Top Bar özelliğinden bahsetmek
istiyorum. Top Bar bize grid üzerine buton koyma imkanı sağlayan bir
bölüm. Bu sayede grid üzerinde işlem yaparken kullanacağımız butonları buraya
tanımlayabiliyoruz. Yukarıda da görebileceğiniz üzere Top Bar' a 3 tane
buton tanımladık. Bu butonların her birinin text, disabled, iconCls
gibi özellikleri var. Fakat handler özelliği diğer
hepsinden daha çekici bana kalırsa. Bu özelliğe istersek işlem yapıcak
foksiyonun sadece ismini tanımlarız, istersek örnekteki gibi fonksiyonu oraya
yazarız.

Son olarak sıra geldi grid üzerindeki kolonları tanımlamaya. Kolonları
özelleştirme noktasında da Ext bize baya bir esneklik sağlıyor. Başlığından,
editörünün kısıtlanmasına kadar örnekte de görebileceğiniz bir çok
özelleştirmede bulunabiliyoruz.

Böylece kodumuzdaki önemli noktaların ve kavramların üstünden geçmiş olduk.
Kodun tamamı aşağıdaki gibidir.

[Default.aspx]

<%@
Page
Language
="C#"
AutoEventWireup="true"
CodeFile="Default.aspx.cs"
Inherits="_Default"
%>

 

<!DOCTYPE
html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html
xmlns="http://www.w3.org/1999/xhtml">

<head
runat="server">

    <title></title>

   
<!–JS dosyaları–>

    <script
type="text/javascript"
src="extLib/adapter/ext/ext-base.js"></script>

    <script
type="text/javascript"
src="extLib/ext-all.js"></script>

    <script
type="text/javascript"
src="extLib/ux/RowEditor.js"></script>

 

   
<!–CSS dosyaları–>

    <link
rel="stylesheet"
type="text/css"
href="extLib/resources/css/ext-all.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/grid-examples.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/shared/examples.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/ux/css/RowEditor.css"
/>

 

    <style
type="text/css">

       
.icon-user-add {

           
background-image:
url(extLib/shared/icons/fam/user_add.gif)
!important;

        }

       
.icon-user-delete {

           
background-image:
url(extLib/shared/icons/fam/user_delete.gif)
!important;

        }       

    </style>

 

    <script
type="text/javascript">

     
// gelişi güzel isim oluşturma

      (function()
{

         
//Birkaç meyve adı tanımlaması yaptık

         
var meyveler = ['Elma',
'Armut',
'Muz',
'Kavun',
'Karpuz',
'Portakal',
'Nar',
'Mandalina',
'Yeni Dunya',
'Ananas'];

         
var firstLen = meyveler.length;

 

         
//adından da anlaşılacağı üzere gelişi güzel
sayı değerleri oluşturmamıza

         
//yarayan bir fonksiyon

         
Ext.ux.getRandomInt = function(min,
max) {

             
return Math.floor(Math.random() * (max
- min + 1)) + min;

         
}

 

         
//yine gelişi güzel bir şekilde meyve
isimleri oluşturacağız.

         
Ext.ux.generateName = function() {

             
var name =
meyveler[Ext.ux.getRandomInt(0, firstLen - 1)] +
" Meyvesi " +
Ext.ux.getRandomInt(0, 10);

             
//dataların 'ad' degerlerini identity olarak
da kullandığımız için bir kez

             
//oluşturduğumuz ismi tekrar
oluşturmamalıyız

             
if
(Ext.ux.generateName.usedNames[name]) {

                 
return Ext.ux.generateName();

             
}

             
Ext.ux.generateName.usedNames[name] = true;

             
return name;

         
}

         
Ext.ux.generateName.usedNames = {};

 

      })();

 

      Ext.onReady(function()
{

         
var para = 0;

 

         
//Urun adlı kayıt şablonunun alan adlarını
tanıtalım.

         
var Urun = Ext.data.Record.create([{

             
name: 'ad',

             
type: 'string'

         
}, {

             
name: 'tip',

             
type: 'string'

         
}, {

             
name: 'uretim',

             
type: 'date',

             
dateFormat: 'n/j/Y'

         
}, {

             
name: 'adet',

             
type: 'integer'

         
}, {

             
name: 'fiyat',

             
type: 'integer'}]);

             
//

             
//Kullanıcağımız dataları oluşturalım.

             
var genData =
function() {

                 
var data = [];

                 
var s = new
Date(2007, 0, 1);

                 
var now =
new
Date(), i = -1;

                 
while (s.getTime() < now.getTime()) {

                     
var ecount = Ext.ux.getRandomInt(0,
1);

                     
for (var
i = 0; i < ecount; i++) {

                         
var name = Ext.ux.generateName();

                         
data.push({

                             
uretim: s.clearTime(true).add(Date.DAY,
Ext.ux.getRandomInt(0, 27)),

                             
ad: name,

                             
tip: 'Meyve',

                             
adet: Ext.ux.getRandomInt(10, 100),

                             
fiyat: Ext.ux.getRandomInt(10, 100)

                         
});

                     
}

                     
s = s.add(Date.MONTH, 1);

                 
}

                 
return data;

             
}

             
//

             
//Json tipindeki datalarımızı tutacağımız
store objemiz

             
var store =
new
Ext.data.GroupingStore({

                 
reader: new Ext.data.JsonReader({
fields: Urun }),

                 
//datayı nereden alıcagını belirttik.

                 
data: genData(),

                 
sortInfo: { field: 'uretim',
direction: 'ASC' }

             
});

 

             
//Editor butonlarımızın etiketlerin
dilediğimiz gibi değiştirebiliriz

             
var editor =
new Ext.ux.grid.RowEditor({

                 
saveText: 'Kaydet',

                 
cancelText: 'Iptal'

             
});

 

             
//

             
//gridimizi yaratalım

             
var grid =
new
Ext.grid.GridPanel({

                 
//grid oluştururken 'store' degerini vermeyi
unutmayınız.

                 
store: store,

                 
width: 600,

                 
region: 'center',

                 
margins: '0 5 5 5',

                 
autoExpandColumn: 'ad',

                 
plugins: [editor],

                 
view: new Ext.grid.GroupingView({

                     
markDirty: false

                 
}),

                 
// 'topbar' daki butonlarımızı
oluşturuyoruz.

                 
tbar: [{

                     
iconCls: 'icon-user-add',

                     
text: 'Urun Ekle',

                     
handler: function() {

                         
var e = new
Urun({

                             
ad: 'Meyve Adi',

                             
tip: 'Meyve',

                             
uretim: (new Date()).clearTime(),

                             
adet: 1,

                             
fiyat: 10

                         
});

                         
editor.stopEditing();

                         
store.insert(0, e);

                         
grid.getView().refresh();

                         
grid.getSelectionModel().selectRow(0);

                         
editor.startEditing(0);

                     
}

                 
}, {

                     
ref: '../removeBtn',

                     
iconCls: 'icon-user-delete',

                     
text: 'Urun Sil',

                     
disabled: true,

                     
handler: function() {

                         
editor.stopEditing();

                         
var s =
grid.getSelectionModel().getSelections();

                         
for (var
i = 0, r; r = s[i]; i++) {

                             
store.remove(r);

                         
}

                     
}

                 
}, {

                     
ref: '../removeBtn',

                     
iconCls: 'icon-user-delete',

                     
text: 'Urun Sat',

                     
disabled: true,

                     
handler: function() {

                         
editor.stopEditing();

                         
var s =
grid.getSelectionModel().getSelections();

                         
for (var
i = 0, r; r = s[i]; i++) {

                             
if (r.data['adet']
== 1) {

                                 
para = para + r.data['fiyat'];

                                 
store.remove(r);

                                 
Ext.MessageBox.alert('Satis',
'Satis Islemi tamamlandi. Urun
kalmadi!Suan '
+ para + ' kadar
paraniz var.'
);

                             
}

                             
else {

                                 
para = para + r.data['fiyat'];

                                 
r.set("adet",
r.data['adet'] – 1);

                                 
r.commit();

                                 
Ext.MessageBox.alert('Satis',
'Satis Islemi tamamlandi. Suan ' +
para + ' kadar paraniz var.');

                             
}

                         
}

                     
}

}],

                     
//Kolonlarımızı özellestirelim.

                     
columns: [

       
new Ext.grid.RowNumberer(),

        {

           
id: 'ad',

           
header: 'Meyve Adi',

           
dataIndex: 'ad',

           
width: 220,

           
sortable: true,

           
editor: {

               
xtype: 'textfield',

               
allowBlank: false

           
}

        }, {

           
header: 'Tip',

           
dataIndex: 'tip',

           
width: 150,

           
sortable: true,

           
editor: {

               
xtype: 'textfield',

               
blankText: "Bos Birakma!",

               
allowBlank: false

           
}

        }, {

           
xtype: 'datecolumn',

           
header: 'Uretim Tarihi',

           
dataIndex: 'uretim',

           
format: 'm/d/Y',

           
width: 100,

           
sortable: true,

           
groupRenderer: Ext.util.Format.dateRenderer('M
y'
),

           
editor: {

               
xtype: 'datefield',

               
allowBlank: false,

               
blankText: "Bos Birakma!",

               
maxValue: (new Date()).format('m/d/Y')

           
}

        },

        {

           
header: 'Adet',

           
dataIndex: 'adet',

           
minValue: 1,

           
width: 50,

           
sortable: true,

           
editor: {

               
xtype: 'numberfield',

               
blankText: "Bos Birakma!",

               
allowBlank: false

           
}

        },

        {

           
header: 'Fiyat',

           
dataIndex: 'fiyat',

           
minValue: 1,

           
width: 50,

           
sortable: true,

           
editor: {

               
xtype: 'numberfield',

               
allowBlank: false

           
}

}]

                 
});

                 
//

                 
//

                 
var layout =
new Ext.Panel({

                     
title: 'Meyveler',

                     
layout: 'border',

                     
layoutConfig: {

                         
columns: 1

                     
},

                     
width: 600,

                     
height: 600,

                     
items: [grid]

                 
});

                 
layout.render(Ext.getBody());

 

                 
grid.getSelectionModel().on('selectionchange',
function(sm) {

                     
grid.removeBtn.setDisabled(sm.getCount() < 1);

                 
});

             
});

  </script>

 

    <link
rel="stylesheet"
type="text/css"
href="extLib/resources/css/ext-all.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/grid-examples.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/shared/examples.css"
/>

    <link
rel="stylesheet"
type="text/css"
href="extLib/ux/css/RowEditor.css"
/>

 

 

 

</head>

<body>

    <form
id="form1"
runat="server">

    <div>

    </div>

    </form>

</body>

</html>

 

Tüm bu işlemler sonrasında aşağıdaki gibi bir görüntü
elde edeceğiz.

 

 

 

Böylece bu makalemizin de sonuna gelmiş olduk. Eğer
örnekteki herhangi bir yeri anlamadığınızı düşünüyorsanız bana mail aracılığıyla
ulaşabilirsiniz.

 

Serinin devamında sunucu-taraflı data işlemlerine
değiniyor olacağız, yani işin içine biraz AJAX girecek.

 

Herkese iyi kodlamalar.


MetaData üzerinden öznitelik ataması yapılarak doğrulama, biçimleme ve özel alan şanlonlarını(FieldTemplates) nasıl kullanacağımızdan bahsetmiştik.

Bu makale özel özniteliklerin ve alan şablonlarının geliştirilmesi konusunu içerecektir. Bu nedenle FileUpload kontrolünün kullanımı ve alan şablonlarının çalışma mantığıyla özel özniteliklerin kullanımı hakkında bilgi sahibi olacağız.

Önceki makalemde bahsettiğim gibi ASP.NET Dynamic Data Web Site ile FileUpload işlemlerini klasik yöntemlerle kullanamıyoruz.

 
ASP.NET Dynamic Data Web Sitesinde Ajax Toolkit ile birlikte kullanıyorsanız ve FileUpload bileşeniniz UpdatePanel içerisinde yer alıyorsa ScriptManager nesnesinin EnablePartialRendering özelliğini false olarak atamanız gerekiyor.

Kodlamaya başlamadan önce yapılması gereken işlemleri özetlemenin faydalı olduğunu düşünüyorum. Kodlama detayları ilgili sınıfların içinde yer almaktadır.

  1. Zorunlu olmasa da dosyanın sunucuya yükleme işleminin gerçekleştirileceği yardımcı bir sınıf.
  2. Her bir dosya yükleme alanı için dosya türü, boyutu vb. bildirimleri yapmak için öznitelik tabanlı bir sınıf
  3. Dosya yükleme alanlarının ekleme ve güncelleme ekranı için FileUpload kontrolü listeleme ve detay sayfaları için ise dosya türüne göre yüklenen dosyaya uygun simge, önizleme vb. için alan şablonlarının(FieldTemplate) gerekli hazırlanması.
  4. İşlevin kazandırılacağı alanlara gerekli öznitelik tanımlamasının yapılması

Temel düzeyde dosya yükleme işlemini gerçekleştirmek üzere aşağıdaki sınıfı kullanacağız

FileUploadUtil.cs

using System;
using System.Web;
using System.IO;
using Eposta.Core.CustomAttributes;
using Eposta.Core.Extentions;
using System.Text.RegularExpressions;

namespace Eposta.Core.Utils
{
    /// <summary>
    /// Ömer Faruk ZORLU
    /// </summary>
    public class FileUploadUtil
    {
        private string _fileName;

        /// <summary>
        /// Dosyanın yükleneceği fiziksel konum
        /// Örnek kullanım: HttpContext.Current.Server.MapPath("~/Uploads/")
        /// </summary>
        public string UploadDictionaryPath { get; set; }

        /// <summary>
        /// Yükleme işlemi başarısız olmuşsa bu değer
        /// üzerinden hata mesajı okunabilir
        /// </summary>
        public string ErrorMessage { get; private set; }

        /// <summary>
        /// Değer atama işleminin ardından güvenlik, tekillik gibi
        /// nedenler gereği isim değiştirilmelidir.
        /// </summary>
        public string FileName
        {
            get { return _fileName; }
            set
            {
                string strExtention = Path.GetExtension(value);

                // ToSEFString methodu gönderilen string değeri arama
                // motoru dostu karakterler ile değiştirir
                //
                // RandomHelper sınıfı doğru rasgele karakterler ve
                // sayılar üretmek için kullanılıyor
                // Bağlantı: http://tinyurl.com/y8of6sn
                _fileName = Path.GetFileNameWithoutExtension(value).ToSEFString()
                + RandomHelper.RandomString(10, true)
                + strExtention;
            }
        }

        /// <summary>
        /// ctor
        /// </summary>
        public FileUploadUtil()
        {
            _fileName = string.Empty;
        }

        /// <summary>
        /// Dosya yükleme işleminin tetiklenmesi için bu method çağırılmalıdır.
        /// </summary>
        /// <param name="postedFile">
        /// Bu değişken klasik html input alanları tarafından post edilen
        /// verilerinde methodu kullanabilmeleri için bu tipte tanımlanmıştır.
        /// FileUpload kontrolü kullanılacaksa PostedFile özelliği gönderilebilir.
        /// </param>
        /// <param name="fuAttribute">
        /// Dosya yükleme işleminin gerçekleşmesi ile ilgili bilgiler içeren sınıftır
        /// Attribute sınıfından türetilmiştir. MetaColumn ile kullanılacaksa ilgili
        /// alan üzerinde tanımlı özniteliğin gönderilmesi yeterlidir.
        /// </param>
        /// <returns></returns>
        public bool UploadFile(HttpPostedFile postedFile, FileUploadAttribute fuAttribute)
        {
            #region Checks
            if (postedFile.ContentLength <= 0)
            {
                this.ErrorMessage = "Veri akışı bulunamadı";
                return false;
            }

            // Maksimum dosya boyutu öznitelikte atanan değere göre kontrol ediliyor.
            long FileSize = postedFile.ContentLength;
            if (FileSize > (fuAttribute.MaximumFileSize * 1024000))
            {
                this.ErrorMessage = string.Format("Maksimum dosya boyutu izin verilenden fazla olamaz. İzin verilen maksimum dosya boyutu: {0}", fuAttribute.MaximumFileSize);
                return false;
            }

            // Dosya uzantısı öznitelikte atanan değere göre kontrol ediliyor.
            // İçerik türüne(MIME) görede kontrol edilebilir.
            if (!Regex.IsMatch(Path.GetExtension(_fileName), fuAttribute.AllowedFileFormats, RegexOptions.IgnoreCase))
            {
                this.ErrorMessage = string.Format("Dosya türüne izin verilmiyor. İzin verilen dosya formatları: {0}", fuAttribute.AllowedFileFormats);
                return false;
            }
            #endregion

            // Klasör yoksa oluştur.
            DirectoryInfo DInfo = new DirectoryInfo(this.UploadDictionaryPath);
            if (!DInfo.Exists)
                DInfo.Create();

            #region WriteStreamToFile
            // Dosyayı kaydet
            string strFullFileName = this.UploadDictionaryPath + this._fileName;
            postedFile.SaveAs(strFullFileName);
            #endregion

            return true;
        }
    }
}

Yukarıdaki sınıf içinde kullanılan FileUploadAttribute sınıfını dosya yükleme işleminin gerçekleşmesini istediğimiz kolon için gerekli bildirimlerin yapılması için kullanacağız . Bu sınıfın kodlaması aşağıdaki gibidir.

using System;

namespace Eposta.Core.CustomAttributes
{
    /// <summary>
    /// Ömer Faruk ZORLU
    /// </summary>
    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
    public class FileUploadAttribute : Attribute
    {
        /// <summary>
        /// Yüklenecek dosyanın maksimum boyutunun megabyte karşılığıdır.
        /// </summary>
        public short MaximumFileSize { get; set; }

        /// <summary>
        /// Bu özellik adının kontrol edilmesi için kullanılır.
        /// Kontrol işlemi RegularExpressions(Regex) sınıfı ile
        /// gerçekleştirilir.
        ///
        /// Örnek Kullanım: “jpg|gif|png|JPG|GIF|PNG”
        /// </summary>
        public string AllowedFileFormats { get; set; }

        /// <summary>
        /// Yükleme işleminin gerçekleştirileceği klasörün fiziksel
        /// yolunu saklar.
        ///
        /// Örnek Kullanım: HttpContext.Current.Server.MapPath(“~/Uploads/”)
        /// </summary>
        public string UploadDictionaryPath { get; set; }
    }
}

Buraya kadarki kodlamalarla iş katmanı için yükleme işini üstlenecek sınıfların kodlamasını tamamlamış olduk. Sırada bu katmanı istediğimiz kolon üzerinde kullanabilmek için gerekli alan şablonunu tasarlama işi var.  Daha önceki makalelerde belirttiğim gibi güncelleme, ekleme ve listeleme, detay sayfa şablonları için iki adet alan şablonu hazırlanmalıdır. Ekleme ve günnceleme için gerekli alan şablonunun kodları aşağıdaki gibidir.

MyFileUpload_Edit.ascx

<%@ Control Language="C#" CodeFile="MyUpload_Edit.ascx.cs" Inherits="MyUpload_Edit" %>
<asp:Label ID="Label1" runat="server" Text='<%# FieldValueEditString %>'></asp:Label><br />
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:CustomValidator ID="CustomValidator1" runat="server"
    ErrorMessage="CustomValidator"></asp:CustomValidator>

MyFileUpload_Edit.ascx.cs

using System;
using System.Collections.Specialized;
using System.Web.UI;
using System.Linq;
using Eposta.Core.CustomAttributes;
using Eposta.Core.Utils;

public partial class MyUpload_Edit : System.Web.DynamicData.FieldTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected override void OnDataBinding(EventArgs e)
    {
        base.OnDataBinding(e);
    }

    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
        // DataControl nesnesi olarak Label1 atandığı için
        // dosya yüklemenmesede varsayılan olarak zaten kayıtlı olan
        // veri dönüş değerinde kullanılmak üzere atanıyor
        dictionary[Column.Name] = ConvertEditedValue(Label1.Text);

        // Bu kolon üzerinde atanması zorunlu olan FileUploadAttribute
        // özniteliği alınıyor.
        var fuAttribute = base.Column.Attributes.OfType<FileUploadAttribute>().FirstOrDefault();
        // FileUploadAttribute ataması yoksa dön
        if (fuAttribute == null)
            return;

        // Dosya seçilmişse
        if (FileUpload1.HasFile)
        {
            try
            {
                FileUploadUtil fuUtil = new FileUploadUtil();
                // Atama işleminin ardından dosyaya yeni isim atanıyor.
                fuUtil.FileName = FileUpload1.FileName;
                fuUtil.UploadDictionaryPath = fuAttribute.UploadDictionaryPath;

                // Dosyayı yükle ve yeni dosya adını dönüş değeri olarak ata.
                // Hata kontrolüne karşı ilgili değişken(string ErrorMessage)
                // kontrol edilebilir.
                if (fuUtil.UploadFile(FileUpload1.PostedFile, fuAttribute))
                    dictionary[Column.Name] = fuUtil.FileName;
            }
            catch (Exception Ex)
            {
                // Denetlenmemiş herhangi bir hata oluşursa sayfanın tamamen
                // hata vermesi yerine hata mesajını hata özetlerinde ve atama
                // işleminin yapıldığı alanın yanında görünmesi için CustomValidator1
                // nesnesinden yararlanılıyor.
                CustomValidator1.IsValid = false;
                CustomValidator1.ErrorMessage = Ex.Message;
            }
        }
    }

    public override Control DataControl
    {
        get
        {
            return Label1;
        }
    }
}

Listeleme ve detay sayfa şablonlarında kullanılacak alan şablonu kodları aşağıdaki gibidir. Yüklenen dosyaların(ilgili verilerin) yalnızca    resim dosyası olduğu öngörülerek yazılmıştır. Dosya tipi yada türüne göre özelleştirilmiş görüntüleme tekniği kullanılabilir.

MyUpload.ascx.cs

using System;
using System.Web.UI;

public partial class MyUpload : System.Web.DynamicData.FieldTemplateUserControl
{
    public override Control DataControl
    {
        get
        {
            return imgThumbnail;
        }
    }

    public string GetSrcUrl()
    {
        // Veri boş ya da null ise NoImage.gif dönder
        if (String.IsNullOrEmpty(FieldValueString)) return "NoImage.gif";

        // Veri http, ftp vb herhangi bir protokolü kullanıyor ise
        // olduğu gibi değilse upload klasörünü kök dizin alarak dönder
        if (-1 < FieldValueString.IndexOf("://"))
            return FieldValueString;
        else
            return "~/uploads/" + FieldValueString;
    }
} 

Dynamic Data’nın en sevdiğim kısımı tabiki MetaData üzerinde yapılan tanımlamalardır. O kadar çok kod yazmak gerekiyorki daha ne yapalım birde diyenleri duyar gibiyim.

Dynamic Data ile yapılan her geliştirme tasarruf niteliği taşır.

Geliştirdiğimiz dosya yükleme aracı için klasik kodlama kullansaydık benzer kodları kullanmak istediğimiz sayfalarda(aynı sayfada pek çok kere de olabilir) harcanan efor göz önüne alınmalıdır. Yapılan geliştirme bir sonraki proje için yatırımdır. Ayrıca geriye dönük olarak yapılan projelerde kullan/a/mamak için bir neden söz konusu değildir.

Şimdi en zevkli kısıma gelelim. Bundan böyle dosya yükleme(FileUpload) işlemi ile çalışmasını istediğiniz herhangi bir kolon için meta data üzerinde aşağıdaki gibi bir tanımlama yapmanız yeterli oluyor.

NORTWIND veritabanında bulunan Employee tablosundaki PhotoPath kolonu için yapılan örnek tanımlama:

using System.ComponentModel.DataAnnotations;

[MetadataType(typeof(EmployeeMetaData))]
public partial class Employee
{

}

public class EmployeeMetaData
{
    [Eposta.Core.CustomAttributes.FileUpload(
        AllowedFileFormats = "jpg|gif|png|JPG|GIF|PNG",
        MaximumFileSize = 1, // MB
        UploadDictionaryPath = "~/uploads/"
        )]
    [UIHint("MyUpload")]
    public string PhotoPath { get; set; }
} 

Ekran görüntüleri
Listemele ve detay sayfa şablonlarında:

Ekleme ve Güncelleme sayfa şablonlarında:

Meraklısından meraklılarına faydalı olması dileğiyle. Mutlu kodlar.

Ömer Faruk ZORLU

 

ASP.NET , ,

ASP.NET Dynamic Data – Gelişmiş Scaffolding

30 Nisan 2010

 

 

Merhabalar, daha önce ASP.NET Dynamic Data(yazının devamında DD kısaltmasını kullanacağım) hakkında bazı bilgileri yayınlamıştım. Yeni bir makale konusunda düşünürken makale konusu olarak gerçek bir DD projesinde kullanıcı tarafından gelebilecek isteklerin hızlı bir şekilde nasıl karşılanabilineceğinden bahsetmenin uygun olduğuna karar verdim.
Yazılımcı gözüyle değerlendirmek gerekirse kullanıcı gereksinimleri konusunda gözden kaçan bir çok gereksinimi görülmeyebilir.  Örneğin bir tablo içindeki kayıtların listelenmesi yazılımcı için gayet yeterlidir ancak kullanıcı gözüyle bakıldığında her şeyin listelenmesi çoğu zaman gereksiz olacaktır. Bu kapsamda kullanıcı isteklerine karşılık sorun çözümüyle alakalı makalele dizisinin ilkini yazmaya başlıyorum. Daha önceki makalelerde bahsettiğim isimlendirme, biçimlendirme vb. gibi temel işlemlere bu makalede değinmeyeceğim.

Kullanıcı tarafında tablo üzerindeki her alanın(column) görüntülenmesi istenmeyebilir. Bazı durumlarda ise tüm kayıtların listelenmesi kullanım kolaylığı açısından sıkıntılı olabilir.

Scaffolding tekniğiyle istenilen alanların tüm şablonlarda görüntülenmesini engelleyebiliyoruz. Özellikle listeleme sayfalarında tüm alanların sayfada görünür halde olması yatay olarak uzayan bir sayfaya neden olur ancak bu alanları klasik scaffolding tekniği ile gizlersek diğer şablonlardanda kayboluverir.  İşte burada asıl sorun ortaya çıkıyor: Gizlenen alanların kullanıcı tarafından düzenlenmesi gerekiyorsa yada detaylı görüntüleme şablonunda tüm alanların görüntülenmesi gerekiyorsa ne yapacağız?

 

  Aletleri geliştirmek DD için her zaman kazanımdır. Bu senaryoda scaffolding tekniğini sayfa şablonlarına göre nasıl özelleştirebileceğimizi öğreneceğiz.

 

Kullanabileceğimiz veri bileşenleri(GridView, FormView, DetailsView vb.) veri listeleme sırasında listeleme işlemi için IAutoFieldGenerator arayüzünü uygulayan bir sınıf ile veri alanları üzerindeki kararını verir. Varsayılan alan oluşturucularda verideki tüm alanlar DD bildirimleri uygunlandıktan sonra(scaffolding gibi kısıtlamalar vb.) listelenir. Yapılması gereken şey ise veri listeleme işini gerçekleştirme görevini yazacağımız bir sınıfın üstlenmesidir.

IAutoFieldGenerator arayüzünü uygulayan sınıfımız:

namespace Eposta.Core.CustomFieldGenerator{    using System.Collections.Generic;    using System.Web.UI;    using System.Web.DynamicData;     

    /// <summary>    /// Bu sınıf veri listelemesini işlemlerini    /// özelleştirmek amacıyla yazılmıştır.     /// </summary>    public class CustomColumnGenerator : IAutoFieldGenerator    {        /// <summary>        /// Veri listelemesi için incelenecek        /// tablo değişkenini tutar        /// </summary>        protected MetaTable mTable = null;        #region IAutoFieldGenerator Members        /// <summary>        /// Listeleme işlemini gerçekleştirecek method        /// </summary>        /// <param name="control"></param>        /// <returns></returns>        public System.Collections.ICollection GenerateFields(Control control)        {            // Uygun kolonların biriktirildiği koleksiyon            List<DynamicField> dynFieldList = new List<DynamicField>();            // MetaTable atanmışsa            if (mTable != null)            {                // Her bir MetaColumn için                foreach (MetaColumn mColumn in this.mTable.Columns)                {                    // Scaffolding ataması yapılmışsa koleksiyona eklenmesi                    // uygun değildir. Eğer bu kontrol yapılmazsa ilgili                    // alan görüntülenecektir. Çünkü tüm sorumluluğu almış                    // bulunuyoruz                    if (                            !mColumn.Scaffold                        )                        continue;                     DynamicField dynField = new DynamicField();                    dynField.DataField = mColumn.Name;                    dynFieldList.Add(dynField);                }            }            return dynFieldList;        }        #endregion    }}

Scaffolding tekniğini denetleyerek görüntüleme işlemini üstlenen sınıfımız artık hazır. Şimdi sıra şablonlara göre bu denetleme işlemine geldi. Varsayılan şablonlar için bir enum tanımlayıp GenerateFields methodunda şablona görede bir denetleme yapmamız gerecektir.

namespace Eposta.Core.Enums{    public enum PageTemplateType    {        Details,        Edit,        Insert,        List,        ListDetails    }}

Özelleştirme işlemlerinin uygulanabilmesi için özel bir öznitelik geliştirip bildirimlerin bu öznitelik üzerinden gerçekleştirmesi gerekiyor bunun için aşağıdaki sınıfı kullanabiliriz.

[more]

using System;using Eposta.Core.Enums;

namespace Eposta.Core.CustomAttributes{    [AttributeUsage(AttributeTargets.Property)]    public class CustomHiddenColumnAttribute : Attribute    {        /// <summary>        /// İlgili alanın gizlenmesi gereken sayfa şablonları belirleniyor        /// </summary>        public PageTemplateType[] PageTemplateTypes { get; private set; }        /// <summary>        /// Parametresiz bir constructor yazılması mecburi ancak        /// kullanılmaması için hata fırlatılması daha uygun        /// </summary>        public CustomHiddenColumnAttribute()        {            throw new InvalidOperationException();        }        /// <summary>        /// Sayfa şablonlarının atama işleminin kolaylaştırılması        /// nedeniyle params yöntemi kullanılmıştır. Öznitelik         /// tanımlamasında AllowMultiple=true atamasıda yapılabilir        /// </summary>        /// <param name="PageTemplateParams"></param>        public CustomHiddenColumnAttribute(params PageTemplateType[] PageTemplateParams)        {            this.PageTemplateTypes = PageTemplateParams;        }    }}

Bu özniteliğin örnek tanımlaması aşağıdaki gibidir. Daha öncede belirttiğim gibi öznitelik yazmayı çok severim :) Bundan böyle sadece aşağıdaki kodu kullarak tüm kodu yazmadan işimizi halledebiliriz.

[CustomHiddenColumn(        PageTemplateType.List, PageTemplateType.ListDetails)]public string SmtpHost { get; set; }

Madem bu kadar kod yazdık birde MetaColumn nesneleri için genişletilmiş bir method yazarak kolonda ve şablona göre gizlilik bildirimi yapılmışmı diye kontrol edelimki her seferinde bir yığın kod yazmaktan kurtulalım.

using System.Linq;using Eposta.Core.CustomAttributes.UIHint;using Eposta.Core.CustomAttributes;using Eposta.Core.Enums;/// <summary> /// Ömer Faruk ZORLU/// </summary>namespace Eposta.Core.Extentions{    public static class MetaColumnExtentions    {        /// <summary>        /// Sayfa şablonuna göre alanın gizlilik durumunu dönderir        /// </summary>        /// <param name="mColumn"></param>        /// <param name="pTemplateType"></param>        /// <returns></returns>        public static bool IsHidden(this System.Web.DynamicData.MetaColumn mColumn, PageTemplateType pTemplateType)        {            // Kolon üzerinde atanmış ustomHiddenColumn özniteliği alınıyor            // Eğer çoklu tanımlama(AllowMultiple) ya izin verilmişse bir            // döngü içerisinde kontrol edilmesi gerekir            CustomHiddenColumnAttribute chCAttr =                mColumn.Attributes.OfType<CustomHiddenColumnAttribute>().FirstOrDefault();               //  Herhangi bir öznitelik ataması yoksa gizli değildir            if (chCAttr == null)                return false;             // İlgili alan için yapılan gizlilik bildirimleri parametrede            // gönderilmiş sayfa şablonunu içeriyorsa gizlidir            return chCAttr.PageTemplateTypes.Contains(pTemplateType);;        }    }}

Artık daha önce yazdığımız alan oluşturucu sınıf üzerinde özel gizleme yapımızı denetleyen kodlar yazabiliriz. Yukarıda yazdığımız sınıfa yeni eklenen kodlar kalın olarak yazılmıştır.

using System.Collections.Generic;using System.Web.DynamicData;using System.Web.UI;using Eposta.Core.Extentions;using Eposta.Core.Enums; namespace Eposta.Core.CustomFieldGenerator{    /// <summary>    /// Bu sınıf veri listelemesini işlemlerini    /// özelleştirmek amacıyla yazılmıştır.     /// </summary>    public class CustomFieldGenerator : IAutoFieldGenerator    {        /// <summary>        /// Veri listelemesi için incelenecek        /// tablo değişkenini tutar        /// </summary>        protected MetaTable mTable = null;

        protected PageTemplateType pTemplateType;         #region ctor         public CustomFieldGenerator(MetaTable _mTable, PageTemplateType _pTemplateType)        {            this.mTable = _mTable;            this.pTemplateType = _pTemplateType;        }         #endregion         #region IAutoFieldGenerator Members        /// <summary>        /// Listeleme işlemini gerçekleştirecek method        /// </summary>        /// <param name="control"></param>        /// <returns></returns>        public System.Collections.ICollection GenerateFields(Control control)        {            // Uygun kolonların biriktirildiği koleksiyon            List<DynamicField> dynFieldList = new List<DynamicField>();            // MetaTable atanmışsa            if (mTable != null)            {                // Her bir MetaColumn için                foreach (MetaColumn mColumn in this.mTable.Columns)                {                    // Scaffolding ataması yapılmışsa koleksiyona eklenmesi                    // uygun değildir. Eğer bu kontrol yapılmazsa ilgili                    // alan görüntülenecektir. Çünkü tüm sorumluluğu almış                    // bulunuyoruz                    if (                            !mColumn.Scaffold                        )                        continue;                     // List ve ListDetails şablonları için IsHidden                    // genişletilmiş methodu ve IsLongString methodunu                    // kontrol ediyoruz ancak Details şablonu için                    // IsLongString methodunu kontrol edip gizlersek                    // uzun metin alanlar görüntülenmeyecek yani ufak bir                    // bug oluşacaktır.                    switch (this.pTemplateType)                    {                        case PageTemplateType.Details:                            if (mColumn.IsHidden(this.pTemplateType))                                continue; // foreach                            break;                        case PageTemplateType.List:                            if (mColumn.IsHidden(this.pTemplateType) ||                                    mColumn.IsLongString)                                continue; // foreach                            break;                        case PageTemplateType.ListDetails:                            if (mColumn.IsHidden(this.pTemplateType) ||                                    mColumn.IsLongString)                                continue; // foreach                            break;                        default:                            break;                    }                     // Varsayılan şablonların haricinde uzun metinlerin                    // görüntülenmesini engellemek amacıyla bu kontrol                    // yapılıyor                    if (mColumn.IsLongString)                        continue;                     DynamicField dynField = new DynamicField();                    dynField.DataField = mColumn.Name;                     dynFieldList.Add(dynField);                }            }            return dynFieldList;        }        #endregion    }}

Son adımında ise ilgili veri kontrolüne veri listeleme işlemini bizim üstleneceğimizi bildirmek gerekiyor. GridView nesnesi için ColumnGenerator DetailsView içinse RowGenerator parametresi kullanılıyor. Son haliyle List.aspx.cs ve Details.aspx.cs şablon kodları aşağıdaki gibi tanımlanmalıdır.

List.aspx.cs kodları:

using System;using System.Web.DynamicData;using Eposta.Core.CustomFieldGenerator;using Eposta.Core.Extentions; public partial class List : System.Web.UI.Page{    protected MetaTable table;    protected void Page_Init(object sender, EventArgs e)    {        DynamicDataManager1.RegisterControl(GridView1, true /*setSelectionFromUrl*/);        table = GridDataSource.GetTable();        GridView1.ColumnsGenerator = new CustomFieldGenerator(table, Eposta.Core.Enums.PageTemplateType.List);    }    protected void Page_Load(object sender, EventArgs e)    {        Title = table.DisplayName;        InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert);         // Disable various options if the table is readonly        if (table.IsReadOnly)        {            GridView1.Columns[0].Visible = false;            InsertHyperLink.Visible = false;        }    }    protected void OnFilterSelectedIndexChanged(object sender, EventArgs e)    {        GridView1.PageIndex = 0;    }}


Details.aspx.cs kodları:

using System;using System.Linq;using System.Web.DynamicData;using System.Web.UI.WebControls;using Eposta.Core.CustomFieldGenerator;using Eposta.Core.CustomAttributes; public partial class Details : System.Web.UI.Page {    protected MetaTable table;    protected void Page_Init(object sender, EventArgs e) {        DynamicDataManager1.RegisterControl(DetailsView1);    }    protected void Page_Load(object sender, EventArgs e) {        table = DetailsDataSource.GetTable();        DetailsView1.RowsGenerator = new CustomFieldGenerator(table, Eposta.Core.Enums.PageTemplateType.Details);

        Title = table.DisplayName;

        ListHyperLink.NavigateUrl = table.ListActionPath;    }    protected void DetailsView1_ItemDeleted(object sender, DetailsViewDeletedEventArgs e) {        if (e.Exception == null || e.ExceptionHandled) {            Response.Redirect(table.ListActionPath);        }    }}

Çözüm itibari ile Grup tablosunda yapılan tanımlalarla listeleme sayfa şablonlarında bazı alanların gizlenmesini güncelleme ve detaylı görüntüleme sayfa şablonlarında ise kullanıcının verileri görüntülemesine ve düzenlemesine imkan tanımış olduk. Ekran görüntüleri aşağıdaki gibidir.

Güncelleme ekranı:

Listeleme ekranı:

Bir yazının daha sonuna geldik. Kullanıcı gereksinimleriyle alakalı makaleler devam edecektir. Bir sonraki makalede görüşmek üzere. Yaşasın dinamizm!

Ömer Faruk ZORLU

 

ASP.NET , ,

Windows 7 Bitlocker ile Sürücü Şifreleme

24 Mart 2010

Windows 7 ilk çıktığında platformlarda en iyi kullanıcı işletim sistemi olduğu lanse edilmişti. Başı çeken özellikleri arasında ”Gerekli donanım sağlandığında stabil çalışması,Direct Access,Bitlocker sürücü şifreleme,Yeni görsel tasarımı” gösterilmişti.Biz bu makalemizde Bitlocker Sürücü Şifrelemesine değineceğiz.Windows işletim sistemi ailesinde daha önce kullanılan EFS dosya şifreleme yerine Windows 7 ultimate,enterprise,server 2008 R2 ve Vista Enterprise,Ultimate sürümleri  ile birlikte sürücüyü de şifreleyebilen Bitlocker Sürücü Şifreleme eklenmiştir. Günümüzde kişisel bilgisayarlar ve şirket bilgisayarlarında bulunan veriler artık önemli bir güvenlik gerektirmekte ve üçüncü şahısların eline geçmesi telafisi mümkün olmayan sonuçlar doğurmaktadır. Windows 7 de bulunan bu özellik ile sürücümüzü, sürücülerimizi hatta harici depolama aygıtlarımızı mesela usb belleğimizi bile şifreleyebiliriz. Bu şifreleme işleminden sonra sürücülerin içine dahil edilen ve yeni oluşturulan dosyalarda şifrelenmiş olmaktadır. Sistem diskimiz dışındaki disklere bile şifreleme yaptığımızda şifreleme dosyaları sistem içerisinde oluşturulacağı için üçüncü kişiler şifreleme bilgilerimize erişemeyecektir. Bitlocker bilgisayarın yeniden başlatılması sırasında bios ve açılış ayarlarında bir sorun algılar ise güvenlik şifresi girilmesini zorunlu kılar. Network üzerinde oluşturulan paylaşımlarda bize şifreli koruma özelliği sağlar. BitLocker normalde, şifrelenmiş olan bir sabit diskin kilidini kaldırmak için kullanılan anahtarları depolamak için bilgisayarınızdaki Güvenilir Platform Modülü (TPM) yongasını kullanır. Bilgisayarınıza oturum açtığınızda, BitLocker TPM’ye sabit diskin anahtarlarını sorar ve diskin kilidini kaldırır. TPM, BitLocker’a anahtarları siz bilgisayara oturum açtıktan hemen sonra sağladığı için bilgisayarınızın güvenliği oturum açma parolanızın gücüne bağlıdır. Yetkisiz kullanıcıların oturum açmasını önleyen güçlü bir parolanız varsa, BitLocker tarafından korunan sabit disk kilitli kalır. Aşağıda TPM ve Bitlocker çalışma mantığını anlatan grafikler verilmiştir.

Bu bilgilendirme işleminden sonra dilerseniz sürücülerimizin nasıl şifreleneceği konusunda örnek yapalım iki diskli sistemimde (F) diskimizi de Bitlocker Sürücü Şifreleme ile şifreleyelim. Bunun öncesinde TPM desteği olmayan anakartlar da bu şifreleme işlemini yapabilmek için neler yapılması gerektiğini inceleyelim.

Bitlockeri açmak için Başlat – Denetim Masası – Bitlocker Sürücü Şifrelemesi ‘ni tıklatalım.

Bitlocker bilgisayarımız da anakart üzerinde şifrelenmiş sürücünün anahtarlarını içeren “Trusted Platform Modüle (TPM)”e ihtiyaç duyar.Bu donanıma sahip olmayanlar ise bitlockeri yine kullanabilirler fakat bir usb belleğe ihtiyaçları vardir.Şifreleme verileri usb bellek üzerine yazılır.

 

Zaten Windows 7 işletim sistemini destekleyen çoğu donanım da bu sorunu yaşamaz ve kurulumu gerçekleştirebilir siniz. Ben işlemlerimi sanal bir bilgisayar üzerinden gerçekleştirdiğim için bu sorunu yaşayacağım ki olumsuz senaryo ile karşılaşanlar makaleden yararlanabilsinler. Yukarıdaki resimde görüldüğü gibi Tpm ile ilgili hata aldım.Tpm etkin olmadan Bitlocker kullanabilmek için Policy ayarlarımızda değişiklikler yapmamız gerekmektedir.Bunun için başlat – çalıştır – gpedit.msc komutunu yazalım.Açılan Yerel Grup İlkesi Düzenleyiciden Bilgisayar yapılandırması – Yönetim Şablonları – Windows Bileşenleri – Bitlocker Drive Encryption – İşletim Sistemi Sürücüleri Sekmesine kadar gelelim sağ ekranda bulunan Başlangıçta ek kimlik doğrulması iste ilkesini çift tıklatalım.

Açılan ekranda etkin radio butonuna tıklayalım,uygula ve sonra tamam butonlarına basalım.Daha sonra Yerel İlke Düzenleyiciyi kapatalım.Aşağıdaki resimlerde görüldüğü gibi Grup ilkesinde Uyumlu bir Tpm olmadan flash bellek üzerinden işlemimizi yapması için izin verdik.Tabi yukarıda da belirttiğimiz gibi TPM uyumlu anakarta sahip olanlar bu işlemleri gerçekleştirmeyecek ve flash belleğe gereksinim duymayacak.Biz olumsuz durumu göz önüne alıp bu işlemleri gerçekleştirmeye  başladık.

Bu işlemlerden sonra policy ayarlarımızın etkin olması için Başlat – Çalıştır – satırına gpupdate komutunu yazarak ayarlarımızı etkin hale getirip.Denetim masasından tekrar Bitlocker Sürücü şifrelemesini çift tıklatalım.Aşağıdaki resim dikkatini çektiyse yaptığımız policy ayarlarından sonra Tpm aramak yerine (C) sürücüsünün yanında Bitlockeri Aç seçenekli ekran karşımıza geldi.

Yukarıda da bahsettiğimiz gibi işlemleri TPM hatasını almak ve bunun çözümünü nasıl gerçekleştiğini öğrenmek için sanal sistem üzerinden yaptık.Şimdi sürücü şifrelemememizi örneklendirmek adına (F) diskimi şifreleyeceğim.Eğer C sürücümü şifrelemek isteseydim benden flash bellek isteyecekti testlerimizi vmware üzerinden yaptığımız için açılışta Veri Şifrelemesini okuyamayacak , şifrelemeyi tamamlayamayacaktı.Siz bunu gerçek sistemde yapacağınız için bu sorunu yaşamayacak ve çoğu donanımda TPM sorununu da yaşamayacaksınız.Bu açıklamadan sonra (F) diskinizi bitlocker ile şifreleme aşamasına geçelim.Bunun için Bilgisayarımı açalım ve aşağıdaki resimdeki gibi işaretlenmiş alandaki Bitlockeri aç kısmına tıklayalım.

Aşağıdaki açılan ekranda Sürücünün kilidini açmak için bir parola kulanı seçerek bir parola belirleyelim. Bu parola sürücümüzü açmak istediğimizde bize sorulur dilersek bunu akıllı kart ile yapabiliriz ama biz ilk seçeneği  uyguluyoruz.Sona İleri butonuna tıklayalım.

Aşağıda gelen ekranda Kurtarma Anahtarını bir dosyaya kaydeti seçelim.Dilersek bu işlemden önce kurtarma anahtarını  çıktı alıp işimizi sağlama almış oluruz.Biz Kurtarma Anahtarını bir dosyaya kayeti seçip ilerliyoruz.

Kaydetme işlemini aşağıdaki gibi (E) sürücüsünü şifrelerken € diskine kaydedemeyeceğimizden dolayı (C) dikime otomatik gelen kendi ismi ile kaydediyorum.

Aşağıdaki ekranda bize kurtarma anahtarımızın güvenlik amaçlı ağa kaydetmemiz önermektedir. Dilersek ağ üzerine de kayıt yapabiliriz biz evet diyip geçelim. Evet dedikten sonra bir önceki ekrana dönülecektir. İleri butonuna tıklayalım.

Aşağıdaki ekranda veri şifrelemeyi başlatmaya hazır olup olmadığımız sorulmaktadır. Biz Şifrelemeyi Başlat butonuna tıklatıp ilerleyelim.

Aşağıda örüldüğü gibi şifreleme işlemi başlamış olup (E )sürücüme kilit ikonu gelmiştir. Bitlocker ile şifrelenen sürücülerde bu işaret olmaktadır. Bu işlem diskimizin büyüklüğü ve bilgisayarımızın performansına göre biraz zaman alacaktır.

Aşağıdaki ekranda görüldüğü üzere şifreleme işlemi tamamladı. Kapat diyip işlemi bitirelim.

Şimdi bitlocker üzerinde biraz inceleme yapalım. Aşağıdaki resimde bitlocker kurtama anahtarımızın içeriği görüntülenmektedir. Sürücünün kilidini açmak veya kaldırmak istediğimizde kendi oluşturduğumuz parolayı unuttuğumuz taktirde bu bitlocker kurtarma anahtarının içeriğinden yararlanarak işlemimizi yapabiliriz.

Windows7 ile bitlocker biraz daha geliştirilmiştir.128 bitlik ve 256 bitlik şifreleme sağlamakla beraber default 128 bittir. Windows 7 üzerinde bitlocker şifrelemesi uygulanan sistem Vista ve xp üzerinde sadece okunabilmekle beraber yazma işlemi gerçekleştirilemez. Şimdi birkaç test yapalım sonrasında bitlockeri nasıl devre dışı bırakacağımıza bakalım ve makalemizi sonlandıralım. Aşağıdaki resimlerde sağda şifresi açılmış solda ise şifreli haldeki sürücü resimleri yer almaktadır.

                  

Şimdi F dikimize bir şeyler kopyalamak için açalım. Açmaya çalıştığımızda aşağıdaki resimdeki gibi parola isteyecektir. Parolamızı girelim eğer unutursak Bitlocker kurtarma anahtarındaki kurtarma anahtarı ile açabiliriz.

Şifremi girip F diskimi açtığımda kilidinin pasif ve F sürücüme eriştiğimi göreceksiniz.

Bitlocker özellikleri için resimde olduğu gibi diske saş tıklatıp Bitlockeri yöneti seçelim.

Açılan ekran aşağıdaki gibidir. Aşağıdaki seçeneklerde Şifre değiştirme, Parolayı sürücüden kaldırma, Sürücünün kilidini akıllı karta çevirme, Kurtarma anahtarını yeniden yazdırma ve kilidi otomatik açmak gibi opsiyonlar bulunmaktadır.

Son olarak Bitlocker şifrelemesini kaldırma işlemine değinerek makalemizi noktalayalım. Bunun için Denetim masasından Bitlocker şifrele kısmını açalım. Sürücümüzün yanında bulunan Bitlockeri Kapat kısmına tıklatalım.

Bu aşamada karşımıza aşağıdaki gibi uyarı gelecektir.Biz Sürücünün şifrelemesini Çöz butonuna tıklatalım.

Aşağıda resimde görüldüğü gibi şifre çözme işlemi başladı. Bu işlem şifrelemede olduğu gibi çözme işlemindede bilgisayarımızın performansı ve harddisk boyutumuza göre zaman alacaktır.

Şifre çözme işlemi bitti kapat butonunu tıklatalım.

Resimde de görüldüğü gibi sürücü üzerindeki kilit işareti kalktı. Bitlocker uygulamasına son verdik.

Bu makalemizde Vista ile ortaya çıkan Windows 2008 serverde bulunan  bitlocker hakkında genel bilgi, Tpm modülü olmayan bilgisayarlarda nasıl aktif edileceği, Bitlockerin nasıl çalıştırılıp nasıl devre dışı bırakılacağı konusuna değindik. Bir başka makalede görüşmek dileğiyle.

Windows 7 , , , ,

Windows Seven Performance Monitor ve Resource Monitor

24 Mart 2010

Performance Monitor ile sahip olduğumuz bilgisayarımızın kaynak tüketimini anlık olarak görebilmekteyiz. Performance monitör ile İşletim sisteminin üzerinde oluşan beklenmedik yavaşlamaların nedenini öğrenebilir, hiç ihtiyacımız olmamasına rağmen sistemin kullanmış olduğu kaynakları tespit edebilir ve daha performanslı bir İşletim sistemine sahip olabiliriz.

  

Windows Seven üzerindeki Performance Monitor ile, bilgisayar üzerindeki CPU, Disk, Network ve memory bilgilerini öğrenebilir, Donanım hakkında bilgi sahibi olabilir, sahip olunan donanımın ne kadarını hangi servis yada uygulama tarafından kullanıldığı tespit edilebilir.

Windows Seven üzerinde ki Performance Monitor, Windows Seven’ in üzerinde gelen ve ücretsiz olarak kullanabileceğimiz bir araçtır. Performance Monitor aracına erişebilmek için bilgisayarımız üzerinde sağ tuş, yönet butonuna tıkladığımız zaman Computer Manager üzerinden Performance sekmesi altında erişebilmekteyiz.

Performance bolumu altında, sahip olduğumuz bilgisayarın donanımı hakkında bizlere ayrıntılı bilgiler verilmektedir.

Bu bilgiler; Bilgisayarımızın ismi, sahip olduğumuz işlemci marka,modeli, RAM oranı ve ne kadarını kullandığımız gibi bir çok bilgiye ulaşabilmekteyiz.

Bilgisayarımızın sahip olduğu kaynak tüketimini detaylı olarak öğrenmek istersek eğer Performance bölümünde Open Resource Monitor bölümünü tıklamamız yeterlidir. Ayrıca çalıştır bölümüne resmon.exe yazarak erişmemiz mümkündür.

Resource Monitor’ u açtığımız zaman bizleri ilk karşılayan bolum Overview bölümüdür. Bu bolum altında İşletim sistemimizin kullanmış olduğu kaynaklara özet olarak bir bakış yapabiliriz.

Overview bölümünde görebilecek olduğumuz kaynak tüketimlerini yukarıdaki resimde görebilmektesiniz.

Sağ taraftaki bolümde ise grafiksel olarak kaynak tüketimini görebiliyoruz.

Her  bir kaynak için, detaylı olarak kaynak tüketimlerini incelemek istersek Overview bölümünün yanındaki sekmelerde bulunan her bir kaynağı ayrı ayrı inceleyebilmekteyiz. İlk olarak inceleyecek olduğumuz kaynak CPU bölümüdür.

Processes bolumu altında, CPU’ nun kaynaklarını kullanan uygulama ve servisleri görebilmekteyiz. Image bolumu altında, izlemek istediğimiz uygulama ve servisi seçebiliriz. Ve seçmiş olduğumuz bu imageye göre, seçmiş olduğumuz imagenin kullanmış olduğu CPU kaynağını belirleyebiliriz.

CPU’ yu kullanan bu imagenin gerçekten bizim kullanmış olduğumuz programa mı ait yoksa İşletim sisteminin kullanmış olduğu bir kaynak  olup – olmadığını belirlemek çok kolaydır. Image’miz seçili durumdayken Associated Handles bölümünü inceleyebiliriz. Associated Handles bolumu altında imagenin, PID Numarasını, File ismini ve Handle Name kısmını inceleyebilir, register yolunu ve değerini tespit edebiliriz.

Resource Monitorumuz’ de CPU bölümünü seçtiğimiz için, en sağ tarafta bulunan gösterge ise sadece CPU değerlerini göstermektedir. Bu gösterge altında Toplam CPU kullanımını, sahip olduğumuz CPU Core’lerinin kullanımını ve CPU’ yu kullanan servislerin kullanım oranlarını grafiksel olarak tespit edebiliriz.

Memory bölümüne geçiş yaptığımız zaman, CPU bölümünde görmüş olduğumuz değerlerin benzerini sahip olduğumuz memory için görebilmekteyiz.

Sahip olduğumuz Memory boyutunu, kullanım içindeki memory oranını ve boşta-hazırda bekleyen memory boyutunu görmemiz mümkündür.

Image bölümünde kullanılan servis ve uygulama-programları görebilir ve ilgili image bazında bilgi alabilmekteyiz.

Sağ tarafta bulunan grafiksel ara yüzde ise Memory kullanımı hakkında grafiksel olarak bilgi alabilmekteyiz.

Disk sekmesi bölümüne geçtiğimiz zaman, sahip olduğumuz sabit disk hakkında genel bilgi alabilmekteyiz. Diskimizin boyutunu, ne kadarını kullandığımızı ve hazır bekleyen disk boyutunu görebilmekteyiz.

Image bölümünü tıkladığımız zaman güncel kullanılan servis ve uygulamaların Disk kullanım oranlarını görebilir, imagenin saniyede disk üzerinde yazmış ve okumuş olduğu performansını tespit edebiliriz. I/O (ınput/output) bilgisini öğrenebiliriz.

Sağ tarafta bulunan grafiksel ara yüzde ise disk kullanımı hakkında grafiksel olarak bilgi alabilmekteyiz.

Son sekmemiz olan Network bölümünde ise bilgisayarımızın üzerinde tanımlı bulunan Network kartı üzerinden geçen paketler, TCP bağlantılarını ve dinlenilen portları tespit edebiliriz.

Performance Monitor ile belirli zaman dilimlerini izlememiz de mümkündür. Performance monitör üzerinde belirli kaynakları, belirli zaman dilimleri arasında izleyerek hata tespitinde bulunmamız çok kolaydır.

Counters bölümünü kullanım amacımıza bir örnek vermemiz gerekirse, sahip olduğumuz bilgisayar günün belirli zamanlarında çok fazla yavaşlıyor. Bunun nedeni virüs olabileceği gibi, ilgili zaman sularında oluşturulan bir zamanlandırılmış görevde olabilir. Bu yavaşlığın sebebini öğrenebilmek için counter’lar ekleyebilir ve belirli zaman dilimleri arasında istediğimiz kaynak hakkında rapor alabiliriz.

AddCounter bölümünü seçtikten sonra İzlemek istediğimiz kaynakları belirliyoruz.

Belirlemiş olduğumuz kaynakları artık izleyebilmekteyiz.

Dilersek bu kaynak tüketimini bir MMC konsolu ile kaydedebilir ve networkumuz içinde bulunan diğer server ve client İşletim sistemlerini de izleyebiliriz.

Microsoft Windows seven üzerinde bulunan Performance ve Resource monitör makalemizin başında belirttiğimiz gibi ücretsiz bir yazılımdır. 3 Party yazılımlar olarak benzeri bir çok yazılım piyasada ücretli ve ücretsiz olmak üzere bulunmaktadır. Bu yazılımlara örnek olarak Uptime, Belarc Advisor yazılımlarını örnek verebiliriz.

Windows 7 , , ,