فشرده سازی ViewState در صفحات وب
  در این مقاله به معرفی روشی جهت فشرده سازی ViewState در صفحات وب می پردازیم.
   ASP.NET
   ۱۹۸۶۰
   دانلود
   مرتضی صحراگرد
   ۱۳۸۹/۱۲/۴
ارسال لینک صفحه برای دوستان ارسال لینک صفحه برای دوستان  اضافه کردن به علاقه مندیها اضافه کردن به علاقه مندیها   نسخه قابل چاپ نسخه قابل چاپ

 

مقدمه:

قطعا یکی از مهمترین مشکلات برنامه نویسی 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