出力キャッシュ(すなわち静的HTML)ASP.NET.NET 4.0までメモリベースでした。 つまり、サイトに大量のキャッシュがある場合、ローカルメモリを消費しやすくなります。 そして、 の助けを借りて 。 .NET 4.0のOutputCacheProviderでは、独自のキャッシュを作成するためのいくつかのオプションがあります。 例えば、HTML出力キャッシュをmemcached分散クラスタサーバーやMongoDB(よく使われるドキュメント指向データベース、この http://msdn.microsoft.com/zh-cn/magazine/gg650661.aspx を参照してください)に保存できます。 もちろん、キャッシュをハードドライブにファイルとして保存することもでき、これはスケーラビリティを考えると最も安価な方法です。この記事ではカスタムファイルキャッシュの構築方法について書いています。
1:OutputCacheProvider OutputCacheProviderは抽象的な基底クラスで、その4つのメソッドをオーバーライドする必要があります。 指定されたアイテムを出力キャッシュに挿入する方法を追加してください。 getメソッドは、出力キャッシュ内の指定されたアイテムへの参照を返します。 指定されたアイテムを出力キャッシュから削除するためのremove メソッドです。 メソッドを設定し、指定されたアイテムを出力キャッシュに挿入し、キャッシュされている場合は上書きします。
2: 自分だけのファイルキャッシュ処理クラスを作成する 型はFileCacheProviderで、コードは以下の通りです:
- public class FileCacheProvider : OutputCacheProvider
- {
- private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
-
- public override void Initialize(string name, NameValueCollection attributes)
- {
- base.Initialize(name, attributes);
- CachePath = HttpContext.Current.Server.MapPath(attributes["cachePath"]);
- }
-
- public override object Add(string key, object entry, DateTime utcExpiry)
- {
- Object obj = Get(key);
- if (obj != null) //这一步很重要
- {
- return obj;
- }
- Set(key,entry,utcExpiry);
- return entry;
- }
-
- public override object Get(string key)
- {
- string path = ConvertKeyToPath(key);
- if (!File.Exists(path))
- {
- return null;
- }
- CacheItem item = null;
- using (FileStream file = File.OpenRead(path))
- {
- var formatter = new BinaryFormatter();
- item = (CacheItem)formatter.Deserialize(file);
- }
-
- if (item.ExpiryDate <= DateTime.Now.ToUniversalTime())
- {
- log.Info(item.ExpiryDate + "*" + key);
- Remove(key);
- return null;
- }
- return item.Item;
- }
-
-
- public override void Set(string key, object entry, DateTime utcExpiry)
- {
- CacheItem item = new CacheItem(entry, utcExpiry);
- string path = ConvertKeyToPath(key);
- using (FileStream file = File.OpenWrite(path))
- {
- BinaryFormatter formatter = new BinaryFormatter();
- formatter.Serialize(file, item);
- }
- }
-
- public override void Remove(string key)
- {
- string path = ConvertKeyToPath(key);
- if (File.Exists(path))
- File.Delete(path);
- }
-
- public string CachePath
- {
- get;
- set;
- }
-
- private string ConvertKeyToPath(string key)
- {
- string file = key.Replace('/', '-');
- file += ".txt";
- return Path.Combine(CachePath, file);
- }
- }
-
- [Serializable]
- public class CacheItem
- {
- public DateTime ExpiryDate;
- public object Item;
-
- public CacheItem(object entry, DateTime utcExpiry)
- {
- Item = entry;
- ExpiryDate = utcExpiry;
- }
- }
コードをコピーします 特に注意が必要な場所が2つあります。 Addメソッドでは、この方法で処理しなければならない条件付き判断があり、そうでなければキャッシュ機構が最初の結果をキャッシュし、期限切れ後にキャッシュが期限切れとなり再構築されません。 例のプログラムでは、キャッシュをキャッシュディレクトリに単純に置きますが、実際のプロジェクトではキャッシュページ数が数千ページになることを考慮すれば、ディレクトリ分類を行う必要があります。そうしないとキャッシュファイルの見つけや読み込みが効率のボトルネックとなり、CPUを消耗させてしまいます。
3: 設定ファイル
Web.configでキャッシュハンドラをカスタムFileCacheProviderに設定する必要があります。つまり、FileCacheProviderの下にノードを追加することです:- <caching>
- <outputCache defaultProvider="FileCache">
- <providers>
- <add name="FileCache" type="MvcApplication2.Common.FileCacheProvider" cachePath="~/Cache" />
- </providers>
- </outputCache>
- </caching>
コードをコピーします
4: キャッシュの使用
MVCの制御で使うと仮定します(ASP.NET ページで使いたい場合は、page@OutputCacheに<%を含めるとVaryByParam="none" Duration="10" %>)、Indexは出力キャッシュされておらず、Index2は10秒間出力キャッシュされています。
- public class HomeController : Controller
- {
- private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
- static string s_conn = "Data Source=192.168.0.77;Initial Catalog=luminjidb;User Id=sa;Password=sa;";
- public ActionResult Index()
- {
- using (DataSet ds = Common.SqlHelper.ExecuteDataset(s_conn, CommandType.Text, "select top 1* from NameTb a, DepTb b where a.DepID = b.ID ORDER BY NEWID()"))
- {
- ViewBag.Message = ds.Tables[0].Rows[0]["name"].ToString();
- }
- return View();
- }
-
- [OutputCache(Duration = 10, VaryByParam = "none")]
- public ActionResult Index2()
- {
- using (DataSet ds = Common.SqlHelper.ExecuteDataset(s_conn, CommandType.Text, "select top 1* from NameTb a, DepTb b where a.DepID = b.ID ORDER BY NEWID()"))
- {
- ViewBag.Message = ds.Tables[0].Rows[0]["name"].ToString();
- }
- return View();
- }
- }
コードをコピーします 5: 効果の確認 上記のコードはIndex2にアクセスすると、Cacheフォルダ内にキャッシュファイルを生成します。以下の通りです。
次に、出力キャッシュと出力キャッシュのパフォーマンス比較を評価し、100人のユーザーから100件の同時リクエストをシミュレートしたことを次のように示します。
|