مقدمه:
قطعا یکی از مهمترین مشکلات برنامه نویسی Webform ها بالا رفتن اندازه ViewState
در صفحات می باشد. بهترین و توصیه شده ترین روش برای کم کردن اندازه ViewState همانطور
که بار ها و بارها گفته شده است، غیر فعال نمودن این ویژگی در کنترل هایی است که نیازی
به آن ندارند. در برخی موارد نیز باید طوری برنامه را طراحی کنید که حتی کنترل هایی
از قبلی GridView نیز نیازی به این ویژگی نداشته باشند.
اما مواقعی نیز وجود دارند که اندازه ViewState به میزان قابل توجهی بالا رفته و
چاره ای برای کم کردن آن وجود ندارد. در این ترفند به معرفی روشی می پردازیم که با
استفاده از آن بتوان محتوای ViewState را به شکل فشرده تری در صفحات ذخیره نمود. به
یاد داشته باشید که تنها زمانی از این روش استفاده کنید که چاره ای جز این نداشته باشید.
در ادامه مقاله بیشتر در این رابطه صحبت خواهیم نمود.
آغاز:
همانطور که حتما می دانید محتوای ViewState به طور پیشفرض در صفحات وب در درون یک
فیلد پنهان (HiddenField) به نام VIEWSTATE__ قرار می گیرد. برای اینکه عمل فشرده سازی
را انجام دهیم باید محتویات ViewState را قبل از اینکه از سمت سرور به سمت کلاینت ارسال
شود فشرده سازی نموده و در درون یک فیلد پنهان جدید ذخیره نماییم. و طبیعتا هنگامی
که اطلاعات مجددا از سمت کاربر به سمت سرور ارسال شد، باید قبل از اینکه محتویات در
سرور مورد پردازش قرار گیرد عکس عمل فشرده سازی را انجام دهیم تا اینکه هیچ مشکلی در
عملکرد برنامه به وجود نیاید.
برای انجام این کار باید دو تابع مهمی که در صفحات وب وجود دارند را
override نماییم.
اولین تابع SavePageStateToPersistenceMedium می باشد که قبل از اینکه اطلاعات از سمت
سرور به سمت کلاینت ارسال شوند فراخوانی می شود و محلی می باشد که ما به محتوای ViewState
دسترسی داریم و می توانیم آن را فشرده سازی نماییم.
دومین تابع LoadPageStateFromPersistenceMedium می باشد که پس
از اینکه اطلاعات از سمت کلاینت به سرور ارسال شد و قبل از اینکه اطلاعات
ViewState در سمت سرور مورد پردازش قرار گیرند فراخوانی می شود و محلی است که باید
اطلاعات فشرده شده ViewState را از حالت فشردگی خارج کنیم تا محتویات آن قابل استفاده
در سمت سرور باشد.
قبل از اینکه به سراغ پیاده سازی فنی این برنامه برویم بد نیست بدانید که به طور
پیشفرض برنامه ASP.NET از کلاس LosFormatter برای Serializeو Deserialize نمودن
محتوای ViewState استفاده می کند. این کلاس بهترین راندمان را برای اینکار دارد البته
به شرطی که محتوای ViewState شامل رشته ها، اعداد، آرایه ها و انواع ابتدایی داده (Primitive
Types) باشد. در غیر اینصورت کلاس LosFormatter از عهده Serializeو Deserialize
نمودن بر نمی آید و این وظیفه به کلاس BinaryFormatter سپرده می شود که عملکرد آن بسیار
کند و هزینه بر می باشد. به همین دلیل است که اکیدا توصیه می شود که از ذخیره نموده
داده های پیچیده مانند کلاس هایی که خودتان نوشته اید (مانند کلاس User، Address و
غیره) در ViewStateجدا خودداری کنید.
به منظور اینکه قطعه کدی که می نویسیم قابلیت استفاده مجدد خوبی داشته باشد، کلاسی
به نام CompressedViewStatePage خواهیم نوشت که از کلاس Page به ارث رفته است و تمام
تغییرات را در آن اعمال می کنیم. بنابراین در صفحاتی که قصد داریم قابلیت فشرده سازی
ViewState به آن ها اعمال شود، تنها کافی است که به جای کلاس Page از کلاس CompressedViewStatePage
به ارث ببرند.
به قطعه کد زیر دقت کنید.
public
class CompressedViewStatePage
: System.Web.UI.Page
{
private
const string
viewStateFormId = "__vsk";
protected
override
void SavePageStateToPersistenceMedium(object
viewState)
{
LosFormatter
losFormatter = new
LosFormatter();
StringWriter
stringWriter = new
StringWriter();
losFormatter.Serialize(stringWriter,
viewState);
string uncompressedViewStateString
= stringWriter.ToString();
string
compressedViewStateString = CompressBase64(uncompressedViewStateString);
ClientScript.RegisterHiddenField(viewStateFormId, compressedViewStateString);
}
protected
override
object LoadPageStateFromPersistenceMedium()
{
string compressedViewState
= Request.Form[viewStateFormId];
string
decompressedViewState = DecompressBase64(compressedViewState);
LosFormatter losFormatter
= new LosFormatter();
return losFormatter.Deserialize(decompressedViewState);
}
.........
در ابتدای کلاس نام فیلد پنهان جدیدی را که قصد داریم محتویات فشرده شده ViewState
را در آن نگهداری کنیم را در یک متغیر ثابت (viewStateFormId) مشخص نموده ایم (vsk__).
در تابع SavePageStateToPersistenceMedium با استفاده از متد CompressBase64 محتویات
ViewState را فشرده سازی نموده ایم. و در تابع LoadPageStateFromPersistenceMedium
محتویات فیلد vsk__ را با استفاده از متد DecompressBase64 از حالت فشرده خارج نمود
ایم.
پیاده سازی متدهای CompressBase64 و DecompressBase64 را در قسمت زیر مشاهده می
کنید.
private
static string CompressBase64(string
uncompressedBase64)
{
MemoryStream
compressedStream = new
MemoryStream();
GZipStream
gzipStream = new
GZipStream(compressedStream,
CompressionMode.Compress,
true);
byte[]
uncompressedData = Convert.FromBase64String(uncompressedBase64);
gzipStream.Write(uncompressedData, 0, uncompressedData.Length);
gzipStream.Close();
byte[] compressedData = compressedStream.ToArray();
string compressedBase64 =
Convert.ToBase64String(compressedData);
return compressedBase64;
}
private
static
string DecompressBase64(string
compressedBase64)
{
byte[]
compressedData = Convert.FromBase64String(compressedBase64);
MemoryStream compressedStream
= new MemoryStream();
compressedStream.Write(compressedData, 0, compressedData.Length);
compressedStream.Position = 0;
GZipStream
gzipStream = new
GZipStream(compressedStream,
CompressionMode.Decompress,
true);
MemoryStream
uncompressedStream = new
MemoryStream();
CopyStream(gzipStream,
uncompressedStream);
gzipStream.Close();
return
Convert.ToBase64String(uncompressedStream.ToArray());
}
private
static
void CopyStream(Stream source,
Stream dest)
{
byte[]
buffer = new
byte[4096];
int
bytesRead = source.Read(buffer, 0, buffer.Length);
while
(bytesRead > 0)
{
dest.Write(buffer, 0, bytesRead);
bytesRead = source.Read(buffer, 0, buffer.Length);
}
}
در متد CompressBase64 عمل فشرده سازی با استفاده از کلاس
GZipStream انجام می شود
و در متد DecompressBase64 عکس این عمل انجام می شود.
تابع CopyStream برای کپی نموده یک محتوای استریم در یک استریم جدید استفاده شده
است. در DotNet Framework 4.0 متد جدیدی به نام CopyTo معرفی شده
است که این کار را انجام می دهد اما به منظور اینکه قطعه کد ما با نسخه 3.5 نیز
سازگاری داشته باشد، پیاده سازی تابع CopyStream را خودمان انجام داده ایم. با توجه
به اینکه جزئیات پیاده سازی الگوریتم فشرده سازی خارج از اهداف این مقاله می باشد
از ارائه جزئیات بیشتر در این رابطه خودداری می کنیم.
خوب کار تمام است. برای مشاهده نحوه عملکرد این کلاس کافی است که در یک صفحه وب
که دارای حجم زیادی از ViewState می باشد، کلاس صفحه وب را از CompressedViewStatePage
به ارث ببرید و نتیجه را مقایسه کنید.
نکات بسیار مهم:
- شاید این سوال به ذهن شما خطور کرده باشد که چرا خود طراحان برنامه ASP.NET
این قابلیت را به طور پیشفرض در برنامه قرار نداده اند تا اینکه خود ما مجبور نباشیم
این قابلیت را اضافه کنیم؟! شاید دلیل این امر هراس توسعه دهندگان تیم ASP.NET
از استفاده نادرست این ویژگی توسط برنامه نویسان باشد. توجه داشته باشید که فشرده سازی و از حالت فشردگی
خارج نموده محتوای ViewState باعث بالا رفتن پردازش CPU می شود و این موضوع در
وب سایت هایی که دارای بازدیدکنندگان بسیار زیادی می باشند یا اینکه به هر دلیلی
میزان پردازش CPU بالا می باشد، می تواند تبدیل به مشکلی بزرگ شود. بنابراین باز
هم توصیه می کنیم که تنها زمانی از این ترفند استفاده کنید که راهی جز این باقی
نمانده باشد.
- فقط در صفحاتی از این ترفند استفاده کنید که دارای اندازه قابل ملاحظه ای ViewState
باشند. در غیر اینصورت ممکن است که اندازه محتوای ViewState فشرده سازی شده از
اندازه معمولی آن بیشتر شود!
سورس کامل انجام شده در این مقاله از لینک بالای
صفحه قابل دریافت می باشد.
برگرفته از:
ASP.NET Site Performance Secrets
30sharp.com