인터넷에서 찾은 샘플을 기반으로 간단한 파일 기반 사용자 지정 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();
}
}
}
가 그때 난 내 내 Web.config의에 기본 출력 캐시 공급자를 변경 한 헤더
<%@ OutputCache Duration="3600" Location="Server" VaryByParam="*" %>
와 함께 .ASPX을 만들었습니다.
이상한 동작은 페이지가 캐시되지 않는다는 것입니다. 대신 이것은 디버깅 정보의 샘플 출력입니다.
- 페이지가 그쪽으로 캐시에서 검색 및
- 오른쪽이 ASP.Net 후 ASP.Net로 다시 전송 내 페이지
마지막으로 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)가 이미 존재합니다. 반환됩니다.
집합 : a2/ss2.aspxHQFCNmycustom2VDE (C : \ eShopKey \ ASP.Net \ Shops \ myshoe_dev \ Cache \ 3e72454ab3f36e4cfe3964e5063be622.txt)가 요청되었습니다.
설정 : ss2.aspxHQFCNmycustom2VDE/A2 (C : \ eShopKey ASP.Net \ 상점 \ myshoe_dev \ 캐시 \ 3e72454ab3f36e4cfe3964e5063be622.txt가 \) : 30/05/2012 15시 7분 27초 디스크에 저장.그래서
내 질문 :
- ASP.Net 내 페이지를 무효화 유지 이유는 무엇입니까?
- Remove() 및 Set() 메서드가 ASP.Net에서 호출 될 때? 그것에 관한 정보를 찾지 못했습니다.
- 페이지의 이름을 바꾸고이 변형을 사용하면 캐싱이 작동합니다! 이것은 완전히 이상합니다.
기본 ASP.Net outputcacheprovider 캐싱을 사용하면 캐싱이 예상대로 작동합니다.
나는 계속하지만 문제를 해결 할 수없는 무엇을 발견 :
의 내가 페이지를 열 수 있다고 가정 해 봅시다 :
: http://www.mydomain.com/mypage.aspx?param1=1ASP.Net 내 OutputCacheProvider 2 개 연속 GET 요청을 보냅니다
- 하나에 대한 페이지 mypage.aspx
- 동일한 페이지에 대해 다른 있지만 쿼리 문자열 매개 변수가 첨부 된
첫 번째 요청은 어떻게 든 헤더와 같이 두 번째 요청과 관련이있는 것으로 보입니다.
같은 쿼리 문자열을 사용하여 동일한 페이지를 연속적으로 호출하자마자 예상대로 캐시됩니다. 내가 페이지 옆에 호출하는 경우
: 다음 http://www.mydomain.com/mypage.aspx?param1=2
같은 2 단계 GET 순서는, 초기화됩니다. ASP.Net은 매개 변수가없는 페이지와 매개 변수가있는 페이지에 대해 각각 하나씩 두 개의 GET 요청을 보냅니다.
매개 변수가없는 페이지에 대한 첫 번째 GET 요청은 캐시에서 발견되어 ASP.Net으로 다시 반환됩니다. 그러나 어떻게 든 두 번째 것과 관련이 없습니다. 호출의 첫 번째 변형과 관련이 있습니다 (param1 = 1).
그럼에도 불구하고 두 번째 요청이 이전에 캐시 된 경우 ASP.Net은 캐시 된 페이지가 유효하지 않다고 생각하고 추가/설정을 다시 요청합니다.
요약하면 주어진 순간에 캐시에 대해 페이지의 변형을 한 개만 가질 수 있습니다. 페이지가 다른 매개 변수를 사용하여 다시 호출 될 때 이전의 모든 cahed 변형은 무효화됩니다.
ASP.NET은 동일한 키를 사용하여 검색하기 때문에 첫 번째 GET 요청과 관련이 있는지 확인할 방법이 없습니다.
그래서 내 새로운 질문 : ASP.Net 사용자 지정 출력 캐시 공급자에 모든 페이지에 대한이 개 요청을 보내는 이유는
- ? 아무도 몰라?
- 어떻게이 이상한 행동을 극복 할 수 있습니까?
- AspNetInternalProvider의 동작이 동일합니까?
그래서 OutputCacheProvider가 예상대로 작동하려면 필요한 조치는 무엇입니까? 인터넷에서 발견 된 모든 단일 사용자 정의 OutputCacheProvider는 동일한 문제점을 겪고 있습니다. – zissop