افزايش كارآئی برنامه های وب در ASP.NET 2.0 ( بخش اول )

يكی از ملزومات كليدی در هر نوع برنامه كامپيوتری ميزان كارائی و قابليت پاسخگوئی سريع آن به كاربران است . طراحان و پياده كنندگان برنامه های كامپيوتری می بايست در زمان طراحی ، پياده سازی و نوشتن كد به اين موضوع توجه جدی داشته باشند. برنامه های وب با توجه به ماهيت و رسالت خود می بايست قادر به ارائه خدمات مورد نياز به صدها و يا هزاران متقاضی همزمان به سادگی و با سرعت مطلوب باشند.
دوشنبه، 7 بهمن 1387
تخمین زمان مطالعه:
موارد بیشتر برای شما
افزايش كارآئی برنامه های وب در ASP.NET 2.0 ( بخش اول )
افزايش كارآئی برنامه های وب در ASP.NET 2.0  ( بخش اول )
افزايش كارآئی برنامه های وب در ASP.NET 2.0 ( بخش اول )

يكی از ملزومات كليدی در هر نوع برنامه كامپيوتری ميزان كارائی و قابليت پاسخگوئی سريع آن به كاربران است . طراحان و پياده كنندگان برنامه های كامپيوتری می بايست در زمان طراحی ، پياده سازی و نوشتن كد به اين موضوع توجه جدی داشته باشند.
برنامه های وب با توجه به ماهيت و رسالت خود می بايست قادر به ارائه خدمات مورد نياز به صدها و يا هزاران متقاضی همزمان به سادگی و با سرعت مطلوب باشند. به عبارت ديگر ، همزمان با افزايش كاربران نمی بايست شاهد افت سرعت و كارآئی يك برنامه وب باشيم .
با ارائه فريمورك دات نت و به دنبال آن ASP.NET ، پياده سازی يك برنامه وب بطرز ناباورانه ای ساده شده است . همين موضوع باعث شده است كه طراحان و پياده كنندگان بيشتر در انديشه طراحی و پياده سازی سريع برنامه های وب باشند و به مسائل مربوط به كارآئی برنامه كمتر توجه نمايند .
پياده كنندگان برنامه های وب با استفاده از فناوری ASP.NET می بايست با بكارگيری مجموعه ای از ترفندها ، فناوری ها و رعايت برخی نكات كليدی اقدام به پياده سازی برنامه های وب با كارآئی بالا نمايند .
در اين مقاله و ساير مقالاتی كه در آينده منتشر خواهد شد قصد داريم به برخی از روش های موجود به منظور طراحی و پياده سازی يك برنامه وب كارآ اشاره نمائيم . بدين منظور بر روی سه محور اساسی زير متمركز خواهيم شد :
• طراحی برای كارآئی : در اين رابطه به مجموعه ای از نكات كليدی اشاره خواهيم كرد كه رعايت آنها در زمان طراحی می تواند زمينه پياده سازی يك برنامه وب كارآ را فراهم نمايد .
• تست برنامه قبل از عملياتی شدن آن : يكی از مسائل مهم در ارتباط با برنامه های وب ، عدم تست آنها با شرايط مشابه و يا نزديك به محيط واقعی است . در اين راستا می توان از نرم افزارها و يا ابزارهای مختلفی استفاده كرد تا بتوان عملكرد و سرويس دهی يك برنامه وب را قبل از زير بار رفتن واقعی مشاهده و بررسی نمود . شركت مايكروسافت در اين رابطه ابزارها و برنامه های متعددی را ارائه نموده است كه به بررسی آنها خواهيم پرداخت .
• پياده سازی سيستم caching : با پياده سازی سيستم caching در سطوح متفاوت و caching داده می توان كارآئی برنامه های وب را بطرز كاملا" محسوسی افزايش داد. در اين بخش به نحوه پياده سازی سيستم caching در برنامه های وب اشاره خواهيم كرد .
در ادامه بر روی اولين محور متمركز و به بررسی مسائل مرتبط با آن خواهيم پرداخت .

طراحی برای كارآئی

توجه و رعايت موارد زير پياده كنندگان را در جهت پياده سازی برنامه های وب با كارآئی بالا كمك خواهد كرد :

مكانيزم ترجمه كد در ASP.NET

برنامه های نوشته شده با استفاده از ASP.NET دارای كارآئی بمراتب بيشتری نسبت به برنامه های نوشته شده با استفاده از ASP كلاسيك می باشند . اين دستاورد ناشی از ترجمه اتوماتيك كد در ASP.NET است . در صفحات قديمی نوشته شده با استفاده از ASP كلاسيك ، كدها و يا اسكريپت های موجود در يك صفحه برای هر يك از درخواست های كاربران پردازش می گرديد . در ASP.NET ، هر كلاس صفحه در اولين مرتبه دستيابی كمپايل و برای درخواست های آتی cache می گردد .
زمانی كه اولين مرتبه يك كاربر صفحه ای را درخواست می نمايد ( و يا اولين مرتبه دستيابی پس از ايجاد تغييرات در صفحه ) ، يك تاخير قابل ملاحظه در زمان پاسخ به درخواست خود را مشاهده می نمايد ( تاخير ناشی از ترجمه صفحه ) . برای برخورد با اين موضوع می توان از روش precompilation استفاده نمود . با استفاده از روش فوق پس از استقرار صفحات بر روی سرويس دهنده وب ، بلافاصله امكان درخواست و بازيابی سريع آنها برای متقاضيان فراهم می گردد .

كنترل های سرويس دهنده

كنترل های سرويس دهنده عناصر اصلی در يك صفحه ASP.NET می باشند و load زيادی را به برنامه تحميل نخواهند كرد . اين نوع كنترل ها معمولا" دارای كارآئی بمراتب بهتری نسبت به زمانی می باشند كه يك صفحه به صورت پويا و با استفاده از ترفندهائی نظير متد Response. Write خروجی خود را توليد می نمايد.
در برخی موارد ضرورتی به استفاده از كنترل های سرويس دهنده ASP.NET در يك صفحه وب نخواهيم داشت . به عنوان نمونه ،‌ در صورتی كه دارای يك متن ايستا می باشيم كه هرگز ضرورتی به دستيابی و تغيير آن در زمان اجراء و از طريق كد نداريم ، لزومی به استفاده از كنترلی نظير label نخواهيم داشت . در چنين مواردی می توان به سادگی متن مورد نظر را با استفاده از امكانات HTML در فايل aspx. قرار داد . در ويژوال استوديو می توان از كنترل DIV ( موجود در بخش HTML ، منوی Toolbox) استفاده كرد. در واقع ما تكليف متن مورد نظر جهت نمايش در يك صفحه aspx . را نه در زمان اجراء بلكه در زمان طراحی مشخص كرده ايم .
يكی ديگر از نكات مهم در زمان استفاده از كنترل های سرويس دهنده در صفحات وب ، توجه به رفتار آنها در ارتباط با نگهداری داده پس از ارسال مجدد به سرويس دهنده می باشد . به صورت پيش فرض ، مقادير مرتبط با كنترل های سرويس دهنده نظير مقدار درج شده در يك TextBox ، پس از postback بطور اتوماتيك در view state ذخيره می گردد . در واقع ، view state مكانيزمی برای نگهداری داده كنترل های سرويس دهنده است كه هدف آن غلبه بر محدوديت پروتكل HTTP است ( ماهيت stateless ) .
view state ، يك نام مناسب برای ذخيره داده در يك فيلد ورودی مخفی درون صفحه است . پس از post back ( ارسال مجدد برای‌ سرويس گيرنده ) يك صفحه ، سرويس دهنده قادر به بررسی مقادير نگهداری شده در view state و استفاده از آنها با توجه به شرايط حاكم بر برنامه می باشد . view state يك قابليت عالی است چراكه اجازه نگهداری وضعيت را با استفاده از امكانات سرويس گيرنده فراهم می نمايد و در اين رابطه از كوكی و حافظه سرويس دهنده برای ذخيره وضعيت استفاده نمی گردد .
تعداد زيادی از كنترل های سرويس دهنده ASP.NET از view state برای نگهداری تنظميات خود در زمان تعامل با عناصر موجود بر روی صفحه استفاده می نمايند ( مثلا" ذخيره صفحه جاری در زمان استفاده از ويژگی paging در كنترل سرويس دهنده gridview ) .
در زمان استفاده از view state توجه به موارد زير ضروری است :
• playload صفحه را در زمان درخواست و ارائه افزايش می دهد .
• افزايش overhead در زمان serializing و deserializing داده ذخيره شده در view state كه برای سرويس دهنده post-back شده است .
• افزايش تخصيص حافظه بر روی سرويس دهنده
كنترل های سرويس دهنده علاقه زيادی به استفاده از view state دارند حتی در مواردی كه به وجود آن نياز نمی باشد . به صورت پيش فرض viewstate فعال است و در صورت عدم نياز می بايست آن را در سطح صفحه و يا كنترل غيرفعال نمود . در رابطه با يك كنترل كافی است كه خصلت EnableViewState را false و يا می توان آن را به صورت سراسری و در سطح page غير فعال نمود . دستور زير نحوه انجام اين كار را نشان می دهد :

<%@ Page EnableViewState="false" %> 

برای غير فعال كردن view state در سطح صفحه و يا كنترل از قوانين زير می توان استفاده نمود :
• در صورتی كه در صفحه ای post back انجام نمی گيرد و يا صفحه می بايست همواره برای هر يك از كنترل های موجود بر روی صفحه و به ازاء هر درخواست مجددا" توليد گردد ، می بايست view state را در سطح page غير فعال نمود .
• در صورتی كه ضرورتی به نگهداری داده مرتبط با يك كنترل سرويس دهنده در view state نمی باشد می بايست آن را برای كنترل مورد نظر غير فعال نمود . بدين منظور لازم است كه مقدار EnableViewState مربوط به كنترل معادل False در نظر گرفته شود .
• در صورتی كه كنترل در زمان طراحی مقداردهی شده است و در زمان اجراء مقدار آن تغيير نمی يابد ، خصلت EnableViewState آن می بايست false در نظر گرفته شود .
• در صورتی كه كنترل با هر post back ، مجددا" خوانده شده و refresh می گردد و ضرورتی به نگهداری مقدار داده قبلی وجود نداشته باشد ، خصلت EnableViewState آن می بايست false در نظر گرفته شود .
• در صورتی كه لازم است انتخاب كاربر پس از postback صفحه بازيابی گردد ، می بايست view state را برای كنترل مورد نظر فعال كرد.
view state ، عموما" كند شدن سرويس دهنده را به دنبال نخواهد داشت بلكه حجم صفحه را افزايش داده و مدت زمان ارسال صفحه برای سرويس گيرنده را زياد خواهد كرد . در چنين مواردی كاربران اين برداشت را خواهند داشت كه برنامه كند و قادر به ارائه پاسخ سريع به آنان نمی باشد ، خصوصا" در مواردی كه ارتباط بين سرويس گيرنده و سرويس دهنده از طريق يك خط با سرعت پائين برقرار شده باشد .
عدم استفاده صحيح از view state در برخی موارد می تواند ادامه حيات موثر يك برنامه وب را با چالش جدی مواجه نمايد . اين موضوع در برنامه هائی كه از كنترل های زيادی در يك صفحه استفاده و حجم بالائی از داده را در خود نگهداری می نمايند، مضاعف می گردد. در چنين مواردی داده دو مرتبه به صفحه وب اضافه می گرد : مستقيما" در كد HTML مرتبط با كنترل و مجددا" در يك فيلد مخفی برای view state . داده فوق با هر post back بين سرويس گيرنده و سرويس دهنده مبادله می گردد .
با استفاده از page tracing می توان از تعداد بايتی كه view state مصرف می كند آگاهی يافت .
بحث خود را با معرفی سه محور اساسی زير آغاز و با تمركز بر روی اولين محور ادامه داديم .
• طراحی برای كارآئی : در اين رابطه به مجموعه ای از نكات كليدی اشاره خواهيم كرد كه رعايت آنها در زمان طراحی می تواند زمينه پياده سازی يك برنامه وب كارآ را فراهم نمايد .
• تست برنامه قبل از عملياتی شدن آن : يكی از مسائل مهم در ارتباط با برنامه های وب ، عدم تست آنها با شرايط مشابه و يا نزديك به محيط واقعی است . در اين راستا می توان از نرم افزارها و يا ابزارهای مختلفی استفاده كرد تا بتوان عملكرد و سرويس دهی يك برنامه وب را قبل از زير بار رفتن واقعی مشاهده و بررسی نمود . شركت مايكروسافت در اين رابطه ابزارها و برنامه های متعددی را ارائه نموده است كه به بررسی آنها خواهيم پرداخت .
• پياده سازی سيستم caching : با پياده سازی سيستم caching در سطوح متفاوت و caching داده می توان كارآئی برنامه های وب را بطرز كاملا" محسوسی افزايش داد. در اين بخش به نحوه پياده سازی سيستم caching در برنامه های وب اشاره خواهيم كرد .
در اين بخش همچنان بر روی اولين محور متمركز و به بررسی مسائل در ارتباط با بانك های اطلاعاتی و تاثير آنها در كارآئی يك برنامه وب اشاره خواهيم كرد .

دستيابی به بانك اطلاعاتی

قوانين دستيابی به بانك های اطلاعاتی خيلی سرراست و مشخص است ولی به دليل عدم رعايت برخی نكات توسط طراحان و پياده كنندگان ممكن است كارآئی برنامه های وب كاهش و همزمان با افزايش كاربران امكان استفاده بهينه و مطلوب از برنامه وجود نداشته باشد .
قبل از بررسی اهم مطالب مرتبط با بكارگيری بانك های اطلاعاتی در برنامه های وب لازم است به اين نكته مهم اشاره گردد كه می بايست يك اتصال به بانك اطلاعاتی را صرفا" در زمانی كه به وجود آن نياز است ايجاد و در اولين فرصت ممكن آن را close كرد چراكه اولا" تعداد اتصالات به يك بانك اطلاعاتی محدود و ثانيا" مديريت آنها كار اضافه ای را نيز به سرويس دهنده تحميل خواهد كرد ( استفاده بهينه از يك منبع محدود ) .
با رعايت موارد زير می توان كارآئی برنامه های وب را بهبود بخشيد :
• استفاده از stored procedure : سيستم های مديريت بانك های اطلاعاتی رابطه ای نظير SQL server پيچيدگی های خاص خود را دارند . سيستم های فوق، قادر به انجام كارهای متنوعی هستند كه با استفاده از ASP.NET نمی توان آنها را انجام داد . بكارگيری اين نوع پتانسيل ها می تواند تاثيرات گسترده ای را بر روی برنامه های وب به دنبال داشته باشد . به عنوان نمونه ، استفاده از stored procedure در مقابل Query های توليد شده پويا می تواند تاثير غيرقابل انكاری بر روی كارآيی برنامه های وب داشته باشد چراكه stored procedure را می توان برای استفاده آتی ترجمه و بهينه سازی كرد . تاثير استفاده از stored procedure در مواردی كه لازم است چندين عمليات مرتبط به هم در يك لحظه انجام شود ، بسيار مشهود و ملموس می باشد .
• استفاده از پروفايلينگ و ايندكس : تعريف ايندكس ها بگونه ای كه با نوع جستجو و خواسته های مورد نياز در يك سيستم مطابقت نمايد ، می تواند نتايج مورد نظر را با سرعت قابل قبولی در اختيار كاربران قرار دهد . برای بهينه سازی بی عيب ايندكس ها در يك بانك اطلاعاتی لازم است كه آنها را با استفاده از يك ابزار profiling ارزيابی كرد ( نظير SQL Server Profiler ) . اين نوع ابزارها فعاليت بانك اطلاعاتی را در يك لاگ خاص ثبت می نمايند و در ادامه می توان آن را بررسی ، آناليز و بر اساس نتايج بدست آمده در ايندكس ها تجديد نظر نمود . ابزارهای فوق می توانند مسائلی نظير اجرای كند query را شناسائی و حتی مجموعه ای جديد از ايندكس ها را كه دارای كارآئی بمراتب بهتری می باشند ، پيشنهاد دهند . برای پروفايل بهتر بانك اطلاعاتی لازم است كه يك لود فرضی را بر روی برنامه شبيه سازی كرد.
• بازيابی صرفا" اطلاعات مورد نياز : يكی از ساده ترين روش هائی كه باعث بهبود هر نوع كد بانك اطلاعاتی می گردد ، كاهش حجم اطلاعات بازيابی شده از بانك اطلاعاتی است . اين كار باعث كاهش لود شبكه ، مدت زمان لازم برای باز شدن اتصال و حجم نهائی صفحه می گردد . به عنوان نمونه با استفاده از فيلترينگ مناسب در query ( نظير استفاده از تاريخ ) و بازيابی صرفا" فيلدهای ضروری ، می توان حجم داده بازيابی شده را حتی المقدور كاهش داد .
• استفاده از connection pooling : در يك برنامه وب عمومی ، سيستم مديريت بانك اطلاعاتی درخواست های بيشماری را از طرف سرويس گيرندگان برای صفحات وب متعدد دريافت می نمايد . معمولا" اين اتصالات برای مدت زمان كوتاهی فعال و ايجاد آنها يكی از مراحل وقت گير در زمان پياده سازی است . در صورتی كه هر صفحه وب از connection string مشابه استفاده نمايد ، بانك های اطلاعاتی نظير SQL server قادر به استفاده از connection pooling تعبيه شده در خود برای استفاده مجدد از يك اتصال برای بيش از يك سرويس گيرنده متوالی می باشند . بدين ترتيب امكان استفاده از connection string به دفعات فراهم می گردد. اين كار بطرز چشمگيری باعث بهبود سرعت می گردد . در چنين مواردی می توان از فايل web.config برای ذخيره connection string استفاده تا امكان بكارگيری آنها در صفحات متعدد يك برنامه وب فراهم گردد.
• استفاده از date binding : سريعترين روش بازيابی و نمايش اطلاعات از يك بانك اطلاعاتی ، استفاده از يك DataReader و يا Dataset و نسبت دهی مستقيم آن به يك كنترل داده است . رويكرد فوق ممكن است به عمليات بيشتری جهت استفاده از تمپليت های سفارشی نياز داشته باشد ولی اين وضعيت بمراتب بهتر از حالتی است كه بطور دستی بين سطرها ( ركوردها ) حركت و آنها را در صفحه مورد نظر قرار داد.
• استفاده از caching : در صورتی كه مجموعه ای خاص از داده متناوبا" درخواست و بندرت تغيير می يابد ، می توان آنها را جهت استفاده آتی cache نمود . با استفاده از سيستم caching ، در اولين مرتبه ای كه يك سرويس گيرنده درخواست اطلاعات را می نمايد ، اطلاعات درخواستی از بانك اطلاعاتی خوانده شده و در حافظه موقت قرار می گيرند . بدين ترتيب امكان استفاده مستقيم از اطلاعات cache شده بدون ضرورت دستيابی به بانك اطلاعاتی فراهم می گردد . در بخش های بعدی به بررسی Output caching و data caching خواهيم پرداخت .

session state

session state يكی از بزرگترين محدوديت های تاثير گذار در خصوص كارآئی برنامه های نوشته شده با استفاده از ASP كلاسيك است . با اين كه در ASP.NET ويژگی های جديدی به منظور بهبود كاركرد session state ارائه شده است ولی همچنان لازم است كه از آن با دقت استفاده گردد .
اگر صرفا" ID يك خريدار كالا را در session state ذخيره كرده باشيم، درگير مسائلی خاص نخواهيم شد . در چنين مواردی می توان يك سبد خريد كالای الكترونيكی را با ذخيره ليستی از محصولات انتخابی توسط خريدار ايجاد نمود . در صورتی كه قصد ذخيره حجم بالائی از اطلاعات نظير يك Dataset را داشته باشيم ، می بايست در اين رابطه دقت و تاثير آن را بر روی موفقيت برنامه بررسی كرد . به عنوان نمونه ، در صورتی كه هر session فضائی به ميزان يك مگابايت را استفاده نمايد ، يكصد session همزمان باعث استفاده 100 مگابايت از حافظه خواهد شد .
برای حل اين نوع از مشكلات ، در زمان طراحی می توان بر اساس يكی از دو گزينه های زير تصميم گيری نمود :
• ذخيره تمامی اطلاعات مورد نياز در يك ركورد بانك اطلاعاتی و ذخيره ID ركورد مورد نظر در يك session . روش فوق باعث صرفه جوئی در مصرف حافظه می گردد ولی سرعت برنامه را كاهش خواهد داد ( با توجه به فرآيند دستيابی به بانك اطلاعاتی كه يكی از عناصر مهم و تاثيرگذار در خصوص كارآئی برنامه های وب است ) .
• به عنوان يك راه حل بهتر می توان اطلاعات مورد نظر را در يك ركورد بانك اطلاعاتی ذخيره و در ادامه برخی از اطلاعات را در حافظه cache نمود . بدين ترتيب ، امكان بازيابی اطلاعات با سرعت بيشتری فراهم می گردد . در بخش های بعدی با data caching بيشتر آشنا خواهيم شد .
بهترين روش و يا گزينه برای ذخيره session ، استفاده از روش in-process است كه به صورت پيش فرض در نظر گرفته می شود . برای ذخيره session می توان از روش های ديگری نظير يك بانك اطلاعاتی SQL نيز استفاده نمود . استفاده از روش فوق پردازش های بيشتری را به سيستم تحميل و صرفا" در مواردی كه وب سايت مورد نظر در يك web farm به همراه چندين سرويس دهنده هاست شده باشد ، توصيه می گردد .
محور دوم : تست برنامه قبل از عملياتی شدن آن و يا پروفايلنگ ( Profiling )
برای قضاوت در خصوص تلاش های انجام شده در ارتباط با بهبود كارآئی يك برنامه وب ، می بايست قادر به سنجش كارآئی آن در عمل باشيم . در مواردی كه كارآئی يك برنامه كند و نااميد كننده است ، می بايست بر اساس اطلاعات كافی اقدام به شناسائی گره ها و عوامل تاثير گذار بر روی كارآئی برنامه های وب نمائيم تا از اين رهگذر بتوانيم مشكل و يا مشكلات را برطرف و يك برنامه وب كارآ را آماده استفاده عملياتی و نهائی نمائيم .
يكی از مسائل مهم در ارتباط با برنامه های وب ، عدم تست آنها با شرايط مشابه و يا نزديك به محيط واقعی است . در اين راستا می توان از نرم افزارها و يا ابزارهای مختلفی استفاده كرد تا بتوان عملكرد و سرويس دهی يك برنامه وب را قبل از زير بار رفتن واقعی مشاهده و بررسی نمود .
برای قضاوت در خصوص تلاش های انجام شده در ارتباط با بهبود كارآئی يك برنامه وب ، می بايست قادر به سنجش كارآئی آن در عمل باشيم . در مواردی كه كارآئی يك برنامه كند و نااميد كننده است ، می بايست بر اساس اطلاعات كافی اقدام به شناسائی گره ها و عوامل تاثير گذار بر روی كارآئی برنامه های وب نمائيم تا از اين رهگذر بتوان مشكل و يا مشكلات را برطرف و يك برنامه وب كارآ را آماده استفاده عملياتی و نهائی كرد .
شركت مايكروسافت در اين رابطه ابزارها و برنامه های متعددی را ارائه نموده است كه در ادامه به بررسی آنها خواهيم پرداخت .

Stress Testing

پياده كنندگان برنامه های وب می توانند از ابزارهای تست متعدد به همراه برخی امكانات ارائه شده در فريمورك دات نت برای پروفايل كردن برنامه های ASP.NET استفاده نمايند . اغلب ، گذر از مرحله تست و اعمال يك پل ارتباطی بين نتايج تست و برنامه وب كار زمان گيری است . به عنوان نمونه ممكن است در مرحله تست بتوان اطلاعات مهمی نظير TTFB ( برگرفته شده از Average Time to first byte ) كه نشان دهنده مدت زمان ارسال درخواست و دريافت اولين بايت از سرويس دهنده است و يا TTLB ( برگرفته شده از Average Time to last byte ) كه نشان دهنده زمان ارسال درخواست و دريافت آخرين بايت از سرويس دهنده است را ركورد و ثبت نمود . ولی بدون استفاده از يك روش دقيق و صحيح اندازه گيری ، تشخيص پارامترهای تاثيرگذار در كاهش كارآئی يك برنامه وب كار مشكلی خواهد بود .
به عنوان مثال ، كاهش كارآئی يك برنامه وب ممكن است مربوط به سرعت پائين هارد ديسك ، تنظيمات ضعيف ASP.NET ، عدم طراحی صحيح بانك اطلاعاتی و يا عدم طراحی مناسب برنامه باشد . در واقع‌، تست كارآئی علم و دانش مختص به خود را دارد .
برای انجام اكثر تست های اوليه ، می توان از يك سرويس دهنده اختصاصی و مجموعه ای از سرويس گيرندگان استفاده نمود كه از طريق يك شبكه سريع ايزوله شده با سرويس دهنده وب تعامل برقرار می نمايند . بدين منظور می توان از يك ابزار توليد load كه بطور اتوماتيك مجموعه ای ‌از صفحات را از سرويس دهنده درخواست می نمايد استفاده كرد تا يك لود سنگين شبيه سازی گردد . ACT ( برگرفته شده از Application Center Test ) و WAST ( برگرفته شده از Web Applications Stress Tool ) دو نمونه متداول در اين زمينه می باشند .
با استفاده از ابزارهای فوق می توان شرايط حاكم بر يك برنامه وب در دنيای واقعی را شبيه سازی نمود ( تداوم درخواست صفحات از طريق چندين اتصال همزمان ) . اكثر ابزارهای توليد load ، فعاليت ها و كارهائی را كه انجام می دهند ثبت می نمايند تا امكان بررسی آنها توسط طراحان و پياده كنندگان وجود داشته باشد .
علاوه بر برنامه های فوق ، می توان نتايج را با استفاده از Windows performance counters ثبت و مشاهده كرد .

performance counter

برنامه performance counters ويندوز يكی از ابزارهای متداول موجود برای اندازه گيری كارآئی يك برنامه می باشد . با استفاده از برنامه فوق می توان به تعداد دلخواه counter را اضافه و يا مستقيما" كارآئی را از طريق جعبه محاوره ای system performance اندازه گيری كرد .
برای فعال كردن برنامه فوق می توان از مسير Settings|Control Panel |Administrative Tools |Performance استفاده كرد. اين برنامه به صورت پيش فرض صرفا" كارآئی پردازشگر اصلی سيستم و ديسك را اندازه گيری می نمايد .
پس از نصب ASP.NET ، مجموعه ای counter مفيد برای رديابی و ارزيابی كارآئی برنامه های وب نيز نصب می گردد . برای اضافه كردن counter ، با كليك (سمت راست) بر روی ليست counter و انتخاب properties ، می توان گزينه های مختلفی را پيكربندی نمود ( نظير تغيير شكل ظاهری نمودار و نحوه ثبت اطلاعات در قالب يك گزارش ) .
يكی از مهمترين گزينه ها بخش مربوط به Data است كه با استفاده از آن می توان به ليست موجود يك counter را اضافه و يا از آن حذف نمود . برای شروع ، می توان تمامی كانتر های پيش فرض را حذف و با استفاده از گزينه Add موارد دلخواه را به ليست اضافه نمود .
در جعبه محاوره ای Add Counter ، چندين ويژگی مهم از جمله امكان مشخص كردن نام كامپيوتر وجود دارد . به عبارت ديگر ، شما می توانيد كارآئی يك كامپيوتر راه دور را مانيتور نمائيد . مانيتورينگ كارآئی سرويس دهنده وب از طريق يك سرويس گيرنده ايده آل است چراكه احتمال تاثير عملكرد مانيتورينگ بر روی سرويس دهنده از بين خواهد رفت . ويژگی مهم بعدی ، performance object است كه با استفاده از آن می توان يك گروه counter را متناسب با شی مورد نظر انتخاب نمود . گروه ASP.NET اطلاعات كاملی را در خصوص كارآئی كلی برنامه های ASP.NET ارائه می نمايد . اين در حالی است كه گروه ASP.NET Application اطلاعاتی را در رابطه با يك برنامه وب خاص ارائه می نمايد .
برخی از انواع مفيد كانترها به همراه گروه ، نام counter و عملكرد هر يك از آنها در جدول 1 نشان داده شده است .
سطرهای ستاره دار، كانترهائی را مشخص می نمايد كه با استفاده از آنها می توان اشكال زدائی يك مسئله را انجام داد . ساير سطرها ، كانترهائی را نشان می دهد كه استفاده از آنها همواره مفيد می باشد .

 

گروه

counter

عملكرد

processor

% CPU Utilization

درصد استفاده از CPUرا نشان می دهد . در صورتی كه استفاده از CPUدر يك بازه زمانی صرفنظر از loadسرويس گيرنده ثابت باقی بماند ، نشان دهنده انتظار يك برنامه برای استفاده از يك منبع محدود است .  

ASP.NET

Requests Queued

تعداد درخواست های در انتظار پردازش را مشخص می نمايد . از counterفوق برای مشخص كردن حداكثر loadسرويس دهنده وب استفاده می گردد .

ASP.NET

* Application Restarts ,
Worker Process Restarts

تعداد دفعاتی كه پردازه ASP.NETراه اندازی مجدد و يا resetمی گردد را مشخص می نمايد . اين counterنشاندهنده بروز مسائل ناخواسته است.

ASP.NET Applications

Requests/Sec

حداكثر توان عملياتی برنامه وب را مشخص می نمايد .

ASP.NET Applications

* Errors Total

تعداد خطاء توليد شده توسط يك برنامه وب را مشخص می نمايد . مقدار اين counterدر عمل می بايست صفر و يا نزديك به صفر باشد .

ASP.NET Applications

Pipeline Instance Count

تعداد درخواست pipelineيك برنامه را مشخص می نمايد و از آن برای مشخص شدن حداكثر درخواست همزمانی كه می توان به آنها پاسخ داده شود ، استفاده می گردد .
در صورتی كه مقدار اين counterتحت يك loadپائين باشد ، نشان دهنده استفاده مطلوب از CPUاست . 

System

* Context Switches/sec

پارامتر فوق تعداد دفعات سوئيچينگ thread contextرا نشان می دهد . در صورتی كه مقدار اين پارامتر زياد باشد ،  threadهای مختلف برای استفاده از  يك منبع محدود با يكديگر رقابت می نمايند .

جدول 1 : ليست برخی كانترهای مفيد

دستيابی به كلاس های performance counters از طريق كد

با توجه به اين كه ASP.NET بخشی از فريمورك دات نت است ، پياده كنندگان برنامه های وب می توانند در صفحات وب نوشته شده با استفاده از فناوری ASP.NET به تمامی كلاس های موجود در فريمورك دات نت دستيابی داشته باشند . اين بدان معنی است كه از طريق يك صفحه وب ASP.NET می توان عمليات متعددی نظير پردازش تصاوير ، نوشتن در event log و يا خواندن و انعكاس performance counters در خروجی را انجام داد . گرچه استفاده از امكاناتی از اين قبيل ممكن است چالش های امنيتی مختص به خود را دارا باشد ولی با رعايت نكات ايمنی می توان پتانسيل برنامه های وب را در جهت ارائه خدمات مطلوب و بهينه به كاربران افزايش داد .
به عنوان نمونه می توان يك performance counter جديد را اضافه و يا مقدار متناظر با يك performance counter را بازيابی و در ادامه آن را در يك صفحه وب و يا يك برنامه desktop نمايش داد .
برای استفاده از پتانسيل فوق ، از namespace با نام System.Diagnostics استفاده می گردد . ليست برخی از كلاس های دات نت به منظور تعامل با performance counter در جدول 2 نشان داده شده است .

 

كلاس

عملكرد

PerformanceCounter

ارائه يك  counterخاص كه شامل اطلاعاتی نظير نام counterو نوع داده ئی است كه می بايست ثبت گردد .

PerformanceCounterCategory

يك گروه counterرا  كه شامل يك و يا چندين counterاست ، مشخص می نمايد .

CounterCreationData

ارائه داده مورد نياز برای ايجاد يك counterجديد .

CounterSample

ارائه مجموعه ای از اطلاعات ثبت شده توسط counter.
در اين رابطه يك RawValue( شماره ثبت شده ) ، يك TimeStamp( زمانی كه مقدار ثبت شده است ) و اطلاعات اضافه ای در رابطه با نوع counterو نحوه خواندن آن را ارائه می نمايد .

جدول 2 : ليست برخی كلاس های دات نت برای كار با Performance counter
مثال : نمايش ظرفيت آزاد حافظه فيزيكی در يك صفحه وب
در كد فوق ، ظرفيت آزاد حافظه فيزيكی بر حسب مگابايت در صفحه وب نمايش داده می شود . برای انجام اين كار ، در ابتدا يك نمونه از كلاس PerformanceCounter به همراه نام گروه Memory و counter با نام Available MBytes ايجاد شده است . برای ايجاد يك نمونه از كلاس PerformanceCounter از كد زير استفاده شده است

 Dim perfFreeMem as New PerformanceCounter("Memory", "Available MBytes")

بدين ترتيب يك شی با نام perfFreeMem ايجاد كه Performance counter مورد نظر را ارائه می نمايد . برای خواندن مقدار جاری counter از متد NextValue استفاده می گردد تا مقدار بعدی Performance counter را برگرداند . با نسبت دادن مقدار برگردانده شده به خصلت Text كنترل سرويس دهنده Label ، امكان مشاهده آن در خروجی فراهم می گردد .

<%@ Import Namespace = System.Diagnostics %>
<script runat="server">
  sub Page_Load(sender as Object, e as EventArgs)
     Dim perfFreeMem as New PerformanceCounter("Memory", "Available MBytes")
     lblFreeMem.Text = perfFreeMem.NextValue()
  end sub
</script>

Free Memory (in MB):
<asp:Label id="lblFreeMem" runat="server" />

مراحل انجام كار در مثال فوق به شرح زير است :
• مرحله اول : استفاده از namespace با نام System.Diagnostics در ابتدای برنامه
• مرحله دوم : ايجاد و مقداردهی مناسب يك نمونه از كلاس PerformanceCounter تا قادر به خواندن counter با نام Available MBytes از گروه Memory باشد .
• مرحله سوم : نسبت دادن مقدار برگردانده شده توسط متد NextValue به خصلت Text كنترل سرويس دهنده label با نام lblFreeMem
در اين بخش به بررسی امكانات caching در ASP.NET 2.0 خواهيم پرداخت .

مفاهيم اوليه Caching

Caching از جمله واژه های كاملا" آشنا در عرصه فناوری اطلاعات و ارتباطات است . اين واژه ريشه فرانسوی‌ دارد و به معنی ذخيره سازی است . در دنيای پردازش اطلاعات ، به ذخيره اطلاعات برای استفاده آتی اطلاق می گردد .در واقع ، Caching فرآيندی است كه بر اساس آن داده با فركانس استفاده بالا به منظور پاسخ به درخواست های بعدی ذخيره می گردد. اطلاعات ذخيره شده ممكن است در آينده مجددا" استفاده گردند و يا اين احتمال وجود خواهد داشت كه هرگز شرايط استفاده مجدد از آنها فراهم نگردد . بنابراين Cache صرفا" زمانی مفيد خواهد بود كه هزينه ذخيره اطلاعات كمتر از هزينه بازيابی و يا محاسبه مجدد آنها باشد .
امروزه از مفهوم Caching در زمينه های متعددی در سيستم های كامپيوتری و شبكه ای استفاده می گردد . پردازنده های كامپيوتر دارای cache اختصاصی برای داده و دستورالعمل ها می باشند . سيستم های عامل دارای بافرهای cache برای سيستم های فايل و درايوها می باشند . سيستم های فايل توزيع شده ( شبكه ای ) نظير NFS ( برگرفته شده از network file system ) و AFS ( برگرفته شده از Andrew File System ) برای بهبود كارآئی خود از cache استفاده می نمايند . روترهای بكارگرفته شده در ستون فقرات شبكه اينترنت مسيرهائی را كه اخيرا" از آنها استفاده كرده اند ، cache می نمايند . سرويس دهندگان DNS ، ماحصل فرآيند ترجمه نام به آدرس را جهت استفاد آتی cache می نمايند .
برنامه های كامپيوتری خصوصا" برنامه های وب نيز از اين فناوری در ابعاد گسترده ای استفاده می نمايند تا بتوانند با سرعت بيشتر پاسخگوی نياز كاربران و مخاطبان خود باشند . به عنوان نمونه ، مرورگر با ارائه پتانسل های لازم سمت سرويس گيرنده امكان caching متن و يا تصاوير را فر اهم می نمايد و در سمت سرويس دهنده با استفاده از امكانات متعددی می توان بهترين گزينه caching را به منظور افزايش كارائی انتخاب كرد.
در صورتی كه از روش هائی مناسب به منظور پياده سازی سيستم Caching در برنامه های كامپيوتری استفاده گردد ، كارائی و توانمندی آنها در جهت ارائه خدمات به كاربران بطرز محسوسی افزايش خواهد يافت .

روش های caching در ASP.NET

با عرضه ASP.NET 2.0 تحولات گسترده ای در خصوص cache ايجاد گرديد . پياده كنندگان برنامه های وب با آشنائی و بكارگيری پتانسيل های موجود می توانند برنامه های وب با كارآئی مطلوب را پياده سازی نمايند .
در ASP.NET از دو نوع سيستم caching استفاده می گردد . پياده كنندگان برنامه های وب می توانند و شايد بهتر باشد بگوئيم می بايست از دو سيستم فوق در جهت افزايش كارآئی برنامه های خود استفاده نمايند ، چراكه دو سيستم فوق مكمل يكديگر می باشند .
• Output caching ، ساده ترين روش caching است . صفحات aspx . بر اساس فرآيندی در سمت سرويس دهنده ترجمه و پس از اجراء ، ماحصل خروجی آنها به صورت يك صفحه html برای سرويس گيرنده ارسال می گردد . در اين روش يك نسخه نهائی از صفحه ترجمه شده html كه برای سرويس گيرنده ارسال شده است ، cache می گردد . بدين ترتيب ، زمانی كه سرويس گيرنده بعدی درخواست خود برای استفاده از اين صفحه را برای سرويس دهنده ارسال می نمايد ، در مقابل اجرای صفحه و توليد خروجی لازم ( انجام پردازش های سمت سرويس دهنده با توجه به ماهيت و جايگاه عملكردی يك صفحه در يك برنامه وب ) ، صفحه ترجمه شده html بطور اتوماتيك برای وی ارسال می گردد . بدين ترتيب ، مدت زمانی كه لازم است صفحه به همراه كد درون آن ترجمه و اجراء گردد بطور كامل حذف می گردد .
• Data caching : برای استفاده از اين روش می بايست بطور دستی و از طريق كد شرايط آن را فراهم نمود . پياده كنندگان می توانند بخش های مهمی از اطلاعات را كه زمان زيادی صرف ساختن آنها شده است ( نظير يك DataSet بازيابی شده از يك بانك اطلاعاتی ) را در cache ذخيره نمايند . در ادامه ، ساير صفحات می توانند وجود اين اطلاعات را بررسی و در صورت موجود بودن در cache از آنها استفاده نمايند . بدين ترتيب ، مراحل مورد نياز برای بازيابی اطلاعات حذف خواهد شد .
روش فوق از لحاظ مفهومی شباهت زيادی به استفاده از application state دارد ولی دارای قابليت های بيشتری در سمت سرويس دهنده است . به عنوان نمونه زمانی كه حجم داده بگونه ای زياد گردد كه كارآئی يك برنامه را تحت تاثير قرار دهد ، آيتم های موجود در cache بطور اتوماتيك از cache حذف خواهند شد . برای ذخيره آيتم ها در cache می توان يك تاريخ را مشخص تا پس از سپری شدن زمان مورد نظر بطور اتوماتيك از حافظه حذف گردند .
علاوه بر روش های كلی فوق ، دو نوع خاص ديگر از caching بر اساس مدل های اشاره شده نيز ايجاد شده است :
• Fragment caching : روش فوق نوع خاصی از output caching است و در مقابل caching كد Html برای تمامی صفحه ، صرفا" بخش هائی خاص از كد cache می گردد. در اين روش خروجی كد ترجمه شده Html مربوط به يك كنترل كاربر بر روی يك صفحه ذخيره می گردد . بدين ترتيب در صورت اجراء مجدد صفحه ، كد موجود در صفحه اجراء‌ می گردد و ضرورتی به اجراء كد مرتبط با كنترل كاربر نخواهد بود .
• Data source caching : اين نوع caching بر اساس كنترل های منبع داده ايجاد و شامل كنترل های منبع داده ObjectDataSource ، SqlDataSource و XmlDataSource می باشد. از لحاظ فنی ، در روش فوق از data caching استفاده می گردد. تنها تفاوت موجود در اين رابطه ، عدم نياز به انجام پردازش های مورد نياز توسط پياده كننده است . بدين منظور لازم است كه برخی خصلت ها و پيام های كنترل منبع داده كه مسئوليت ذخيره و بازيابی caching را برعهده دارند ،‌ توسط پياده كنندگان پيكربندی گردد.
در اين بخش و ساير بخش های بعدی به ترتيب به بررسی موارد زير خواهيم پرداخت :
• output caching
• data caching
• caching در كنترل های منبع داده
• SQL cache dependency

نحوه استفاده از output caching

با استفاده از output caching ، نسخه نهائی كد ترجمه شده Html صفحه cache می گردد . زمانی كه صفحه مجددا" و توسط كاربر ديگر درخواست می گردد ، اشياء ايجاد نخواهند شد . همچنين ، چرخه حيات صفحه آغاز نخواهد شد و هيچگونه كدی اجراء نمی گردد . در مقابل ، كد cache شده در اختيار متقاضيان بعدی قرار داده می شود . با توجه به اين كه در روش output caching هزينه های بالا سری كد ( پردازش های اضافه ) حذف می گردد ، كارآئی برنامه بطرز محسوسی افزايش خواهد يافت .
برای آشنائی با نحوه عملكرد output caching ، كد زير را كه زمان و تاريخ جاری سيستم را در خروجی نشان می دهد ، بررسی می نمائيم .

 

 <%@ OutputCache Duration="20" VaryByParam="None" %>
<script runat="server">
  sub Page_Load(sender as Object, e as EventArgs)
    lblDate.Text = "The time is now:<br />"
    lblDate.Text &= DateTime.Now.ToString()
  end sub
</script>
<asp:Label id="lblDate" runat="server" />

متداولترين روش caching يك صفحه ASP.NET ، درج دايركتيو OutputCache در ابتدای فايل aspx . است . كد زير نحوه استفاده از دايركتيو فوق را نشان می دهد :

 <%@ OutputCache Duration="20" VaryByParam="None" %>

در دايركتيو فوق از دو خصلت Duration و VaryByParam استفاده شده است . خصلت Duration به ASP.NET اعلام می نمايد كه صفحه را به مدت 20 ثانيه cache نمايد. خصلت VaryByParam ميزان وابستگی فرآيند caching را به يك و يا چندين پارامتر مشخص می نمايد . در برخی موارد ممكن است اين وابستگی مهم نباشد و مقدار آن None در نظر گرفته شود ( همانند مثال فوق ) .
پس از ذخيره كد فوق در فايلی با نام CacheExample1.aspx و اجراء آن ، نتايج جالب و قابل توجه ای را مشاهده خواهيم كرد . اولين مرتبه ای كه صفحه درخواست می گردد ، تاريخ و زمان جاری در خروجی نمايش داده می شود .در صورتی كه پس از گذشت مدت زمان بسيار كوتاهی صفحه را refresh نمائيم ، خروجی صفحه بهنگام نخواهد شد . در مقابل ، ASP.NET بطور اتوماتيك خروجی نسخه cache شده را ارسال خواهد كرد . وضعيت فوق به مدت 20 ثانيه ادامه خواهد يافت و پس از اتمام تاريخ مصرف نسخه cache شده ، ASP.NET مجددا" كد صفحه را اجراء و يك نسخه جديد cache را ايجاد و از آن به مدت 20 ثانيه ديگر استفاده خواهد كرد .
شايد بنظر 20 ثانيه زمان زيادی نباشد ولی برای سايتی كه حاوی اطلاعات گسترده ای جهت ارائه به كاربران متعدد است ، اين موضوع می تواند كاملا" متفاوت باشد. به عنوان نمونه ، فرض كنيد می خواهيم ليستی از محصولات قابل عرضه به كاربران را در يك صفحه نمايش دهيم . با caching صفحه به مدت 20 ثانيه ، دستيابی به بانك اطلاعاتی محدود به سه عمليات در يك دقيقه می گردد . بدون caching ، برای هر كاربری كه متقاضی مشاهده ليست محصولات است ، می بايست فرآيند ارتباط با بانك اطلاعاتی و نمايش محصولات در يك ساختار نمايشی مناسب ( نظير Gridview ) انجام شود . بديهی است با caching صفحه به مدت 20 ثانيه امكان پاسخگوئی به ده ها درخواست در مدت زمان فوق و بدون نياز به دنبال كردن فرآيند ارتباط با بانك اطلاعاتی و نمايش داده انجام می شود .
توجه داشته باشيد كه اگر مدت زمان حضور يك نسخه cache در حافظه 20 ثانيه تعيين شده باشد ، اين بدان معنی نخواهد بود كه واقعا" در طی مدت زمان فوق نسخه cache شده در حافظه وجود خواهد داشت . صفحه مورد نظر ممكن است در اولين فرصتی كه سيستم به منظور انجام كارهای اساسی تر خود با كمبود حافظه مواجه شود از آن خارج گردد . بدين ترتيب ، پياده كنندگان می توانند با خيالی آسوده از cache استفاده نمايند بدون اين كه نگران تاخير در اجرای برنامه به دليل استفاده از عنصر حياتی حافظه توسط cache باشند.
زمانی كه يك صفحه cache شده مجددا" ترجمه می گردد ، ASP.NET بطور اتوماتيك صفحه را از cache خارج می نمايد . بدين ترتيب از بروز مسائلی نظير عدم وجود نسخه بهنگام شده در cache ممانعت بعمل می آيد .
در زمان تست برنامه بهتر است كه caching غير فعال گردد . در زمان استفاده از روش ها و تكنيك های اشكال زدائی نظير متغيرهای watch و يا ايجاد نقاط breakpoint ممكن است با مشكلاتی‌ مواجه شويم . در چنين مواردی در صورتی كه يك نسخه cache شده از صفحه در دسترس باشد ، كد مرتبط با آن در زمان اشكال زدائی اجراء نخواهد شد .

Caching سمت سرويس گيرنده

يكی ديگر از گزينه ها ، cache صفحه در سمت سرويس گيرنده است . در اين روش ، مرورگر نسخه ای از صفحه را ذخيره و بطور اتوماتيك از آن در مواردی كه دكمه back مرورگر كليك و يا آدرس URL صفحه مجددا" تايپ شود، استفاده می نمايد . در صورتی كه كاربر دكمه Refresh را فعال نمايد ، از نسخه cache شده صرفنظر و صفحه مجددا" از سرويس دهنده درخواست می گردد .
برای cache يك صفحه در سمت سرويس گيرنده از خصلت Location در دايركتيو OutputCache استفاده می گردد . مقدار پيش فرض اين خصلت server است و می تواند مقادير ديگر نظير Client ، None و Any را به آن نسبت داد .

 

 <%@ OutputCache Duration="20" VaryByParam="None" Location="Client" %>

استفاده از caching سمت سرويس گيرنده بمراتب كمتر از caching سمت سرويس دهنده است چراكه صفحه همچنان برای هر كاربر خاص مجددا" ايجاد خواهد شد . در روش فوق ، شاهد كاهش مدت زمان اجراء كد و يا دستيابی به بانك اطلاعاتی در جهت بهبود كارآئی برنامه نخواهيم بود . از روش caching سمت سرويس گيرنده در موارد خاصی نظير زمانی كه صفحه cache شده حاوی داده سفارشی و مختص به يك كاربر است ، استفاده می گردد .
در صورتی كه هر كاربر در يك session مجزاء فعاليت می نمايد ، صفحه يك مرتبه ايجاد و تمامی سرويس گيرندگان از آن استفاده خواهند كرد . در چنين وضعيتی ممكن است عملكرد يك صفحه با مشكل مواجه گردد ( نظير نمايش يك پيام خوش آمدگوئی به كاربر و بر اساس نام آن ) . در مقابل ، می توان از fragment caching برای caching بخش هائی خاص از صفحه و يا caching سمت سرويس گيرنده به منظور ذخيره نسخه مختص يك كاربر بر روی كامپيوتر هر يك از سرويس گيرندگان استفاده نمود.

Caching و Query string

يكی از نكات مهم در خصوص caching ، تصميم در خصوص زمان استفاده مجدد از صفحه و صحت اطلاعات است . اغلب پياده كنندگان تمايل زيادی در ارائه اطلاعات به صورت بلادرنگ دارند و كمتر در انديشه استفاده بهينه از سيستم caching می باشند . پياده كنندگان می توانند بدون نگرانی در موارد متعددی از caching استفاده نمايند تا كارآئی برنامه های وب را افزايش دهند .
در مواردی كه اطلاعات به صورت پويا توليد می گردد وضعيت caching و يا استراتژی ايجاد و بكارگيری مجدد آن تا اندازه ای متفاوت خواهد بود . به عنوان نمونه ، در صورتی كه در صفحه ای از session كاربر جاری استفاده می شود تا بر اساس آن رابط كاربر سازماندهی گردد ، caching تمام صفحه مناسب نخواهد بود چراكه يك صفحه مشابه نمی تواند برای ساير كاربران مفيد و قابل استفاده مجدد باشد . يك نمونه ديگر ، صفحه ای است كه اطلاعات دريافتی خود را از يك صفحه ديگر و از طريق query string دريافت می نمايد . در چنين مواردی صفحه به صورت پويا ايجاد و برای caching آن می بايست از راهكارهائی ديگر استفاده گردد.
در مثال اشاره شده در بخش چهارم به خصلت VaryByParam دايركتيو OutputCache ، مقدار None نسبت داده شده بود . بدين ترتيب به ASP. NET اعلام شده است كه صرفا" يك نسخه از صفحه را cache نمايد تا بتوان از آن در تمامی حالات استفاده مجدد نمود . در چنين مواردی اگر درخواست صفحه به همراه اضافه كردن آرگومان های query string به URL باشد ، صرفا" از همان يك نسخه cache شده بدون توجه به مقدار آرگومان های دريافتی استفاده می گردد ( تا زمانی كه تاريخ مصرف نسخه cache شده به اتمام نرسيده باشد ) . شما می توانيد اين موضوع را با اضافه كردن يك آرگومان query string بطور دستی در مرورگر انجام دهيد . مثلا" سعی كنيد صفحه را با افزودن a=b ? در انتهای URL اجراء نمائيد. مشاهده خواهيد كرد كه خروجی cache شده همچنان يكسان خواهد بود .
با توجه به نتايج فوق ممكن است اينگونه برداشت شود كه output caching برای صفحه ای كه از آرگومان های query string استفاده می نمايد ، مناسب نباشد . در اين رابطه ASP.NET يك راه حل ديگر را ارائه نموده است . در چنين مواردی می توان خصلت VaryByParam را "*" در نظر گرفت تا مشخص گردد كه صفحه از query string استفاده می نمايد و به ASP.NET اعلام گردد كه نسخه های cache مجزاء را برای مقادير مختلف آرگومان query string ذخيره نمايد .

 

 <%@ OutputCache Duration="20" VaryByParam="*" %>

بدين ترتيب زمانی كه صفحه به همراه اطلاعات query string درخواست شود ، در ابتدا ASP.NET مقدار query string را بررسی می نمايد . در صورتی كه رشته دريافتی با درخواست قبلی مطابقت نمايد و يك نسخه cache شده از صفحه موجود باشد ، از آن استفاده خواهد كرد . در غير اينصورت يك نسخه جديد از صفحه ايجاد و بطور جداگانه cache می گردد .
برای آشنائی بهتر با نحوه عملكرد فرآيند فوق ، فرض كنيد مجموعه ای از درخواست ها به ترتيب زير دريافت گردد:
• كاربری صفحه ای را بدون پارامتر query string درخواست و نسخه A صفحه را دريافت می نمايد .
• كاربری صفحه را با پارامتر ProductID=1 درخواست و نسخه B صفحه را دريافت می نمايد .
• كاربر ديگر صفحه را با پارامتر ProductID=2 درخواست و نسخه C صفحه را دريافت می نمايد .
• كاربر ديگر صفحه را با پارامتر ProductID=1 درخواست می نمايد . در صورتی كه تاريخ اعتبار نسخه B كه قبلا" cache شده است به اتمام نرسيده باشد ، اين نسخه برای وی ارسال می گردد.
• كاربر ديگر صفحه را بدون پارامتر درخواست می نمايد . در صورتی كه تاريخ اعتبار نسخه A كه قبلا" cache شده است به اتمام نرسيده باشد ، اين نسخه برای وی ارسال می گردد.
برای تست فوق و دريافت نتايج بهتر می توان مدت زمان اعتبار نسخه cache شده را زياد كرد .
در صورتی كه صفحه ای صرفا" در ارتباط با داده سمت سرويس دهنده ( نظير داده موجود در يك بانك اطلاعاتی ) و يا داده موجود در query string باشد ،‌ بدون نگرانی می توان از روش output caching استفاده كرد .
در صورتی كه خروجی صفحه وابسته به اطلاعات خاص و مرتبط با كاربر نظير داده session و يا كوكی باشد ، از روش output caching نمی توان استفاده نمود چراكه مكانيزمی وجود ندارد كه بر اساس آن بتوان تفاوت caching را بر اساس session و يا كوكی تشخيص داد. output caching همچنين با صفحات پويائی كه محتويات خود را در پاسخ به رويدادهای مرتبط با كنترل ها تغيير می دهند كار نمی كند . در چنين مواردی ، می توان از fragment caching برای caching يك بخش خاص از صفحه و يا از data caching برای caching اطلاعات خاص استفاده كرد.

caching با پارامترهائی خاص

بندرت مقدار VaryByParam معادل "*" در نظر گرفته می شود و در اكثر موارد بهتر است كه يك متغير query string مهم را با نام مشخص كرد . كد زير نحوه انجام اين كار را نشان می دهد.

 

 <%@ OutputCache Duration="20" VaryByParam="ProductID" %>

در چنين مواردی ، ASP.NET مقدار query string را بررسی و به دنبال پارامتر ProductID می گردد . درخواست هائی با پارامترهای مختلف ProductID بطور جداگانه cache و از ساير پارامترها صرفنظر خواهد شد .
در صورت لزوم می توان چندين پارامتر را كه توسط semicolon از يكديگر جدا شده اند به خصلت VaryByParam نسبت داد . كد زير نحوه انجام اين كار را نشان می دهد

در چنين مواردی ، ASP.NET نسخه هائی جداگانه از صفحه را با توجه به مقادير متفاوت ارائه شده توسط ProductID و CurrencyType در cache نگهداری خواهد كرد .

 <%@ OutputCache Duration="20" VaryByParam="ProductID;CurrencyType" %>

مثال : Caching چندين نسخه جداگانه از يك صفحه
در اين مثال از دو صفحه برای نشان دادن نحوه caching چندين نسخه جداگانه از يك صفحه وب استفاده شده است .

صفحه QueryStringSender.aspx

<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %>
<Script Runat="Server">
  Protected Sub AnyButton_Click(ByVal sender As Object,ByVal e As System.EventArgs )
    Response.Redirect("QueryStringRecipient.aspx" &"?Version=" & CType(sender, Control).ID)
  End Sub
</Script>
<html dir="rtl">
<head >
<title>Caching Test</title>
</head>
<body style="font-family: Tahoma;">
  <form id="form1" runat="server">
    <div>
     <asp:Button ID="cmd1" runat="server" Text="نسخه شماره يك"
                        OnClick="AnyButton_Click" Width="133px" Font-Names="Tahoma" />
                       <br /><br />
     <asp:Button ID="cmd2" runat="server" Text="نسخهشماره دو"
                        OnClick="AnyButton_Click" Width="133px" Font-Names="Tahoma" />
                       <br /><br />
    <asp:Button ID="cmd3" runat="server" Text="نسخه شماره سه"
                       OnClick="AnyButton_Click" Width="133px" Font-Names="Tahoma" />
  </div>
  </form>
</body>
</html>

يك event handler ( با نام AnyButton_Click ) پس از كليك بر روی هر يك از سه دكمه موجود در صفحه فعال می گردد . در روتين فوق پس از تشخيص اين كه بر روی كدام دكمه ( cmd2 ، cmd1 و cmd3 ) كليك شده است ، مقدار آن استخراج و به پارامتر Version نسبت داده می شود و در نهايت كاربر به صفحه QueryStringRecipient.aspx هدايت می گردد .
صفحه مقصد ( QueryStringRecipient.aspx ) يك پيام را متناسب با مقدار پارامتر Version در خروجی نمايش می دهد . در صفحه فوق مقدار خصلت VaryByParam دايركتيو OutputCache معادل Version در نظر گرفته شده است.
(صفحه فوق به دنبال يك پارامتر query string با نام Version جهت ايجاد نسخه های جداگانه cache می گردد ) .

 <%@ OutputCache Duration="20" VaryByParam="Version" %>

در صفحه QueryStringRecipient.aspx با توجه به مقدار پارامتر Version ، تاريخ و زمان جاری بر اساس يك فرمت خاص در خروجی نمايش و يك نسخه از آن نيز cache می گردد .

صفحه QueryStringRecipient.aspx

<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %>
<%@ OutputCache Duration="30" VaryByParam="Version" %>

<Script Runat="Server">
  Sub page_load ( )
   lblDate.Text = "زمان و تاريخ جاری:<br />" & DateTime.Now.ToString()
   Select Case Request.QueryString("Version")
    Case "cmd1"
       lblDate.Font.Size = FontUnit.XLarge
    Case "cmd2"
      lblDate.Font.Size = FontUnit.Large
    Case "cmd3"
      lblDate.Font.Size = FontUnit.Small
   End Select
 End Sub
</Script >

<html dir="rtl">
<head id="Head1" runat="server">
<title>Cache test</title>
</head>
 <body style="font-family: Tahoma;">
   <form id="form1" runat="server">
     <div>
          <asp:Label id="lblDate" runat="server" Font-Size="X-Large" Font-Bold="True"
                            EnableViewState="False"></asp:Label>
    </div>
  </form>
</body>
</html>

بدين ترتيب سه خروجی جداگانه Html ايجاد و با توجه به مدت زمان مشخص شده توسط خصلت Duration دايركتيو OutputCache جهت استفاده آتی cache می گردند .

Custom Caching Control

برای ذخيره چندين نسخه cache از يك صفحه تنها گزينه موجود استفاده از پارامترهای query string نمی باشد . ASP.NET به پياده كنندگان برنامه های وب امكان ايجاد رويه هائی سفارشی را می دهد كه به كمك آنها می توان در خصوص caching يك نسخه جديد از يك صفحه و يا استفاده از نسخه موجود تصميم گيری كرد .
كد نوشته شده در هر يك از رويه های فوق مناسب بودن اطلاعات را بررسی و يك رشته را برمی گرداند . در ادامه ، ASP.NET از رشته فوق برای پياده سازی caching استفاده می نمايد. در صورتی كه كد مورد نظر رشته مشابهی را برای درخواست های مختلف توليد نمايد ، ASP.NET از نسخه cache شده صفحه استفاده خواهد كرد و در صورتی كه كد فوق يك مقدار جديد را توليد نمايد ، ASP.NET يك نسخه جديد cache را ايجاد و آن را بطور جداگانه ذخيره می نمايد .
به عنوان نمونه فرض كنيد قصد داريم نسخه های مختلفی از يك صفحه را بر اساس نوع مرورگر cache نمائيم . بدين منظور در ابتدا از دايركتيو OutputCache در ابتدای صفحاتی كه قصد caching آنها را داريم استفاده كرده و در ادامه از خصلت VaryByCustom برای مشخص كردن يك نام كه نوع caching سفارشی را مشخص می نمايد ، استفاده می نمائيم .
با توجه به اين كه قصد داريم صفحات بر اساس مرورگر كاربران cache نمائيم ، در نمونه كد زير از نام Browser استفاده شده است .

 

<%@ OutputCache Duration="10" VaryByParam="None" VaryByCustom="Browser" %>

در ادامه نياز داريم رويه ای را كه رشته سفارشی caching را توليد می نمايد ، ايجاد نمائيم . رويه فوق می بايست در فايل پيكربندی global.asax و يا فايل code-behind مربوطه باشد .
كد زير نحوه انجام اين كار را نشان می دهد .

رويه ای برای ايجاد سفارشی چندين نسخه cache از يك صفحه

 

رويه ای برای ايجاد سفارشی چندين نسخه cacheاز يك صفحه

Function GetVaryByCustomString(ByVal context As HttpContext, ByVal arg As String) As String

 If arg = "Browser"
    Dim BrowserName As String
    BrowserName = Context.Request.Browser.Browser
    Return BrowserName
 Else
    Return MyBase.GetVaryByCustomString(context, arg)
 End If
End Function
 

تابع GetVaryByCustomString يك رشته با مقدار VaryByCustom را از طريق پارامتر arg دريافت می نمايد . بدين ترتيب می توان برنامه ای را پياده سازی نمود كه چندين نوع از caching سفارشی را صرفا" در يك تابع مشابه پياده سازی نمايد . هر نوع از يك نام VaryByCustom مختلف استفاده می نمايد ( نظير Browser ، BrowserVersion و يا DayOfWeek ) . تابع فوق مقدار VaryByCustom را از طريق آرگومان arg مشاهده و رشته caching مناسب را برمی گرداند . در صورتی كه رشته های caching برای درخواست های مختلف مطابقت نمايد ، ASP.NET از نسخه cache شده صفحه استفاده می نمايد. در غير اينصورت ASP.NET برای هر رشته caching يك نسخه جداگانه را ايجاد ، ذخيره و cache می نمايد .
دايركتيو OutputCache دارای يك خصلت سوم است كه از آن برای تعريف caching استفاده می گردد . خصلت فوق كه VaryByHeader نام دارد ، به شما اجازه می دهد كه نسخه هائی جداگانه از يك صفحه را بر اساس مقدار دريافتی يك HTTP header ذخيره نمائيد . در اين رابطه می توان صرفا" يك header و يا مجموعه ای header كه توسط semicolon از يكديگر جدا شده اند را مشخص نمود . سايت های چند زبانی می توانند از روش فوق برای caching چندين نسخه از يك صفحه بر اساس زبان مرورگر سرويس گيرنده استفاده نمايند .
كد زير نحوه استفاده از خصلت VaryByHeader را نشان می دهد .

 <%@ OutputCache Duration="20" VaryByParam="None" VaryByHeader="Accept-Language" %>

Fragment Caching

در برخی موارد ممكن است نتوان تمامی يك صفحه را cache نمود ولی همچنان اصرار داريم كه بخشی از صفحه را كه بندرت تغيير می يابد ( نظير ليست كالاهای موجود ) و هزينه زيادی صرف ايجاد آن شده است را cache نمائيم . در چنين مواردی می توان از روش های متعددی نظير data caching ( در بخش بعد اين مقاله با روش استفاده از آنها آشنا خواهيم شد ) و fragment Caching استفاده كرد .
برای پياده سازی fragment Caching می بايست برای بخشی از صفحه كه قصد caching آن را داريم يك كنترل كاربر را ايجاد و دايركتيو OutputCache را به آن اضافه كرد . بدين ترتيب علی رغم اين كه صفحه cache نخواهد شد ولی كنترل كاربر cache می گردد .
fragment Caching از لحاظ مفهومی مشابه caching يك صفحه است و صرفا" دارای يك تفاوت اساسی است . در صورتی كه صفحه يك نسخه cache شده از يك كنترل كاربر را بازيابی نمايد ، نمی تواند با آن و از طريق كد ارتباط برقرار نمايد . به عنوان نمونه در صورتی كه كنترل كاربر خصلت هائی خاص را ارائه می نمايد ، صفحه وب مورد نظر نمی تواند به اين خصلت ها دستيابی و آنها را تغيير دهد . توجه داشته باشيد ، زمانی كه از يك نسخه cache شده كنترل كاربر استفاده می گردد ، يك بلاك از تگ های Html درون صفحه قرار خواهند گرفت و در عمل شی كنترل كاربر در دسترس نخواهد بود .

Cache Profiles

يكی از مسائل در ارتباط با output caching قرار دادن كد درون صفحه است ( در بخش aspx markup . و يا در بخش كد كلاس ) . با اين كه استفاده و پيكربندی خصلت های مرتبط با دايركتيو OutputCache در صفحات وب ساده تر بنظر می آيد ولی اين روش می تواند مسائل مديريتی و پشتيبانی مختص به خود را نيز به دنبال داشته باشد (خصوصا" اگر ده ها صفحه cache شده ايجاد شده باشد ) . به عنوان نمونه در صورتی كه قصد داشته باشيم تغييراتی را در خصوص caching تمامی صفحات فوق انجام دهيم ( مثلا" تغيير مدت زمان caching از 30 ثانيه به 60 ثانيه ) ، می بايست هر صفحه بطور جداگانه تغيير و در ادامه نيز توسط ASP.NET مجددا" ترجمه گردند .
در ASP.NET 2.0 با معرفی يك راهكار جديد اين امكان در اختيار پياده كنندگان گذاشته شده است تا بتوانند از تنظيمات caching مشابه برای گروهی از صفحات استفاده نمايند . به ويژگی فوق cache profile می گويند و به كمك آن می توان تنظيمات caching را در يك فايل web.config تعريف نمود . بدين ترتيب ، اعمال تغييرات صرفا" از طريق يك نقطه فراهم می گردد .
برای تعريف يك Cache Profile ، از تگ <add> در بخش <outputCacheProfiles> فايل web.config استفاده می گردد . به cache profile ايجاد شده يك نام و مدت زمان مناسب نسبت داده می شود . كد زير نحوه انجام اين كار را نشان می دهد .

 

تعريف يك cache profileدر فايل web.config

<configuration>
   <system.web>
      <caching>
         <outputCacheSettings>
               <outputCacheProfiles>
                   <add name="ProductItemCacheProfile" duration="60" />
                </outputCacheProfiles>
          </outputCacheSettings>
     </caching>
...
   </system.web>
</configuration>

در ادامه می توان از پروفايل فوق به كمك خصلت CacheProfile در يك صفحه استفاده نمود .

 <%@ OutputCache CacheProfile="ProductItemCacheProfile" VaryByParam="None" %>

در صورتی كه بخواهيم ساير جزئيات caching نظير VaryByParam را نيز مشخص نمائيم می توان آن را به عنوان يك خصلت در دايركتيو OutputCache و يا تگ <add> در پروفايل مشخص نمود .

Output Caching در يك سرويس وب

از Output Caching می توان برای متدهای جداگانه در يك سرويس وب نيز استفاده كرد . برای انجام اين كار ، لازم است كه مقدار CacheDuration به WebMethod و قبل از تعريف متد اضافه گردد . كد زير نتايج يك متد وب را به مدت 30 ثانيه cache می نمايد .

 

<WebMethod(CacheDuration:=30)> _
    Public Function MyMethod(ByVal myParameter As Integer) As String
    ...
    End Function

در اين بخش به بررسی data caching خواهيم پرداخت .

caching داده

caching داده ، انعطاف پذيرترين نوع caching است كه استفاده از آن مستلزم انجام مراحلی خاص در برنامه است . پياده كنندگان برنامه های وب می توانند با استفاده از پتانسيل فوق آيتم هائی را كه هزينه ايجاد آنها گران است به شی cache اضافه نمايند .
cache يك خصلت از كلاس صفحه است و نمونه ای از كلاس System.Web.Caching.Cache را بر می گرداند . عملكرد شی فوق شباهت زيادی با شی Application دارد ( نظير دستيابی به آن در تمامی صفحات توسط سرويس گيرندگان مختلف ) . علی رغم وجود شباهت های زياد ، دو شی Application و Cache دارای تفاوت هائی اساسی با يكديگر می باشند :
• شی Cache از نوع thread-safe است . اين بدان معنی است كه پياده كنندگان لازم نيست با صراحت عمليات lock و unlock شی cache را قبل از اضافه كردن و يا حذف يك آيتم از cache انجام دهند . به عنوان نمونه ، در صورت ايجاد يك شی سفارشی ممكن است در يك لحظه بيش از يك سرويس گيرنده قصد استفاده از آن را داشته باشند . در چنين مواردی اين احتمال وجود خواهد داشت كه شرايط استفاده از داده غيرمعتبر برای هر يك از سرويس گيرندگان فراهم گردد . برای غلبه بر محدوديت فوق می توان از روش های مختلفی استفاده نمود . ايجاد يك نسخه ديگر از شی به منظور استفاده از آن در يك صفحه ، يكی از ساده ترين راهكارهای موجود در اين زمينه است .
• آيتم های موجود در شی Cache بطور اتوماتيك از آن حذف می گردند . ASP.NET يك آيتم را پس از اتمام مدت زمان اعتبار آن ، در صورت تغيير يكی از اشياء و يا فايل های وابسته و يا كمبود حافظه سرويس دهنده از cache خارج می نمايد . اين بدان معنی است كه پياده كنندگان می توانند با خيالی آسوده از cache استفاده نمايند بدون اين كه نگران از دست دادن منبع ارزشمند حافظه باشند چراكه ASP.NET در صورت نياز آيتم ها را از حافظه خارج خواهد كرد . با توجه به اين كه همواره اين احتمال وجود دارد كه آيتم های ذخيره شده از cache خارج شده باشند می بايست همواره قبل از دستيابی ، موجود بودن آنها در cache بررسی گردد .
• آيتم های موجود در cache از وابستگی ها ( dependencies ) حمايت می نمايند . پياده كنندگان می توانند يك شی cache شده را به يك فايل ، يك جدول بانك اطلاعاتی و يا يك منبع ديگر مرتبط نمايند . در صورت بروز تغييرات در منبع وابسته ، شی cache شده بطور اتوماتيك غيرمعتبر می گردد و در نهايت از حافظه حذف می شود .

اضافه كردن آيتم به cache

برای اضافه كردن يك شی درون cache از روش های مختلفی استفاده می گردد . يكی از روش های موجود نسبت دهی داده مورد نظر به يك نام و ذخيره آن در شی cache است ( نظير كار با اشياء Session و Application ) . با توجه به اين كه در اين روش نمی توان برای شی cache شده يك مدت زمان خاص را مشخص نمود ، استفاده از اين روش كمتر توصيه شده است .

 

 Cache("KeyName") = objectToCache

يكی ديگر از روش های درج داده درون شی cache ، استفاده از متد Insert است . متد فوق دارای چهار نسخه خاص است . در جدول زير ، گرامر يكی از نسخه های فوق كه جزئيات بيش تری از كار را با بكارگيری پنچ پارامتر مشخص می نمايد، نشان داده شده است .

Cache.Insert(key, item, dependencies, absoluteExpiration, slidingExpiration)

در جدول زير عملكرد هر يك از پارامترهای متد Insert توضيح داده شده است .

پارامتر

عملكرد

Key

 نام در نظر گرفته شده برای آيتم Cacheشده را مشخص می نمايد. بدين ترتيب ، امكان دستيابی به آيتم Cacheشده بر اساس نام فراهم  گردد.

Item

 شی واقعی كه قصد cachingآن را داريم ، مشخص می نمايد .

dependencies

يك شی CacheDependencyكه به شما اجازه می دهد يك وابستگی برای آيتم مورد نظر در cacheرا ايجاد نمائيد .
در صورتی كه قصد تعريف يك آيتم وابسته را نداريم ، مقدار اين پارامتر می بايست  nullدر نظر گرفته شود .

absoluteExpiration

 يك شی DataTimeكه  زمان و تاريخ خارج كردن آيتم cacheشده  از cacheرا مشخص می نمايد .

slidingExpiration

 يك شی TimeSpanكه مدت زمان انتظار بين درخواست های متوالی در صورت عدم استفاده از داده cacheشده جهت خروج از cacheرا مشخص می نمايد .
به عنوان مثال ، در صورتی كه اين مقدار 20 دقيقه در نظر گرفته شود و در مدت زمان فوق هيچگونه درخواستی برای داده فوق دريافت نگردد ،‌ ASP.NETآن را از حافظه خارج خواهد كرد . 

جدول 1 : پارامترهای متد Insert
معمولا" از تمامی پارامترهای فوق در يك زمان استفاده نمی گردد . به عنوان مثال ، Cache dependencies يك ابزار خاص است كه به كمك آن می توان وابستگی يك آيتم cache شده به ساير منابع تاثيرگذار را مشخص نمود .
در صورتی كه قصد استفاده از يك absolute expiration را داشته باشيم ، می بايست مقدار پارامتر slidingExpiration معادل TimeSpan.Zero در نظر گرفته شود.

 Cache.Insert("MyItem", obj, Nothing,DateTime.Now.AddMinutes(60), TimeSpan.Zero)

در صورتی كه مطمئن باشيم اطلاعات موجود در يك آيتم cache شده در يك بازه زمانی خاص معتبر باقی می ماند ( نظير يك گزارش هواشناسی ) ، استفاده از absolute expiration توصيه می گردد . در صورتی كه داده ذخيره شده در cache همواره معتبر باشد ( نظير كاتولوگ يك محصول ) ، استفاده از Sliding expiration توصيه می گردد . به عنوان يك سياست مطلوب در خصوص بكارگيری Sliding expiration ، می توان مقدار پارامتر absoluteExpiration را به DateTime.Max نسبت داد .

Cache.Insert("MyItem", obj, Nothing,DateTime.MaxValue, TimeSpan.FromMinutes(10))

يك مثال كاربردی

در برنامه زير يك سيستم caching داده ساده پياده سازی شده است . در اين مثال يك آيتم با نام TestItem كه تاريخ و زمان جاری را در خود نگهداری می نمايد به مدت 30 ثانيه cache می گردد . پس از postback صفحه ، در صورتی كه تاريخ اعتبار آيتم ذخيره شده در cache به اتمام نرسيده باشد ، مقدار آن از cache بازيابی و در خروجی نمايش داده می شود . پس از اتمام تاريخ اعتبار آيتم ذخيره شده در cache ، مجددا" و بر اساس داده جديد ( تاريخ جديد سيستم ) آيتم مورد نظر ايجاد و جهت استفاده آتی در cache ذخيره می گردد .

 

ذخيره و بازيابی داده در شی cache

<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %>

<Script Runat="server">
   Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)   Handles Me.Load
    If Me.IsPostBack Then
      lblInfo.Text &= "ارسال مجددصفحه برای سرويس دهنده<br />"
    Else
      lblInfo.Text &= "ايجاد صفحه<br />"
   End If
  If Cache("TestItem") Is Nothing Then
    lblInfo.Text &= "ايجاد داده جهت ذخيره درcache<br />"
    Dim testItem As DateTime = DateTime.Now
    lblInfo.Text &= "به مدت 30 ثانيه<br />"
    Cache.Insert("TestItem", testItem, Nothing, DateTime.Now.AddSeconds(30), TimeSpan.Zero)
  Else
   lblInfo.Text &= "بازيابی داده ازcache...<br />"
   Dim testItem As DateTime = CType(Cache("TestItem"), DateTime)
   lblInfo.Text &= "دادهcache شده: '" & testItem.ToString()
   lblInfo.Text &= "'<br />"
 End If
 lblInfo.Text &= "<br />"

End Sub
</Script>

<html xmlns="http://www.w3.org/1999/xhtml" dir ="rtl">
 <head id="Head1" runat="server">
     <title>تستcaching داده</title>
 </head>
 <body style="font-family: Tahoma;">
    <form id="form1" runat="server">
      <div>
        <asp:Button ID="Button1" runat="server" Text="ارسالصفحه برای سرويس دهنده" Font-Names="Tahoma" />
        <br /><br />
        <asp:Label ID="lblInfo" runat="server"></asp:Label>
      </div>
   </form>
 </body>
</html>

در اين بخش برای آشنائی با نحوه عملكرد شی cache به بررسی يك نمونه مثال كاربردی پرداختيم كه در آن داده مورد نظر برای مدت زمان خاصی در cache مستقر می گرديد . در ادامه و به منظور پاسخ به درخواست سرويس گيرندگان از داده ذخيره شده در cache مشروط به عدم اتمام تاريخ اعتبار آن استفاده می گرديد . در صورت اتمام تاريخ مصرف نسخه cache شده ، داده جديد توليد و مجددا" در cache قرار می گرفت . در اين مثال صرفا" يك داده ساده در cache قرار می گرفت .
شايد برای شما اين سوال مطرح شده باشد كه آيا می توان اطلاعات پيچيده تری نظير داده بازيابی شده از يك بانك اطلاعاتی را نيز بدين شكل در cache قرار داد تا بتوان از آن برای پاسخ به ساير سرويس گيرندگان استفاده نمود ؟ آيا می توان يك سيستم فيلترينگ را بر اساس داده های cache شده پياده سازی نمود بگونه ای كه متناسب با خواسته كاربر بخشی از داده cache شده در اختيار وی قرار داده شود ؟ اجازه دهيد با بررسی يك مثال كاربردی به سوالات فوق پاسخ دهيم .
مثال : ايجاد caching با قابليت مشاهده چندين view از داده
در اين مثال اطلاعات مورد نظر از يك بانك اطلاعاتی ( به عنوان نمونه Northwind ) بازيابی و پس از ذخيره در يك DataSet در يك Gridview نمايش داده می شود . DataSet در cache ذخيره می گردد تا در آينده و قبل از اتمام تاريخ اعتبار آن بتوان از تمام و يا بخشی از اطلاعات آن متناسب با خواسته كاربر استفاده نمود .
خروجی صفحه وب بر اساس خواسته كاربر و به صورت پويا ايجاد می گردد . در واقع ، كاربر است كه مشخص می كند در خروجی قصد مشاهده چه نوع اطلاعاتی را دارد . خروجی برنامه فوق در چندين ستون مختلف می تواند نمايش داده شود . كاربر با انتخاب يك و يا چندين ستون نظر خود را خصوص نحوه نمايش خروجی مشخص می نمايد .

توضيحات برنامه :

• DataSet از طريق يك تابع اختصاصی و به صورت زير ايجاد می گردد .

 

ايجاد DataSetبه كمك يك تابع اختصاصی

Function RetrieveData() As DataSet
  Dim connectionString As String = _
        WebConfigurationManager.ConnectionStrings("NORTHWNDConnectionString").ConnectionString
  Dim SQLSelect As String = "SELECT * FROM Customers"
  Dim con As New SqlConnection(connectionString)
  Dim cmd As New SqlCommand(SQLSelect, con)
  Dim adapter As New SqlDataAdapter(cmd)
  Dim ds As New DataSet()
  Try
    con.Open()
   adapter.Fill(ds, "Customers")
  Finally
    con.Close()
  End Try

Return ds
End Function

• در اولين مرتبه ای كه صفحه load می گردد ، ليستی از ستون ها توسط يك كنترل CheckBoxList با نام chckColumns در خروجی و به منظور دريافت نقطه نظرات كاربر نمايش داده می شود . بدين منظور از كد زير در روتين page_load استفاده شده است .

نمايش ليستی از ستون ها توسط يك كنترل CheckBoxList

chkColumns.DataSource = ds.Tables(0).Columns
chkColumns.DataMember = "Item"
chkColumns.DataBind()

• Dataset به مدت دو دقيقه كه توسط پارامتر sliding expiration مشخص شده است در cache قرار می گيرد . ذخيره Dataset در Cache در زمان ايجاد DataSet و از طريق روتين GetDataSet و به كمك متد Insert شی cache انجام می شود .

ذخيره DataSetدر cacheبه مدت 2 دقيقه

Cache.Insert("DataSet", ds, Nothing, DateTime.MaxValue,TimeSpan.FromMinutes(2))

• پس از كليك بر روی دكمه " فيلتر و نمايش اطلاعات " ، در ابتدا سعی می گردد كه DataSet از طريق cache بازيابی گردد ( استفاده از روتين GetDataSet ) . در صورتی كه صفحه نتواند DataSet را از cache بازيابی نمايد ، تابع RetrieveData فراخوانده می شود تا پس از توليد DataSet در ادامه بتوان آن را به cache اضافه نمود .
برای آگاهی كاربران منبع ارائه اطلاعات نيز در خروجی نمايش داده می شود ( ايجاد و ذخيره اطلاعات در cache و يا بازيابی اطلاعات از cache ) .

بازيابی DataSetاز cacheو يا ايجاد و ذخيره مجدد DataSetدر cache

Function GetDataSet() As DataSet
   Dim dsPubs As DataSet
    If Cache("Titles") Is Nothing Then
      dsPubs = RetrieveData()
      Cache.Insert("Titles", dsPubs, Nothing, DateTime.MaxValue, TimeSpan.FromMinutes(2))
      lblCacheStatus.Text = "ايجاد اطلاعات و ذخيره آنها درcache"
   Else
     dsPubs = CType(Cache("Titles"), DataSet)
      lblCacheStatus.Text = "بازيابی اطلاعاتازcache"
  End If
  Return dsPubs
 End Function

• برای ارائه يك grid قابل پيكربندی ، كد موجود در روتين cmdApply_Click در DataTable حركت و تمامی ستون هائی را كه كاربر جهت عدم نمايش در خروجی فيلتر نموده است ، از grid حذف می نمايد ( قبل از حذف ستون هائی از DataSet يك نسخه ثانويه از آن ايجاد می گردد ) .
در اين رابطه شايد بتوان از گزينه های متعدد ديگری استفاده نمود ولی استراتژی بكار گرفته شده در مثال فوق بيانگر يك حقيقت مهم در خصوص caching است . زمانی كه يك آيتم بازيابی می گردد در واقع يك مرجع به شی cache شده بازيابی شده است و اگر شی تغيير يابد ، در حقيقت آيتم cache شده تغيير يافته است .

فيلترينگ داده بر اساس خواسته كاربر جهت نمايش در Gridview

Sub cmdApply_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdApply.Click
   Dim ds As DataSet = GetDataSet()
   ds = ds.Copy()
 
  For Each item As ListItem In chkColumns.Items
    If item.Selected Then
       ds.Tables(0).Columns.Remove(item.Text)
   End If
  Next
  gridPubs.DataSource = ds.Tables(0)
  gridPubs.DataBind()
End Sub

كد مثال فوق بطور كامل در جدول زير نشان داده شده است .

ذخيره داده بازيابی شده از بانك اطلاعاتی در cache
و استفاده از آن بر اساس خواسته كاربر قبل از اتمام تاريخ اعتبار آن

<%@ Page Language="VB" Culture="fa-IR" UICulture="fa-IR" %>
<%@ import Namespace="system.Data" %>
<%@ import Namespace="system.Data.SqlClient" %>
<%@ Import Namespace="System.Web.Configuration" %>

<script runat="server">

 Sub cmdApply_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdApply.Click
   Dim ds As DataSet = GetDataSet()
   ds = ds.Copy()
 
  For Each item As ListItem In chkColumns.Items
    If item.Selected Then
       ds.Tables(0).Columns.Remove(item.Text)
   End If
  Next
  gridPubs.DataSource = ds.Tables(0)
  gridPubs.DataBind()
End Sub

'=======================================================================
 Function GetDataSet() As DataSet
   Dim dsPubs As DataSet
    If Cache("Titles") Is Nothing Then
      dsPubs = RetrieveData()
      Cache.Insert("Titles", dsPubs, Nothing, DateTime.MaxValue, TimeSpan.FromMinutes(2))
      lblCacheStatus.Text = "ايجاد اطلاعات و ذخيره آنها درcache"
   Else
     dsPubs = CType(Cache("Titles"), DataSet)
      lblCacheStatus.Text = "بازيابی اطلاعاتازcache"
  End If
  Return dsPubs
 End Function

'=======================================================================
 Function RetrieveData() As DataSet
  Dim connectionString As String = _
        WebConfigurationManager.ConnectionStrings("NORTHWNDConnectionString").ConnectionString
  Dim SQLSelect As String = "SELECT * FROM Customers"
  Dim con As New SqlConnection(connectionString)
  Dim cmd As New SqlCommand(SQLSelect, con)
  Dim adapter As New SqlDataAdapter(cmd)
  Dim ds As New DataSet()
  Try
    con.Open()
   adapter.Fill(ds, "Customers")
  Finally
    con.Close()
  End Try

Return ds
End Function

'======================================================================
 Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Me.IsPostBack Then
  Cache.Remove("Titles")
  Dim dsPubs As DataSet = GetDataSet()
  chkColumns.DataSource = dsPubs.Tables(0).Columns
  chkColumns.DataMember = "Item"
  chkColumns.DataBind()
  End If
End Sub
</script>

'==============================================================
<html xmlns="http://www.w3.org/1999/xhtml" dir="rtl" >
  <head runat="server">
    <title>Untitled Page</title>
  </head>
  <body style="font-family: Tahoma">
   <form id="form1" runat="server">
    <div id="DIV1">
      <asp:label id="Label1" runat="server">ستون هائی راكه قصد نمايش آنها در خروجی را نداريد ، انتخاب نمائيد:
      </asp:label>
      <asp:checkboxlist id="chkColumns" runat="server" RepeatColumns="2"></asp:checkboxlist><br />
      <asp:button id="cmdApply" runat="server" Width="144px" Text="فيلتر و نمايشاطلاعات"
              Font-Names="Tahoma" ></asp:button><br />
      <asp:Label ID="lblCacheStatus" runat="server">Hide Columns:</asp:Label>
      <hr />
      <asp:gridview id="gridPubs" runat="server" Width="384px" Height="120px"
             BorderColor="#CC9966" BorderStyle="None" 
             BorderWidth="1px" BackColor="White" CellPadding="4"
            Font-Size="X-Small" Font-Names="Verdana" EnableViewState="False">
     <RowStyle ForeColor="#330099" BackColor="White" HorizontalAlign="Left"></RowStyle>
     <HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
    </asp:gridview>
   </div>
  </form>
 </body>
</html>

كنترل های ObjectDataSource ، SqlDataSource و XmlDataSource بطور ذاتی از امكانات caching حمايت می نمايند . استفاده از caching به همراه كنترل های فوق اكيدا" توصيه می گردد چراكه برخلاف كد سفارشی نوشته شده توسط پياده كنندگان به منظور دستيابی داده ، كنترل های منبع داده همواره در هر postback يك query را بر روی منبع داده اجراء می نمايند .
كنترل های فوق ، همچنين برای هر كنترل نسبت دهی يك query در سطح منبع داده را اجراء می نمايند . به عنوان نمونه اگر در يك صفحه از سه كنترل نسبت دهی داده در ارتباط با يك منبع داده يكسان استفاده شده باشد ، سه query مجزاء بر روی بانك اطلاعاتی و قبل از تفسير و ارسال صفحه برای سرويس گيرنده ، اجراء خواهد شد . بديهی است حتی با استفاده از امكانات اندك caching به همراه كنترل های منبع داده ، شاهد بهبود چشمگير كارآئی و كاهش load عملياتی در سمت سرويس دهنده خواهيم بود .
با اين كه تعداد زيادی از كنترل های منبع داده از caching حمايت می نمايند ، ولی ويژگی فوق به عنوان يك ضرورت در بكارگيری كنترل های منبع داده مطرح نمی گردد و می توان از كنترل های منبع داده ئی كه از پتانسيل caching حمايت نمی نمايند نيز استفاده كرد .
برای حمايت از caching كنترل های ObjectDataSource ، SqlDataSource و XmlDataSource از خصلت های مشابهی استفاده می نمايند . در جدول 1 ، خصلت های فوق نشان داده شده اند .

خصلت

عملكرد

 EnableCaching

 با نسبت دهی مقدار Trueبه خصلت فوق ، پتانسيل cachingفعال می گردد . مقدار پيش فرض خصلت فوق Falseدر نظر گرفته می شود . 

CacheExpirationPolicy

 سياست و يا استراتژی زمان اتمام تاريخ اعتبار cacheرا مشخص می نمايد . بر اين اساس می توان مقدار خصلت فوق را ثابت و يا متغير ( مدت زمان بين دو درخواست متوالی ) در نظر گرفت . 

 CacheDuration

 مدت زمان cachingآيتم مورد نظر در cacheرا بر حسب ثانيه  مشخص می نمايد .


CacheKeyDependency
و
SqlCacheDependency

 امكان ايجاد يك وابستگی بين يك آيتم cacheشده با آيتم ديگر در data cache  ( با استفاده از CacheKeyDependency) و يا يك جدول بانك اطلاعاتی(با استفاده از SqlCacheDependency) را فراهم می نمايد .  

جدول 1 : خصلت های caching كنترل های منبع داده




نظرات کاربران
ارسال نظر
با تشکر، نظر شما پس از بررسی و تایید در سایت قرار خواهد گرفت.
متاسفانه در برقراری ارتباط خطایی رخ داده. لطفاً دوباره تلاش کنید.
مقالات مرتبط