SİTE
İÇİ ARAMA |
|
Blogroll |
|
|
|
ViewState’in Sunucuda Saklanması |
|
Gönderiliyor lütfen bekleyin... |
|
|
ASPNET uygulamaları, doğaları gereği, Win32 ortamı içinde
çalışan Windows Forms uygulamalarından oldukça farklı yönlere sahiptirler: Bir
ASPNET uygulamasının görüntü ve durumunu saklaması, her ne kadar Windows Forms
uygulamalarına öykünse de, bir web programcısı için çok farklı yollara başvurma
gereği ortaya koyar. Session ve Application objeleri, uygulamayı geliştiren
kişinin en önemli olanaklarını belirlemektedir. Ancak pek çok programcı, bunların
yanında yadsınamayacak bir değer taşımakta olan ViewState’in varlığını hiçe
saymakta, ya da ona değerinin çok altında bir önem vermektedir. Bu makale sizlere
ViewState’i genel olarak tanıtacak, alternatif örneklerle, kullanımı konusunda
temel bilgiler verecektir.
İçerik:
- Genel olarak ViewState
- Getirileri ve götürüleri
- ViewState’in kullanımı
- Kullanıma yönelik alternatifler
- Sunucuda Saklamak
- Server’ın diski üzerinde saklamak
- SQL server ya da benzeri bir veri kaynağını kullanmak
- DataSet ve Session objeleri üzerinde saklamak
Genel Olarak ViewState
ASP.NET ile uygulama geliştirmek, tanımı ve çalışma şekli gereği,
“HTML çıktısı veren bir uygulama yazmak” olarak algılanabilir. Bu durum uygulama
geliştiricinin, ASP.NET’in üretmekte olduğu HTML’in sunumunu yapmakta olan IIS
ile browser arasında, sürekli veri gidiş-gelişlerini düşünmesini gerektirir.
Gerçekte her bir Page objesi, Init event’i ve PreRender event’leri arasında
oluşturulur, HTML çıktısı hazırlanır, ve bu çıktı browser’a gönderildiği anda
dispose edilir. Dolayısıyla hiçbir zaman, bir önceki durumunu kendi başına hatırlayabilen
bir Page objesinden söz edilemez. Programcı, Page objesine bu gidiş-gelişlerden
herhangi biri sırasında, eski durumunu hatırlaması konusunda yardımcı olabilmek
için ViewState ya da benzeri ortak bir depoya başvurmak zorundadır.
Getirileri ve Götürüleri
Performans
ViewState’in kullanımı default olarak etkin durumdadır.
Kullanımı sırasında, Session ve Application objelerinin kullandığı sunucu kaynağından
daha az kaynak tüketir. Çünkü sunucu, veri tutma işini browsera verdiği ve her
seferinde geri aldığı ViewState datasını, sadece Init sırasında deserialize
etmek, ve PreRender sırasında, istemciye HTML göndermeden hemen önce serialize
etmek dışında bir kaynak kullanmadığı için daha az hafıza harcayacaktır. Herhangi
bir session sırasında bazen yüzlerce kere Page oluşturulmakta, ve dispose edilerek
hafızadan atılmaktadır. ViewState de Page’in bir parçasıdır.
Hafıza kullanımının azalmasına rağmen ağ performansı konusunda
pek iyimser olmak mümkün değildir: ViewState her bir PostBack işlemi sırasında
ağ üzerinden istemciye gönderilmek ve geri alınmak zorundadır. Sayfalara bölünmüş,
büyük miktarda veri içeren datagridlerin kullanımı örnek olarak gösterilirse,
ViewState’in kilobyte’larca yer tutarak ve sayfayla birlikte taşınarak ağ üzerindeki
performansı önemli ölçüde azaltabildiği gözlenebilir.
Güvenlik
ViewState browser’a gönderilen bir string’den oluşmakta
olduğundan ve sadece Base64 olarak çevrimi yapıldığından, içeriğinin bir programcı
tarafından çalınması mümkündür. Ancak sanılanın aksine, browser’dan sunucuya
gönderilecek viewstate verisinin değiştirilmesi ile sunucunun kandırılması pek
mümkün değildir. Bunun nedeni, yine sayfa üzerinde tanımlı özelliklerden enableViewStateMAC’ın
default olarak “True” olmasıdır. (Pek çok kaynakta bu default değer “False”
olarak belirtilse de gerçekte “True” değeri almaktadır.)
Browser’dan sunucuya gönderilmekte olan viewstate verisi, sadece
temel güvenlik kriterleri izlendiğinde (Kredi kartı vb. gibi bilgilerin ViewState
verisinin içine yerleştirilmemesi) doğal olarak bir güvenlik açığı yaratmayacaktır.
ViewState’in Kullanımı
ViewState’in ağ performansına yönelik negatif etkileri
nedeniyle kullanımı konusunda belli kriterler ya da alternatifler getirmek yerinde
olur:
- Sabit sayfalarda enableViewState özelliği değerini “False”’a
çevirmek.
- Sayfa üzerinde state’in hatırlanması işlemini ViewState
yerine, Session ya da Application objeleri ile taşınacak verilerle belirlemek.
- Tüm sayfanın enableViewState’ini iptal etmektense, belli
kontrollerin ViewState kullanmasını engellemek.
Kullanıma Yönelik Alternatifler
ViewState’in network performansı üzerindeki negatif etkisini
azaltmak amacıyla bazı alternatif kullanım şekilleri geliştirilebilir. Bu yolda
atılması gerekli en önemli adım, Page nesnesi tarafından ViewState’in nasıl
kullanıldığının anlaşılmasıdır.
Sunucuda Saklamak
Page class’ı üzerinde ViewState’in alınması için yazılmış ve
Page’den türettiğimiz her bir sayfamız tarafından ViewState verilerinin serialize-deserialize
edilerek kullanılmasını sağlayan iki adet virtual metot bulunmaktadır:
protected
virtual object LoadPageStateFromPersistenceMedium()
|
ve
protected
virtual void SavePageStateToPersistenceMedium(object viewState) |
Bu metotlar, LosFormatter adlı, sadece sayfa üzerindeki ViewState
nesnesinin (StateBag class’ı) serialize ve deserialize edilmesi için geliştirilmiş
bir metot kullanmaktadırlar. LosFormatter’ın kullanımı konusunda bir ipucu yakalamak
için, LoadPageStateFromPersistenceMedium metodu içinde olması muhtemel default
kodlara şöyle bir göz atalım:
string
strViewState = Request.Form["__VIEWSTATE"];
LosFormatter lf = new LosFormatter();
object viewState = lf.Deserialize(strViewState);
|
Page class’ından türetilmiş sayfamız üzerinde LoadPageStateFromPersistenceMedium
ve
SavePageStateToPersistenceMedium
metotlarının override edilmesi ve bu metotlar içinde
LosFormatter class’ının Deserialize ve Serialize metotlarının
kullanılmasıyla sunucu, ViewState verilerini hiçbir şekilde istemciye göndermeden
state bilgisini saklayabilir. Bu şekilde hem performans, hem de güvenlik konusunda
önemli artı değerler kazanılabilir.
Aşağıda, bu konuda önerilebilecek üç ayrı alternatif hakkında
bilgiler bulabilirsiniz:
Sunucunun Diski Üzerinde Saklamak
Sunucuda ya da Web Farm üzerindeki herhangi bir ağ paylaşımında,
örneğin “SessionID.SayfaURL.viewState” adlı bir dosya tutulabilir. Aynı session
ID’sine sahip tüm dosyalar, session sona erdiğinde silinebilir. Aşağıda bununla
ilgili bir örnek bulabilirsiniz:
Örnek, web uygulamasının bulunduğu klasörde “NT AUTHORITY\NETWORK
SERVICE” hesabının yazma hakkı bulunan “ViewStateData” adlı bir klasörün bulunduğu
kabul edilerek hazırlanmıştır.
Öncelikle ViewState’i saklayacak ve okuyacak her iki virtual
metodu da override edelim. Bu iki override işlemi de ViewState’in diskte saklanmasını
istediğimiz Page class’ı içinde yapılacaktır:
protected
override void SavePageStateToPersistenceMedium(object viewState)
{
LosFormatter
lf = new LosFormatter();
StreamWriter
sw = new StreamWriter(Server.MapPath("ViewStateData\\" + GetViewStateFileName()));
lf.Serialize(sw,
viewState);
sw.Close();
}
protected
override object LoadPageStateFromPersistenceMedium()
{
LosFormatter lf = new LosFormatter();
StreamReader sr = new StreamReader(Server.MapPath("ViewStateData\\"
+ GetViewStateFileName()));
string strViewState = sr.ReadToEnd();
sr.Close();
return lf.Deserialize(strViewState);
}
private
string GetViewStateFileName()
{
string sessionID = Session.SessionID;
string pageURL = Request.Url.Segments[Request.Url.Segments.Length - 1];
return sessionID + "." + pageURL + ".viewState";
}
|
SavePageStateToPersistenceMedium metodu, LosFormatter ve StreamWriter
kullanarak, ve en altta belirlediğimiz GetViewStateFileName metodundan aldığı
string’e dayanarak dosya yoksa oluşturacak, varsa da üzerine yazarak, içeriğinde
ViewState verilerinin string olarak kalmasını sağlayacaktır.
LoadPageStateFromPersistenceMedium metodu ise ViewState’i string
olarak alıp, yine LosFormatter aracılığıyla StateBag objesine dönüştürecektir.
Son olarak, Session bittiğinde gereksiz dosyaları silme işlemi
de Global class’ı içinde aşağıdaki handler aracılığıyla yapılabilir:
protected
void Session_End(Object sender, EventArgs e)
{
string sessionID = Session.SessionID;
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(Server.MapPath("ViewStateData"));
System.IO.FileInfo[]
files = dir.GetFiles(sessionID + ".*");
foreach (System.IO.FileInfo file in files)
{
file.Delete();
}
}
|
SQL Server ya da Benzeri Bir Data Kaynağı Kullanmak
ViewState’in SQL sunucusunda bir tabloda saklayarak connected
senaryo ile almak da performansı arttıracak başka bir yöntem olarak düşünülebilir.
Öncelikle SessionID, PageURL ve ViewState sütunlarından oluşan
bir tablo belirlenmeli ve SavePageStateToPersistenceMedium metonunun bu tabloya
yazarak ViewState’i saklaması, LoadPageStateFromPersistenceMedium metodunun
da bu tabloda tarama yaparak ViewState verisini alması sağlanmalıdır:
protected
override void SavePageStateToPersistenceMedium(object viewState)
{
SqlConnection
cn = new SqlConnection("data source=localhost;database=ViewStateDemo;trusted_connection=true");
LosFormatter lf = new LosFormatter();
StringWriter sw = new StringWriter();
lf.Serialize(sw, viewState);
System.Text.StringBuilder sb = sw.GetStringBuilder();
string strViewState = sb.ToString();
string strSessionID = Session.SessionID;
string strPageURL = Request.Url.Segments[Request.Url.Segments.Length -
1];
if (SatirVarMi())
{
SqlCommand cmd = new SqlCommand("update ViewStateData set ViewState
= @ViewState where SessionID = @SessionID and PageURL
= @PageURL", cn);
cmd.Parameters.Add("@ViewState", strViewState);
cmd.Parameters.Add("@SessionID", strSessionID);
cmd.Parameters.Add("@PageURL", strPageURL);
try
{
cn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException exp)
{
throw exp;
}
finally
{
cn.Close();
}
}
else
{
SqlCommand cmd = new SqlCommand("insert ViewStateData (SessionID,
PageURL, ViewState) values (@SessionID, @PageURL,
@ViewState)", cn);
cmd.Parameters.Add("@ViewState", strViewState);
cmd.Parameters.Add("@SessionID", strSessionID);
cmd.Parameters.Add("@PageURL", strPageURL);
try
{
cn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException exp)
{
throw exp;
}
finally
{
cn.Close();
}
}
}
protected override
object LoadPageStateFromPersistenceMedium()
{
SqlConnection cn = new SqlConnection("data source=localhost;database=ViewStateDemo;trusted_connection=true");
SqlCommand cmd = new SqlCommand("select ViewState from ViewStateData
where SessionID = @SessionID and PageURL = @PageURL",
cn);
cmd.Parameters.Add("@SessionID", Session.SessionID);
cmd.Parameters.Add("@PageURL", Request.Url.Segments[Request.Url.Segments.Length
- 1]);
string strViewState;
try
{
cn.Open();
strViewState = (string) cmd.ExecuteScalar();
}
catch (SqlException exp)
{
throw exp;
}
finally
{
cn.Close();
}
LosFormatter lf = new LosFormatter();
return lf.Deserialize(strViewState);
}
private
bool SatirVarMi()
{
SqlConnection cn = new SqlConnection("data source=localhost;database=ViewStateDemo;trusted_connection=true");
SqlCommand cmd = new SqlCommand("select count(*) from ViewStateData
where SessionID = @SessionID and PageURL = @PageURL",
cn);
cmd.Parameters.Add("@SessionID", Session.SessionID);
cmd.Parameters.Add("@PageURL", Request.Url.Segments[Request.Url.Segments.Length
- 1]);
int rowCount;
try
{
cn.Open();
rowCount = (int) cmd.ExecuteScalar();
}
catch (SqlException exp)
{
throw exp;
}
finally
{
cn.Close();
}
if (rowCount == 1)
return true;
else
return false;
}
|
Son olarak düşünülmesi gereken, Session bittiğinde SQL’den
gereksiz satırların silinmesidir. Bu işi de Global class’ı içinde aşağıdaki
gibi halletmek mümkündür:
protected
void Session_End(Object sender, EventArgs e)
{
SqlConnection
cn = new SqlConnection("data source=localhost;database=ViewStateDemo;trusted_connection=true");
SqlCommand cmd = new SqlCommand("delete ViewStateData where SessionID
= @SessionID", cn);
cmd.Parameters.Add("@SessionID", Session.SessionID);
try
{
cn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException exp)
{
throw exp;
}
finally
{
cn.Close();
}
}
|
DataSet ve Session Objeleri Üzerinde Saklamak
Son olarak farklı bir alternatif, ViewState’in Session
objesi üzerinde bir dataset’te tutulması düşünülebilir. Aşağıda bu alternatifle
ilgili örnek kodlar bulabilirsiniz:
Öncelikle DSViewState adında bir typed-dataset oluşturalım:
Bu DataSet’in, oluşan her bir yeni session’da bir instance
olarak saklanması ve içindeki tabloya viewstate verilerinin DataRow’lar halinde
eklenmesi ya da değiştirilmesi ile viewstate yine sunucu tarafında ram’de saklanabilecektir.
Global class’ı içinde aşağıdaki gibi bir Session değişkeni
içinde dataset oluşturularak tüm session içinde bu değer kullanılabilir:
protected
void Session_Start(Object sender, EventArgs e)
{
DSViewState
ds = new DSViewState();
Session["dsViewState"] = ds;
}
|
ViewState’in dataset’te saklanması istenen Page class’ı içinde
de aşağıdaki override işlemleri yapılarak da bu alternatif kullanılabilir.
protected
override void SavePageStateToPersistenceMedium(object viewState)
{
LosFormatter
lf = new LosFormatter();
StringWriter
sw = new StringWriter();
lf.Serialize(sw,
viewState);
System.Text.StringBuilder
sb = sw.GetStringBuilder();
string
strViewState = sb.ToString();
string
strPageURL = Request.Url.Segments[Request.Url.Segments.Length - 1];
DSViewState
ds = (DSViewState) Session["dsViewState"];
if
(ds.ViewStateData.Rows.Contains(strPageURL))
{
DataRow
row = ds.ViewStateData.Rows.Find(strPageURL);
row["ViewState"]
= strViewState;
}
else
{
DataRow
row = ds.ViewStateData.NewRow();
row["PageURL"]
= strPageURL;
row["ViewState"]
= strViewState;
ds.ViewStateData.Rows.Add(row);
}
}
protected override
object LoadPageStateFromPersistenceMedium()
{
DSViewState
ds = (DSViewState) Session["dsViewState"];
string
strPageURL = Request.Url.Segments[Request.Url.Segments.Length - 1];
DataRow
row = ds.ViewStateData.Rows.Find(strPageURL);
string
strViewState = (string) row["ViewState"];
LosFormatter
lf = new LosFormatter();
return
lf.Deserialize(strViewState);
}
|
Sonuç olarak, örneklemeye çalıştığım bu üç alternatifle,
ViewState ağ performansı negatif olarak etkilenmeden kullanılabilecek, daha
hızlı çalışan ve ViewState’ten dilediğince yararlanan web uygulamaları geliştirmek
mümkün olabilecektir.
MCSD.NET, MCDBA, MCSE+I, MCSE (NT4, W2K, W2003), MCSA (W2K,
W2003), MCAD, MCP+I, MCP, MCT
Trainer / Software Engineer
[email protected]
Makale:
ViewState’in Sunucuda Saklanması ASP.NET Nazmi Savga
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|
|