ASP.NET caché de salida (es decir, HTML estático) se basaba en memoria hasta .NET 4.0. Esto significa que si nuestro sitio contiene mucha caché, es fácil consumir memoria local. Ahora, con la ayuda de . En OutputCacheProvider en .NET 4.0, tenemos varias opciones para crear nuestra propia caché. Por ejemplo, podemos almacenar la caché de salida HTML en un servidor de clúster distribuido con memcaching o en MongoDB (una base de datos orientada a documentos de uso común, lee esto http://msdn.microsoft.com/zh-cn/magazine/gg650661.aspx). Por supuesto, también podemos almacenar la caché como un archivo en el disco duro, que es la forma más barata de hacerlo teniendo en cuenta la escalabilidad, y este artículo trata sobre cómo construir una caché de archivos personalizada.
1:ProveedorCacheSalida OutputCacheProvider es una clase base abstracta que necesitamos para anular cuatro de sus métodos, que son: Añade método para insertar el elemento especificado en la caché de salida. Get, que devuelve una referencia al elemento especificado en la caché de salida. Método de eliminación para eliminar el elemento especificado de la caché de salida. Set, inserta el elemento especificado en la caché de salida y sobrescribe el elemento si está almacenado en caché.
2: Crea tu propia clase de manejo de caché de archivos El tipo es FileCacheProvider, y el código es el siguiente:
- 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;
- }
- }
Copiar código Hay dos lugares que necesitan atención especial: En el método de Añadir, hay un juicio condicional que debe gestionarse de esta manera, de lo contrario el mecanismo de caché almacenará en caché el primer resultado, y la caché expirará después de la fecha de expiración y no se reconstruirá. En el programa de ejemplo, simplemente ponemos la caché en el directorio de caché, y en la práctica práctica del proyecto, considerando que las páginas en caché serán miles, debemos hacer la clasificación de directorios, de lo contrario encontrar y leer archivos de caché se convertirá en un cuello de botella de eficiencia, lo que drenará la CPU.
3: Archivo de configuración
Necesitamos configurar en Web.config que el gestor de caché sea un FileCacheProvider personalizado, es decir, añadir un nodo bajo FileCacheProvider:- <caching>
- <outputCache defaultProvider="FileCache">
- <providers>
- <add name="FileCache" type="MvcApplication2.Common.FileCacheProvider" cachePath="~/Cache" />
- </providers>
- </outputCache>
- </caching>
Copiar código
4: Uso de la caché
Suponemos que usarlo bajo el control de MVC (si quieres usarlo en una página de ASP.NET, incluye <% en la page@OutputCache VaryByParam="none" Duration="10" %>), y puedes ver que Index no está almacenado en caché de salida, mientras que Index2 está almacenado en caché durante 10 segundos.
- 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();
- }
- }
Copiar código 5: Comprueba el efecto El código anterior, tras acceder a Index2, generará un archivo de caché en la carpeta Cache, de la siguiente manera:
Ahora, evaluemos la comparación de rendimiento entre la caché de salida y la caché de salida, simulando 100 solicitudes concurrentes de 100 usuarios de la siguiente manera:
|