我已经实现了一个简单的基于文件的自定义OutputCacheProvider根据我在互联网上找到的示例。ASP.Net OutputCacheProvider奇怪的行为
的代码如下:
using System;
using System.Configuration;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace SimpleCachedProvider
{
public class FileCacheProvider : OutputCacheProvider {
private string _cachePath;
void WriteToFile(String filename, String contents) {
FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter w = new StreamWriter(fs, System.Text.Encoding.GetEncoding(1253));
w.BaseStream.Seek(0, SeekOrigin.Begin);
w.BaseStream.SetLength(0);
w.Write(contents);
w.Flush();
w.Close();
}
void AppendToFile(String filename, String contents) {
if (contents.ToLower().IndexOf("ss2.aspx") >= 0 || contents.ToLower().IndexOf("default.aspx") >= 0) {
FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter w = new StreamWriter(fs, System.Text.Encoding.GetEncoding(1253));
w.BaseStream.Seek(0, SeekOrigin.End);
w.Write(contents);
w.Flush();
w.Close();
}
}
private string CachePath {
get {
if (!string.IsNullOrEmpty(_cachePath))
return _cachePath;
_cachePath = ConfigurationManager.AppSettings["OutputCachePath"];
var context = HttpContext.Current;
if (context != null) {
_cachePath = context.Server.MapPath(_cachePath);
if (!_cachePath.EndsWith("\\"))
_cachePath += "\\";
}
return _cachePath;
}
}
public override object Add(string key, object entry, DateTime utcExpiry) {
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ")\r\n");
if (File.Exists(path)) {
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ") already exists. Will be returned.\r\n");
return entry;
}
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ") does not exists. Will be created.\r\n");
using (var file = File.OpenWrite(path)) {
var item = new CacheItem { Expires = utcExpiry, Item = entry };
var formatter = new BinaryFormatter();
formatter.Serialize(file, item);
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ") saved to disk.\r\n");
}
return entry;
}
public override void Set(string key, object entry, DateTime utcExpiry) {
var item = new CacheItem { Expires = utcExpiry, Item = entry };
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "Set: " + key + " (" + path + ") requested.\r\n");
using (var file = File.OpenWrite(path)) {
var formatter = new BinaryFormatter();
formatter.Serialize(file, item);
AppendToFile(CachePath + "info.txt", "Set: " + key + " (" + path + "): " + utcExpiry.ToLocalTime().ToString("dd/MM/yyyy HH:mm:ss") + " saved to disk.\r\n");
}
}
public override object Get(string key) {
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "Get: Querying " + key + " (" + path + ")\r\n");
if (!File.Exists(path)) {
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") not found.\r\n");
return null;
}
CacheItem item = null;
using (var file = File.OpenRead(path)) {
var formatter = new BinaryFormatter();
item = (CacheItem)formatter.Deserialize(file);
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") retrieved.\r\n");
}
if (item == null || item.Expires <= DateTime.Now.ToUniversalTime()) {
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") deleted due to expiration.\r\n");
Remove(key);
return null;
}
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") retrieved and used\r\n");
return item.Item;
}
public override void Remove(string key) {
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "Remove: " + key + " (" + path + ") requested.\r\n");
if (File.Exists(path)) {
AppendToFile(CachePath + "info.txt", "Remove: " + key + " (" + path + ") executed.\r\n");
File.Delete(path);
}
}
private string GetPathFromKey(string key) {
return CachePath + MD5(key) + ".txt";
}
private string MD5(string s) {
MD5CryptoServiceProvider provider;
provider = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(s);
StringBuilder builder = new StringBuilder();
bytes = provider.ComputeHash(bytes);
foreach (byte b in bytes)
builder.Append(b.ToString("x2").ToLower());
return builder.ToString();
}
}
}
我已经然后创建一个.aspx与头
<%@ OutputCache Duration="3600" Location="Server" VaryByParam="*" %>
我已经改变了默认的输出缓存提供给我的web.config我的。
奇怪的现象是页面没有被缓存。相反,这是我的调试信息的示例输出。看来:
- 页距离Tha缓存中检索和
- 正确的ASP.Net后送回ASP.Net调用remove()方法来我的页面
最后ASP.Net调用集()和页面更新 - 没有有效的缓存
得到:查询A2/ss2.aspx(C:\ eShopKey \ ASP.Net \店\ myshoe_dev \缓存\ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)
获取:a2/ss2.aspx(C:\ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)。
得到:A2/ss2.aspx(C:\ eShopKey \ ASP.Net \商店\ myshoe_dev \缓存\ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)检索和使用
获取:查询A2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \商店\ myshoe_dev \缓存\ 3e72454ab3f36e4cfe3964e5063be622.txt)
得到:A2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \商店\ myshoe_dev \缓存\ 3e72454ab3f36e4cfe3964e5063be622.txt)检索。
得到:A2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \商店\ myshoe_dev \缓存\ 3e72454ab3f36e4cfe3964e5063be622.txt)检索和使用
卸下:A2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt)请求。
删除:a2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt)执行。
ADD:A2/ss2.aspx(C:\ eShopKey \ ASP.Net \商店\ myshoe_dev \缓存\ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)
ADD:A2/ss2.aspx(C:\ eShopKey \ ASP。 Net \ Shops \ myshoe_dev \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)已经存在。将被退回。
Set:a2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt)请求。
Set:a2/ss2.aspxHQFCNmycustom2VDE(C:\ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt):30/05/2012 15:07:27保存到磁盘。
所以我的问题:
- 为什么ASP.Net保持无效我的网页?
- 当ASP.Net调用Remove()和Set()方法时?我还没有找到任何有关这方面的信息。
- 如果我重命名页面并使用此变体缓存起作用!这很奇怪。
需要注意的是,如果我使用默认ASP.Net outputcacheprovider缓存按预期工作。
我发现了是怎么回事,但无法修复:
比方说,我打开网页:http://www.mydomain.com/mypage.aspx?param1=1
ASP.Net发送2个连续的GET请求我OutputCacheProvider:
- 一个用于页面mypage.aspx
- 另一个用于相同的页面但包含查询字符串参数
在我看来,第一个请求与第二个请求有某种关系,比如头部。
只要我连续调用相同的页面,使用相同的查询字符串,缓存按预期工作。
如果我接下来的页面:http://www.mydomain.com/mypage.aspx?param1=2
那么同样的,2步GET序列,被初始化。 ASP.Net发送2个GET请求,一个用于没有参数的页面和一个带有参数的页面。
然后在缓存中找到第一个GET请求(对于没有参数的页面)并返回到ASP.Net。但不知何故与第二个无关。它与调用的第一个变体(param1 = 1)有关。
因此,如果第二个请求之前被缓存,ASP.Net认为缓存页面无效并再次询问是否添加/设置。
总而言之,您似乎可以在给定时刻只有一个页面变化的缓存。之前所有的变化都将失效,因为页面将被再次调用其他参数。
由于ASP.NET使用相同的密钥来检索它,所以没有办法检查第一个GET请求与什么相关。
所以我的新问题:
- 为什么ASP.Net发送2个请求每一页的自定义输出缓存提供?有人知道吗?
- 我如何克服这种奇怪的行为?
- AspNetInternalProvider是否具有相同的行为?
那么为了让OutputCacheProvider按预期工作,我必须采取哪些必要的操作?请注意,我在Internet上找到的每个自定义OutputCacheProvider都会遇到同样的问题。 – zissop