کش کردن یک صفحه وب به مفهوم ذخیره کردن این صفحه بر روی حافظه سرور هست بنابراین یک بار در زمان مشخص مثلا ۱ دقیقه این صفحه توسط سرور پردازش شده و به طور پیش فرض در حافظه سرور (میتوان روی هارد و یا حتی دیتابیس هم ذخیره کرد) باقی میماند و بعد از این تا ۱ دقیقه هر درخواستی که برای اون صفحه بشه دیگه سرور درگیر پردازش نمیشه و صفحه آماده از حافظه به کلاینت فرستاده میشه. بعد از یک دقیقه دوباره با اولین درخواست، این صفحه ایجاد شده و دوباره همین روند ادامه پیده میکنه.
مشکلی که ممکن هست پیش بیاد اینه که در صفحهای که Cache کردیم، قسمتی وجود داره که نیاز داریم همیشه به روز باشه و در هر درخواستی که از این صفحه به سرور فرستاده میشه، قسمتی از این صفحه بدون کش شدن، به روز رسانی بشه. مثلا در قسمتی از صفحه قرار هست تغییرات قیمت رو در شرایطی داشته باشیم که این قیمت ها مثلا هر یک ثانیه تغییر میکنند بنابراین هر بار که صفحه درخواست میشه تقریبا میشه گفت که قیمتهای جدیدی برای نشون دادن هست.
حالا اگر تمام صفحه کش شده باشه به مدت ۵ دقیقه و در این زمان بازدید کننده ای به سایت بیاد و یا این صفحه را refresh کنه، همون قیمت های ذخیره شده رو میبینه و آپدیت های جدید رو از دست میده تا زمانی که دوره کش (Cache Duration) به پایان برسه و صفحه دوباره کش بشه. در این حالت نیاز داریم که این یک قسمت در سرور کش نشود و هر درخواستی که به این صفحه میرسه، تمام صفحه از کش خونده بشه به جر این بخشی که تعیین شده و قرار هست قیمت ها رو هر دفعه از جایی بخونه و هربار کد مربوط به این قسمت باید دوباره پردازش بشه.
در واقع دلیل اینکه به این روش کش کردن، دونات گفته میشه همین هست که مانند دونات که در وسط اون قسمتی جدا و خالی هست، در وب هم میخواهیم قسمتی از صفحه رو جدا کرده و اون رو طوری که میخواهیم نشان دهیم جدای از بقیه صفحه که بدون پردازش، از کش سرور خوانده میشود.
برای این کار در ASP.Net باید از کنترل Substitution استفاده کنید. این کنترل نام یک تابع را از شما میگیرد که شما باید این تابع را در کد خودتون تعریف کرده باشید و ۳ نکته زیر حتما رعایت شده باشند:
– این تابع باید به صورت Static در سی شارپ یا Shared در وی بی دات نت باشد.
– این تابع باید یک مقدار String برگشت دهد.
– این تابع باید httpcontext را به عنوان ورودی داشته باشد.
در مثال زیر، زمان کش شدن برای کل صفحه ۶۰ ثانیه تنظیم شده. بنابراین لیبلی که قرار هست در هر page load زمان رو نشون بده، تنها هر ۶۰ ثانیه زمان جدید رو نشون میده و در طول یک دقیقه، ساعتی رو نشون میده که بار اول اون زمان در سرور کش شده بود. در کنار این label یک کنترل sabstitution وجود داره که توسط تابع GetTime زمان رو در هر بار Refresh بدون توجه به کش بودن، در صفحه نشون میده.
<%@ Page Language="VB" %>
<%@ OutputCache Duration="60" VaryByParam="None" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
cachedlbl.Text = Now.ToLongTimeString()
End Sub
Shared Function GetTime(ByVal context As HttpContext) As String
Return Now.ToLongTimeString()
End Function
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Donut Caching</title>
</head>
<body>
<form id="form1" runat="server">
<p>
Cached:<br />
<asp:Label runat="server" ID="cachedlbl"></asp:Label>
</p>
<p>
Not-Cached:<br />
<asp:Substitution runat="server" ID="subcontrol"
MethodName="GetTime" />
</p>
</form>
</body>
</html>
محدودیتی که sunstitution control داره اینه که شما فقط میتونید خروجی متنی داشته باشید یعنی html و جاوااسکریپت رو جایگزین کنید در صفحه و امکان استفاده از کنترلهای ASP.Net نیست. مثلا اگر قرار هست قسمتی که LoginView وجود داره رو از کل صفحه کش شده جدا کنید، باید با کد نویسی این کار رو انجام بدید و به نسبت اینکه بازدیدکننده وارد سایت شده یا نه، متن و html مورد نظر رو در تابع پاس داده شده به substitutoin خروجی بگیرید. شما دیگه امکان استفاده از تگ <asp:loginview runat=server> رو ندارید.