Cache w aplikacji ASP.NET, dlaczego warto
stworzony przez Tomek Dziemidowicz dnia mar.15, 2009, w kategorii: ASP.NET
Przeglądając materiały w sieci na temat cache w ASP.NET można zauważyć, że większość skupia się na bardzo wąskiej i raczej niewystarczającej deklaracji :
<%@ OutputCache Duration=„60″ VaryByParam=„none” %>
Nie będę rozwijał i opisywał tej metody. Odsyłam do artykułu na CodeGuru.pl – jest to tam dokładnie opisane.
W tym artykule skupię się na wykorzystaniu obiektu System.Web.Caching.Cache do zapamiętywania wyników z bazy danych czyli w efekcie zmniejszenia obciążenia silnika bazy danych.
W moim przykładzie, dostęp do bazy danych został podzielony na dwie powłoki: BLL i DAL. Każda z nich spełnia określoną rolę:
Powłoka BLL (z ang. Bussiness Logic Layer) odpowiada za dostęp powłoki prezentacyjnej (stron aspx) do bazy danych. W dużym skrócie działa to tak: Pobierz dane z bazy z użyciem powłoki DAL i zapisz je do Cache jeżeli jeszcze nie ma ich w pamięci podręcznej. Przykładowa funkcja z tej powłoki pobierająca wszystkie wiersze z bazy danych tabeli Products:
W pierwszej kolejności dodajemy obsługę obiektu cache
public abstract class BaseProducts : BizObject
{
protected static bool EnableCaching
{
get { return true; }
}
/// <summary>
/// Cache the input data, if caching is enabled
/// </summary>
protected static void CacheData(string key, object data)
{
if (EnableCaching && data != null)
{
BizObject.Cache.Insert(key, data, null,
DateTime.Now.AddSeconds(60), TimeSpan.Zero);
}
}
}
Klasa BizObject obudowuje obiekt Cache dla naszych potrzeb :
namespace AuroraSoft.BLL
{
public abstract class BizObject
{
protected static Cache Cache
{
get { return HttpContext.Current.Cache; }
}
/// <summary>
/// Remove from the ASP.NET cache all items whose key starts with the input prefix
/// </summary>
protected static void PurgeCacheItems(string prefix)
{
prefix = prefix.ToLower();
List<string> itemsToRemove = new List<string>();
IDictionaryEnumerator enumerator = BizObject.Cache.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Key.ToString().ToLower().StartsWith(prefix))
itemsToRemove.Add(enumerator.Key.ToString());
}
foreach (string itemToRemove in itemsToRemove)
BizObject.Cache.Remove(itemToRemove);
}
}
}
Klasa Products odzwierciedla operację na tabeli Products.
public class Products : BaseProducts
{
/// <summary>
/// Returns a collection with all the Products
/// </summary>
public static List<ProductsEntity> GetProducts()
{
List<ProductsEntity> productsCollection = null;
string key = "Products_";
if (BaseProducts.EnableCaching && BizObject.Cache[key] != null)
{
productsCollection = (List<ProductsEntity>)BizObject.Cache[key];
}
else
{
productsCollection = SiteProvider.Products.GetProducts();
BaseProducts.CacheData(key, productsCollection);
}
return productsCollection;
}
}
Bardzo ważnym elementem tej metody jest string key = „Products_”; , ponieważ mówi dla obiektu Cache pod jakim kluczem zostaje zapamiętany nasz obiekt. Jeżeli w innej funkcji użyjemy tego samego klucza spowoduje to zastapienie obiektu. Metoda GetProducts() sprawdza czy dane znajdują się w pamięci Cache, jeżeli nie to pobiera je z bazy danych (SiteProvider.Products.GetProducts();) i zapisuje do pamięci Cache. Przy następny przeładowaniu strony, dane zostaną pobrane z Cache.
OK, ale co się stanie jeżeli ktoś doda jakiś rekord? Tutaj funkcja dodająca rekord do tabeli Products (z klasy Products)
/// <summary>
/// Creates a new Products
/// </summary>
public static int InsertProduct(string Title)
{
ProductsEntity record = new ProductsEntity(0, Title);
int ret = SiteProvider.Products.InsertProduct(record);
BizObject.PurgeCacheItems("Products_");
return ret;
}
Po dodaniu rekordu do bazy danych zostaje wywołane wyczyszczenie Cache BizObject.PurgeCacheItems(„Products_”); dla wszystkich kluczy które zaczynają się od „Products_”.
Pozostaje pytanie: jak długo obiekt będzie istniał w pamięci cache? Otóż to jest zależne od nas i określamy to w metodzie dodającej obiekt do pamięci cache:
BizObject.Cache.Insert(key, data, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
W moim przykładzie obiekt będzie istniał w pamięci cache przez 60 sek.
Powłoka BLL komunikuje się z bazą danych przy pomcy DAL (Data Access Layer). DAL odpowiada za zapisywanie i odczyt informacji z bazy danych.
Wadą tego rozwiązania jest zwiększone zapotrzebowanie aplikacji na pamięć RAM.
Przykładowa strona do pobrania (źródła) z zastosowaniem tej techniki. Znajduje się tam pełna implementacja powłoki BLL i DAL dla jednej tabeli :
Uwaga: Musisz mieć VS2008 i MSSQL (przynajmniej w wersji Express). Do projektu jest dołączony backup bazy danych. Wystarczy odtworzyć to na swoim lokalnym serwerze i odpowiednio zmodyfikować w web.config ConnectionString.
Marzec 2nd, 2010 on 13:12
Bardzo dobry artykuł. Znalazłem go w googlu na 4 miejscu wyszukując frazę:
„asp.net check cache keys”.