Makale Özeti

Bu makalemde ASP.NET projelerinde kontrollerin özellik değerlerinin, geliştireceğimiz bir web control yardımıyla cookie lerde saklanmasını ve sayfanın yüklendiği esnada bu değerlerin geri yüklenmesi konularına değineceğim

Makale

ASP.NET kontrol özelliklerinin saklanması ve geri yüklenmesi

Tüm yazılımcı arkadaşlara selamlar,
Bu makalemde ASP.NET projelerinde kontrollerin özellik değerlerinin, geliştireceğimiz bir web control yardımıyla
cookie lerde saklanmasını ve sayfanın yüklendiği esnada bu değerlerin geri yüklenmesi konularına değineceğim. 

Neden Kontrol Özelliklerini Saklayalım?
Tasarladığımız ASP.NET uygulamalarında, kullanıcıların veritabanında kayıtlı olan bilgilere kolay erişimini sağlamak amacıyla filtreleme veya arama sayfaları geliştiririz.Bu sayfalarda TextBox, CheckBox, DropDownList gibi kontrolleri kullanırız.Bu kontrollerin özelliklerinin (ör: CheckBox.Checked, TextBox.Text) kullanıcı bazında saklanması uygulamamıza kullanım kolaylığı sağlayacaktır.Buna ek olarak bir veri giriş formunda kontrol değerlerinin saklanması, kayıt esnasında oluşacak herhangi bir hatada kullanıcıının girdiği verileri, sayfa tekrar yüklendiğinde görebilmesini sağlayacaktır.

MasterPage kontrolü kullandığınız ASP.NET uygulamalarında siz de farketmişsinizdir, childpage yüklendiğinde masterpage de tekrar yüklenmekte ve masterpage üzerindeki kontrollerin değerleri varsayılan değerlerine geri dönmektedir.Tabi masterpage deki bu sorunu Session değerleri saklayarak aşabilirsiniz ama bu ekstra kodlama gerektirecektir.

StoreControlProperty & StoreControlItem
Bütün bu kolaylıkları nasıl sağlayabiliriz? Bu özelliklerin saklanması için cookie leri kullanabiliriz.Sayfa üzerinde istediğimiz kontrolün istediğimiz özelliğini manuel kod yazmadan cookie lerde saklayabiliriz.Bunu otomasyona almak için de Reflection sınıfı üyelerini kullanabiliriz.Bunun için, değerleri saklanacak kontrollerin bilgilerini gireceğimiz bir birim kontrol ve bu öğelerin değerlerini çalışma zamanında okuma/yazma için taşıyıcı bir kontrol geliştirelim.
Ana kontrolümüze StoreControlProperty, web kontrol özelliklerinin tutulacağı kontrole de StoreControlItem ismini verelim.Fakat kontrolleri geliştirmeye başlamadan önce cookie yazma okuma işlemlerine değinelim.

HttpCookie sınıfı
ASP.NET uygulamalarında cookie okumak yazmak için HttpCookie sınıfını kullanırız.Basit olarak kullanımı aşağıdaki gibidir;

Cookie yaratmak
myCook=new HttpCookie("BenimKurabiyem");
myCook.Expires=DateTime.Now.AddHours(1);
myCook["Deger1"]="The quick brown dog";
myCook["Deger2"]="bites the lazy fox";
this.Page.Response.Cookies.Add(MyCook);


Cookie bilgilerini okumak
HttpCookie myCook=this.Page.Request.Cookies["BenimKurabiyem"];
string strDeger1=myCook["Deger1"].ToString();
string strDeger2=myCook["Deger2"].ToString();


StoreControlItem
Bu sınıfla değerlerini saklayacağımız kontrol bilgilerini saklayacağız.Standartlara uymak açısından kontrol id sini ControlID özellik ismini ise PropertyName üyeleri ile saklayalım.Sınıfımız bir web kontrolü olacağından dolayı System.Web.UI.Control sınıfından türemelidir.

[ToolboxData("<{0}:StoreControlItem runat=server></{0}:StoreControlItem")]
[Browsable(true)]
public class StoreControlItem : Control
{
    private string mControlID = "";
    private string mPropertyName = "";

    public StoreControlItem()
    {
    }

    [NotifyParentProperty(true)]
    [Browsable(true), Description("Değeri saklanacak kontrol ID bilgisi")]
    public string ControlID
    {
        get{return mControlID;}
        set{mControlID = value;}
    } 

    [NotifyParentProperty(true)]
    [Browsable(true), Description("Kontrolün saklanacak özelliği")]
    public string PropertyName
    {
        get{return mPropertyName;}
        set{mPropertyName = value;}
    }
}


StoreControlProperty
Bu sınıfta ilgili kontrollerin özelliklerini işleyeceğiz yani ana sınıfımız StoreControlProperty olacaktır.Bu kontrol StoreControlItem kontrolleri içerecektir.Basit olarak yazım formatına bakmak gerekirse;

<cc2:storecontrolproperty id="StoreControlProperty1" runat="server" ismasterpage="True">
    <StoredControlItems>
        <cc2:StoreControlItem ID="StoreControlItem1" runat="server" ControlID="CheckBox1" PropertyName="Checked">
        </cc2:StoreControlItem>
        <cc2:StoreControlItem ID="StoreControlItem2" runat="server" ControlID="TextBox1" PropertyName="Text">
        </cc2:StoreControlItem>
    </StoredControlItems>
</cc2:storecontrolproperty>


Yukarıdaki kodu sayfamıza yazdığımızda CheckBox1 kontrolünün Checked özelliği ve TextBox1 kontrolünün Text özelliği otomatik olarak cookie ye kaydedilecek, kullanıcının bir sonraki ziyaretinde aynı değerleri alacaktır.

Temel öğeleriyle sınıfımızı oluşturup yavaş yavaş ilerleyelim.

[NonVisualControl, Designer(typeof(StoreControlPropertyDesigner))]
[ParseChildren(true)]
[PersistChildren(false)]
public class StoreControlProperty:Control
{
    //Bu alanda StoreControlItems nesnelerini depolayacağız.
    private List mStoredControlItems = new List();
    //Bu alan sayfanın MasterPage olup olmadığını tutacaktır.
    private bool mIsMasterPage;

    [Browsable(true), Description("")]
    public bool IsMasterPage
    {
        get { return mIsMasterPage; }
        set { mIsMasterPage = value; }
    }        

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public List StoredControlItems
    {
        get{return mStoredControlItems;}
    }

    //Bu metod ile StoreControlPropery içindeki StoreControlItem değerleri okunduğunda
    //StoreControlItem nesnesi StoredControlItems List'ine eklenecektir.
    protected override void AddParsedSubObject(object obj)
    {
        if (obj is StoreControlItem)
            this.StoredControlItems.Add(obj as StoreControlItem);
    }

}

internal class StoreControlPropertyDesigner : ControlDesigner
{
    public override string GetDesignTimeHtml()
    {
        return base.CreatePlaceHolderDesignTimeHtml("");
    }
}


Evet temel üyeleri oluşturduğumuza göre artık değerlerin okunması ve yazılması işlemlerine geçelim.

Kontrol Değerlerinin Sayfa Açılırken Atanması 
Cookie lere yazılmış kontrol bilgilerinin sayfa yüklenirken okunması ve bu kontrollere atanması gerekmektedir.Bu işlem için OnInit metodunu override etmemiz gerekmektedir.Ardından sayfada belirtilen StoreControlItem değerlerini StoreControlItems listesinden okuyup, Cookie değerlerini Reflection ile özelliklerine erişeceğiz.


    protected override void OnInit(EventArgs e)
    {
        if (!this.Page.IsPostBack)
        {
            //StoreControlItems listesindeki StoreControlItem nesnelerine erişiliyor.
            foreach (StoreControlItem sciItem in this.StoredControlItems)
            {
                Control ctlItem;
                //Control türünden ctlItem nesnesine, StoreControlItem da belirtilen ID ye sahip kontrol atanıyor. 
                if (mIsMasterPage)
                    ctlItem = this.Page.Master.FindControl(sciItem.ControlID);
                else
                    ctlItem = this.FindControl(sciItem.ControlID);
                //Eğer kontrol mevcutsa
                if (ctlItem != null)
                {
                    try
                    {
                        object PropertyValue;
                        try
                        {
                            //Her nesnenin özellik değerleri nesne id'si ile kaydedilen cookie lerde olacaktır.
                            //Bu yüzden eğer nesnenin id'sini taşıyan cookie mevcut ise değeri okunuyor.
                            //Ör: this.Page.Request.Cookies["CheckBox1"]["Checked"];
                            PropertyValue = this.Page.Request.Cookies[sciItem.ControlID][sciItem.PropertyName];
                        }
                        catch
                        {
                            return;
                        }

                        //Kontrolümüzün üye bilgilerine ulaşıp cookie'den okuduğumuz değeri ilgili özelliğine atıyoruz.
                        Type ctlType = ctlItem.GetType();
                        MemberInfo[] miType = ctlType.GetMembers();
                        foreach (MemberInfo mi in miType)
                        {
                            if (mi.Name == sciItem.PropertyName)
                            {
                                PropertyInfo pi = (mi as PropertyInfo);

                                object CastPropertyValue = System.Convert.ChangeType(PropertyValue, pi.PropertyType);

                                ctlType.InvokeMember(mi.Name,
                                                    BindingFlags.SetField | BindingFlags.SetProperty |
                                                    BindingFlags.Instance |
                                                    BindingFlags.Public | BindingFlags.NonPublic |
                                                    BindingFlags.IgnoreCase,
                                                    null, ctlItem,
                                                    new object[] { CastPropertyValue });
                            }
                        }
                    }
                    catch
                    {
                        throw new ApplicationException("Özellik yazılamıyor " + sciItem.ControlID + " " + sciItem.PropertyName);
                    }
                }
            }
        }

        base.OnInit(e);
    }

 
Kontrol Değerlerinin PostBack'de Cookie'lere yazılması 
Sayfayı açtığımızda değerlerin yüklenmesi için daha önceden bu değerlerin cookie nesnelerine yazılması gerekmektedir.Bu işlem için OnPreRender metodunu override etmemiz gerekmektedir.Ardından sayfada belirtilen StoreControlItem değerlerini StoreControlItems listesinden okuyup, nesne özelliklerini ilgili Cookie'lere yazacağız.

    protected override void OnPreRender(EventArgs e)
    {
        //StoreControlItems listesindeki StoreControlItem nesnelerine erişiliyor.
        foreach (StoreControlItem sciItem in this.StoredControlItems)
        {
            Control ctlItem;
            //Control türünden ctlItem nesnesine, StoreControlItem da belirtilen ID ye sahip kontrol atanıyor. 
            if (mIsMasterPage)
                ctlItem = this.Page.Master.FindControl(sciItem.ControlID);                    
            else
                ctlItem = this.FindControl(sciItem.ControlID);
            //Eğer kontrol mevcutsa
            if (ctlItem != null)
            {
                object PropertyValue = null;
                try
                {
                    //Her nesnenin özellik değerleri ilgili cookie lere kaydedilecektir..
                    //InvokeMember metodu ile kontrolün istenen özellik değeri PropertyValue değerine atanmaktadır.
                    PropertyValue = ctlItem.GetType().InvokeMember(sciItem.PropertyName,
                                                                 BindingFlags.GetField | BindingFlags.GetProperty |
                                                                 BindingFlags.Instance |
                                                                 BindingFlags.Public | BindingFlags.NonPublic |
                                                                 BindingFlags.IgnoreCase, null, ctlItem, null);
                }
                catch
                {
                    throw new ApplicationException("Özellik okunamiyor " + sciItem.ControlID + " " + sciItem.PropertyName);
                }

                //Kontrolün ID sine ait cookie HttpCookie türünden myCook nesnesine atanıyor.
                HttpCookie myCook = this.Page.Request.Cookies[sciItem.ControlID];
                if (myCook == null)
                {
                    //Eğer cookie client tarafında mevcut değilse, Yeni cookie nesnesi yaratılıyor.
                    myCook = new HttpCookie(sciItem.ControlID);
                    myCook.Expires = DateTime.Now.AddHours(1);
                    //Cookie'ye nesne özellik değeri yazılıyor.
                    //Ör: myCook["Checked"]="true";
                    myCook[sciItem.PropertyName] = PropertyValue.ToString();
                    try
                    {
                        this.Page.Response.Cookies.Remove(sciItem.ControlID);
                    }
                    catch
                    {
                    }
                    //Cookie client tarafında kaydediliyor.
                    this.Page.Response.Cookies.Add(myCook);
                }
                myCook.Expires = DateTime.Now.AddHours(1);
                //Cookie'ye nesne özellik değeri yazılıyor.
                //Ör: myCook["Checked"]="true";
                myCook[sciItem.PropertyName] = PropertyValue.ToString();
                try
                {
                    this.Page.Response.Cookies.Remove(sciItem.ControlID);
                }
                catch
                {
                }
                this.Page.Response.Cookies.Add(myCook);
            }
        }

        base.OnPreRender(e);
    }


Test Projesi
Yeni bir ASP.NET web sayfası oluşturun.Default.aspx sayfasına aşağıdaki gibi kontrolleri yerleştirin.



Solution'a yeni bir Class Library projesi ekleyin ve yukarda yazdığımız sınıfı ClassLibrary projesine ekleyin.
ClassLibrary projesine System.Web ve System.Design referanslarını ekleyin.
XWebSite ASP.NET projesine ClassLibrary projesini referans olarak ekleyin.



XWebExtensions referansını eklediğinizde Araç kutusuna kontrollerimizin eklendiğini göreceksiniz.



Sayfa üzerine bir StoreControlProperty kontrolü sürükleyin ve ASP kod görünümüne geçin.
StoreControlProperty kodunu aşağıdaki kod ile değiştirin.

<cc1:StoreControlProperty ID="StoreControlProperty1" runat="server">
    <StoredControlItems>
        <cc1:StoreControlItem ID="StoreControlItem1" runat="server" ControlID="CheckBox1" PropertyName="Checked">
        </cc1:StoreControlItem>
        <cc1:StoreControlItem ID="StoreControlItem2" runat="server" ControlID="TextBox1" PropertyName="Text">
        </cc1:StoreControlItem>
    </StoredControlItems>
</cc1:StoreControlProperty>


Projeyi derleyin ve çalıştırın.İsim alanına herhangi bir değer girin ve Beni Hatırla Checkbox'ını seçili hale getirin ve button'a tıklayın.
Internet Explorer i kapatın.Projeyi tekrar çalıştırın.Sayfa yüklendiğinde kontrollerin özelliklerinin en son atadığınız özellikleri taşıdığını göreceksiniz.

StoreControlProperty kontrolünü MasterPage sayfalarında da kullanabilirsiniz.Bu özelliği aktif hale getirmeniz için masterpage üzerinde bulunan StoreControlProperty nesnesinin IsMasterPage özelliğini true olarak atamanız yeterli olacaktır. 

Uyarı!
Kontrol değerlerinin cookie lerde saklanması güvenlik açısından açıklara sebep olabilir.
Tavsiyem arama seçenekleri gibi önem teşkil etmeyen durumlarda bu çözümü kullanmanız olacaktır. 
 


Evet bir makalenin daha sonuna geldik.Umarım yararlı olmuştur.
Hepinize mutlu günler dilerim. 


Levent YILDIZ
theone@leventyildiz.net
msmoracle@hotmail.com 
http://www.leventyildiz.net
ÖrnekProje