۱۳۸۸/۰۲/۰۶

كش كردن اطلاعات غير پويا در ASP.Net - قسمت دوم


قسمت قبل به IIS7‌ اختصاص داشت كه شايد براي خيلي‌ها كاربرد نداشته باشد خصوصا اينكه برنامه نويس‌ها ترجيح مي‌دهند به روش‌هايي روي بياورند كه كمتر نياز به دخالت مدير سرور داشته باشد؛ يا زمانيكه سايت شما بر روي يك هاست اينترنتي قرار گرفته است عملا شايد دسترسي خاصي به تنظيمات IIS نداشته باشيد (مگر اينكه يك هاست اختصاصي را تهيه كنيد).
براي IIS6 و ماقبل از آن و حتي بعد از آن!، حداقل دو روش براي كش كردن اطلاعات استاتيك وجود دارد:

الف) استفاده از web resources معرفي شده در ASP.Net 2.0 به بعد
در مورد نحوه‌ي تعريف و بكارگيري web resources مي‌توان به مقاله "تبديل پلاگين‌هاي jQuery‌ به كنترل‌هاي ASP.Net" رجوع كرد.


همانطور كه در شكل فوق نيز ملاحظه مي‌كنيد، هدر مربوط به مدت زمان منقضي شدن كش سمت كلاينت يك web resource توسط موتور ASP.Net به صورت خودكار به سال 2010 تنظيم شده است و اين مقدار خالي نيست.

ب) افزودن اين هدر به صورت دستي

براي اين منظور بايد در نحوه‌ي ارائه فايل‌هاي استاتيك دخالت كنيم و اين‌كار را با استفاده از يك generic handler مي‌توان انجام داد.


كد اين generic handler مي‌تواند به صورت زير باشد:

using System;
using System.IO;
using System.Web;
using System.Web.Services;
using System.Reflection;

namespace test1
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class cache : IHttpHandler
{

private static void cacheIt(TimeSpan duration)
{
HttpCachePolicy cache = HttpContext.Current.Response.Cache;

FieldInfo maxAgeField = cache.GetType().GetField("_maxAge", BindingFlags.Instance | BindingFlags.NonPublic);
maxAgeField.SetValue(cache, duration);

cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(DateTime.Now.Add(duration));
cache.SetMaxAge(duration);
cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
}

public void ProcessRequest(HttpContext context)
{
string file = context.Request.QueryString["file"];
if (string.IsNullOrEmpty(file))
{
return;
}

string contetType = context.Request.QueryString["contetType"];
if (string.IsNullOrEmpty(contetType))
{
return;
}

context.Response.Write(File.ReadAllText(context.Server.MapPath(file)));

//Set the content type
context.Response.ContentType = contetType;

// Cache the resource for 30 Days
cacheIt(TimeSpan.FromDays(30));
}

public bool IsReusable
{
get
{
return false;
}
}
}
}
توضيحات:
اين generic handler دو كوئري استرينگ را دريافت مي‌كند؛ file جهت دريافت نام فايل و contetType جهت مشخص سازي نوع محتوايي كه بايد سرو شود؛ مثلا جاوا اسكريپت يا استايل شيت و امثال آن. سپس زمانيكه محتوا را Response.Write مي‌كند، هدر مربوط به كش شدن آن‌را نيز به 30 روز تنظيم مي‌نمايد.
تابع مربوط به كش كردن اطلاعات از مقاله ASP.NET Ajax Under-the-hood Secrets استخراج شد.

روش استفاده در مورد فايل‌هاي CSS
بجاي تعريف يك فايل CSS در صفحه، به صورت استاندارد، اكنون تعريف متداول را به صورت زير اصلاح كنيد:

<link type="text/css" href="cache.ashx?v=1&file=site.css&contetType=text/css" rel="Stylesheet" />
هر زمانيكه كه فايل site.css درخواست مي‌شود، بايد از فيلتر ما عبور كند و سپس ارائه گردد. در اين حين، هدر مربوط به مدت زمان كش شدن سمت كلاينت به آن اضافه مي‌شود. از كوئري استرينگ مربوط v هم جهت به روز رساني‌هاي بعدي استفاده مي‌شود تا اگر تغييري را اعمال كرديم، كلاينت حتما با توجه به آدرس جديد، محتويات جديد را يكبار ديگر دريافت كند. (مرورگر آدرس‌هاي مشابه را در صورتيكه هدر مربوط به كش شدن آن‌ها تنظيم شده باشد، از كش خواهد خواند و كاري به آخرين تغييرات شما در سرور ندارد)

روش استفاده در مورد فايل‌هاي JS
<script type="text/javascript" src="cache.ashx?v=1&file=js/jquery-1.3.2.min.js&contetType=application/x-javascript"></script>
اكنون اگر سايت را مجددا با افزونه YSlow بررسي كنيم، مي‌توان اين هدر جديد را مشاهده كرد: