У меня есть простой пользовательский 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 в шахте.
Странное поведение заключается в том, что страница не кэшируется. Вместо этого это образец вывода из моей отладочной информации. Кажется, что:
- страница извлекается из кэша тха и отправлен обратно в ASP.Net
- Сразу после этого ASP.Net вызывает метод Remove() на мою страницу
Наконец ASP.Net не требует установки() и страница обновляется - не эффективное кэширование
Get: a2 Запросы/ss2.aspx (C: \ eShopKey \ ASP.Net \ Магазины \ myshoe_dev \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)
Get : a2/ss2.aspx (C: \ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt).
Get: a2/ss2.aspx (C: \ eShopKey \ ASP.Net \ Магазины \ myshoe_dev \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt) извлекаются и используются
Get: a2/Запрос информации ss2.aspxHQFCNmycustom2VDE (C: \ eShopKey \ ASP.Net \ Магазины \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt)
Get: a2/ss2.aspxHQFCNmycustom2VDE (C: \ eShopKey \ ASP.Net \ Магазины \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt) извлекается.
Get: a2/ss2.aspxHQFCNmycustom2VDE (C: \ eShopKey \ ASP.Net \ Магазины \ myshoe_dev \ Cache \ 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 \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt)
ADD: a2/ss2.aspx (C: \ eShopKey \ ASP. Net \ Shops \ myshoe_dev \ Cache \ 7394fd15241e5b7f5c437ddf28dcd0e5.txt) уже существует. Будет возвращено.
Комплект: a2/ss2.aspxHQFCNmycustom2VDE (C: \ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt).
Set: a2/ss2.aspxHQFCNmycustom2VDE (C: \ eShopKey \ ASP.Net \ Магазины \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt): 30/05/2012 15:07:27 сохраняется на диске.
Так что мои вопросы:
- Почему ASP.Net держит недействительности мою страницу?
- Когда методы Remove() и Set() вызывается ASP.Net? Я не нашел никакой информации об этом.
- Если я переименую страницу и использую этот вариант кеширования! Это совершенно странно.
Обратите внимание, что если я использую по умолчанию ASP.Net, то кэширование outputcacheprovider работает, как ожидалось.
Я нашел то, что происходит, но не в состоянии исправить:
Допустим, я открываю страницу: http://www.mydomain.com/mypage.aspx?param1=1
ASP.Net посылает 2 последовательных запросов GET к моему OutputCacheProvider:
- один для страницы mypage.aspx
- другой для той же страницы, но с параметрами querystring прилагается
Мне кажется, что первый запрос каким-то образом связан со вторым, как с заголовком.
Как только я вызываю последовательно одну и ту же страницу с тем же запросом, кеширование работает как ожидалось.
Если я предоставляю слово страницы: http://www.mydomain.com/mypage.aspx?param1=2
то же самое, 2 шаг GET последовательность инициализации. ASP.Net отправляет 2 запроса GET, один для страницы без параметров и один с параметрами.
Первый запрос GET (для страницы без параметров) затем находится в кеше и возвращается обратно в ASP.Net. Но почему-то не связано со вторым. Это связано с первой вариацией вызова (param1 = 1).
Итак, тем не менее, если второй запрос был кэширован раньше, ASP.Net считает, что кэшированная страница недействительна и снова запрашивает команду add/set.
Подводя итог, кажется, что вы можете иметь только один вариант страницы в кеше в данный момент. Все предыдущие варианты с сохранением недействительны, так как страница снова будет вызываться с другими параметрами.
Невозможно проверить, с чем связан первый запрос GET, поскольку ASP.NET использует тот же ключ для его получения.
Так мои новые вопросы:
- Почему ASP.Net посылает 2 запросы на каждой странице поставщика кэша пользовательского вывода? Кто-нибудь знает?
- Как я могу преодолеть это странное поведение?
- Является ли AspNetInternalProvider одинаковым поведением?
Итак, каковы требуемые действия, которые я должен предпринять, чтобы OutputCacheProvider работал так, как ожидалось? Обратите внимание, что каждый отдельный пользовательский OutputCacheProvider, который я нашел в Интернете, страдает от одной и той же проблемы. – zissop