ASP.NET 4.0 väljundi puhverdamine - kirjutame oma providerid

02.04.2010  |  Gunnar

ASP.NET Oma kannete seeria väljundi puhverdamise teemadel tõmban kokku näitega, mis katab ära ASP.NET 4.0 poolt pakutava laiendatud väljundi puhverdamise. Ehk siis – me saame ise kirjutada provider-id, mille abil väljund kuhugi paigutatakse ja mille abil seda sealt kuskilt loetakse. Käesolev kanne on, loomulikult, hardcore XXX ehk mulle nii kodune tase 400, kuid on ka pisike lisaväärtus – seda näidet kasutab üks Redmondis asuv tehnoloogiafirma oma majasisestes koolitustes.

Antud näidet on näinud need, kes käisid Eneta kommuuniõhtul, mille teemaks olid ASP.NET 4.0 uuendused. Kes kohal olid, need siit midagi uut ja huvitavat arvatavasti ei leia ja minu poolest tehke midagi lahedat – tooge mune või tehke toad korda või kutsuge enda küljest niisama GetLife() meetod välja. :)

Vajaminev lähtekoo ning lisaboonusena presentatsiooni slaidid ja ettekande video leiab järgmiste linkide tagant:

Aga asja juurde. Käesolevas näites looma väljundi puhverdamise klassi, mis hoiab puhverdatavaid andmeid kõvakettal, seadistame ära veebirakenduse ja proovime, milline on tulemus.

Väljundi puhvri konfigureerimine

See on küll viimane samm, mis on vaja enne proovimiste teha, aga et tegemist on lihtsa liigutusega, siis kirjeldan selle sissejuhatusena siin ära.

<caching>

<outputCache defaultProvider="AspNetInternalProvider">

  <providers>

   <add name="FileCache"

    type="MyCacheProviders.FileCacheProvider, MyCacheProviders"/>

  </providers>

</outputCache>

</caching>

Toodud plokk ütleb ASP.NET-ile, et vaikimisi kasutame out-of-box provider-it. Kui aga kuskil küsitakse, siis on meil olemas provider nimega FileCache ja see luuakse type-atribuudis toodud tüübi põhjal. Hiljem me teeme siia ühe muudatuse, et FileCache oleks vaikimisi provider.

Provider-i loomine

Oma tööd alustame sellega, et lisame projekti MyCacheProviders uue klassi, mille nimeks paneme FileCacheProvider. FileCacheProvideri failis lisame viite nimeruumile System.Web.Caching. Järgmiseks määrame ära, et FileCacheProvider laiendab väljundi puhverdamise provider-ite baasklassi OutputCacheProvider. Baasklassis on defineeritud kõik meetodid, mille me looma peame.

Et klassi kood pole lühemate killast, siis eelinfoks veel nii palju, et oma elu lihtsustamiseks kasutame me binary serialiseerimist, et objektid faili salvestada ja et neid sealt lugeda. Samuti kasutame me spetsiaalset klassi CacheItem, mis aitab meil paremini puhvrit kontrollida.

Meie klass on selline.

public class FileCacheProvider : OutputCacheProvider
{
    private string _cachePath;
 
    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)
    {
        Debug.WriteLine("Cache.Add(" + key + ", " + entry + ", " + utcExpiry + ")");
 
        var path = GetPathFromKey(key);
 
        if (File.Exists(path))
            return entry;
 
        using (var file = File.OpenWrite(path))
        {
            var item = new CacheItem { Expires = utcExpiry, Item = entry };
            var formatter = new BinaryFormatter();
            formatter.Serialize(file, item);
        }
 
        return entry;
    }
 
    public override object Get(string key)
    {
        Debug.WriteLine("Cache.Get(" + key + ")");
 
        var path = GetPathFromKey(key);
 
        if (!File.Exists(path))
            return null;
 
        CacheItem item = null;
 
        using (var file = File.OpenRead(path))
        {
            var formatter = new BinaryFormatter();
            item = (CacheItem)formatter.Deserialize(file);
        }
 
        if (item == null || item.Expires <= DateTime.Now.ToUniversalTime())
        {
            Remove(key);
            return null;
        }
 
        return item.Item;
    }
 
    public override void Remove(string key)
    {
        Debug.WriteLine("Cache.Remove(" + key + ")");
 
        var path = GetPathFromKey(key);
 
        if (File.Exists(path))
            File.Delete(path);
    }
 
    public override void Set(string key, object entry, DateTime utcExpiry)
    {
        Debug.WriteLine("Cache.Set(" + key + ", " + entry + ", " + utcExpiry + ")");
 
        var item = new CacheItem { Expires = utcExpiry, Item = entry };
        var path = GetPathFromKey(key);
 
        using (var file = File.OpenWrite(path))
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(file, item);
        }
    }
 
    private string GetPathFromKey(string key)
    {
        return CachePath + MD5(key) + ".txt";
    }
 
    private string MD5(string s)
    {
        var provider = new MD5CryptoServiceProvider();
        var bytes = Encoding.UTF8.GetBytes(s);
        var builder = new StringBuilder();
 
        bytes = provider.ComputeHash(bytes);
 
        foreach (var b in bytes)
            builder.Append(b.ToString("x2").ToLower());
 
        return builder.ToString();
    }
}

CacheItem klass, mille ma märkisin serialiseeritavaks, sisaldab antud objekti puhvrisse kirjutamise või objekti muutmise ajatemplit ning objekti, mida ASP.NET meil puhverdada käskis.

[Serializable]
internal class CacheItem
{
    public DateTime Expires;
    public object Item;
}

CacheItem on defineeritud kui internal, sest selle kasutamine on FileCacheProvider klassi sisemise teostuse detail ja seega ei pea see väljapoole näha olema.

NB! Küsige julgelt, kui küsimusi tekkis, sest tegemist pole lihtsaima koodiga ja seni on mujalt maailmast tulnud mitmeid küsimusi selle kohta. Ärge kartke küsida, sest loll pole see, kes küsib, vaid see, kes küsimata jätab, kui küsimusi on. :)

Valmistume veebirakenduse testimiseks

Nüüd on kõik vajalik olemas ja kui midagi valesti ei läinud, siis ei hakka pahanda ka kompilaator meie kallal. Esimese asjana muudame web.config faili. Lisame sinna puhverdamiseks mõeldud kataloogi asukoha ja määrame vaikimisi provider-iks FileCacheProvideri, mille me kirjutasime.

<appSettings>

  <add key="OutputCachePath" value="~/Cache/" />

</appSettings>

 

<caching>

  <outputCache defaultProvider="FileCache">

    <providers>

      <add name="FileCache"type="MyCacheProvider.FileCacheProvider, MyCacheProvider"/>

    </providers>

  </outputCache>

</caching>

Järgmiseks avame rakenduses mõne lehe, mille väljundit soovime puhverdada ning kirjutame selle algusesse deklaratsioonide osa lõppu järgmise deklaratsiooni.

<%@ OutputCache VaryByParam="ID" Duration="300" %>

See ütleb ASP.NET raamistikule, et me puhverdame lehte parameetri ID järgi erinevateks versioonideks ja puhvri kestuseks on 300 sekundit ehk viis minutit. Kui on soovi, siis võib neid parameetreid muuta.

Väljundi puhvri testimine

Testimiseks käivitame veebirakenduse ja avame Visual Studios Output akna, kuhu FileCacheProvider oma tegevuse logi kirjutab.

Näiterakendus, mille peal testime väljundi puhverdamist

Kui toodud ekraanpaugul näha olev leht on avanenud, vaata Visual Studio väljundi akent. Seal peaks näha olema midagi taolist.

Cache.Get(a2/default.aspx) 
Cache.Add(a2/default.aspx, System.Web.Caching.CachedVary, 31.12.9999 23:59:59) 
Cache.Set(a2/default.aspxHQNidV+n+FCDE, System.Web.Caching.OutputCacheEntry, 19.11.2009 12:20:56)

Kui lehel F5 (Refresh) vajutada, siis saame natuke teistsuguse väljundi.

Cache.Get(a2/default.aspx) 
Cache.Get(a2/default.aspxHQNidV+n+FCDE) 
Cache.Get(a2/styles/site.css) 
Cache.Get(a2/webresource.axd) 
Cache.Set(a2/styles/site.css, System.Web.Caching.OutputCacheEntry, 20.11.2009 12:17:09) 
Cache.Add(a2/webresource.axd, System.Web.Caching.CachedVary, 31.12.9999 23:59:59) 
Cache.Set(a2/webresource.axdHQNdVjnaEMMY-tPD2-oCbZFp7vHhVoQiB8SS98KHQMNKjUfs1FCDE, System.Web.Caching.OutputCacheEntry, 19.11.2010 12:17:09) 
Cache.Get(a2/webresource.axd) 
Cache.Get(a2/webresource.axdHQNdVqx_c6oOlTqymCAsGZh_8JA2FCDE) 
Cache.Add(a2/webresource.axd, System.Web.Caching.CachedVary, 31.12.9999 23:59:59) 
Cache.Set(a2/webresource.axdHQNdVqx_c6oOlTqymCAsGZh_8JA2FCDE, System.Web.Caching.OutputCacheEntry, 19.11.2010 12:17:10)

Teisel pöördumisel puhverdati maha veel terve ports andmeid. Need pöördumised FileCacheProvider klassi poole teeb ASP.NET raamistik. Pöördumiste käigus puhverdatakse uut sisu ja kustutatakse puhvrist maha vanemat sisu. Need otsused langetab ASP.NET ise.

Heidame pilgu peale ka puhverdamiseks kasutatavale kataloogile.

Failid puhverdatud väljundiga

Kui soovid teada, kuidas väljund puhverdatud on, siis ava neid faile ja vaata nende sisu. Midagi keerukat seal pole.

Kokkuvõtteks

Väljundi puhverdamiseks oma provider-ite kirjutamine pole keerukas. Vaja on luua lihtsalt klass, mis sellega tegeleb ja tutvustada seda klassi veebirakendusele läbi konfiguratsiooni faili. Sarnaselt siin näites toodule saab luua ka sellised provider-id, mis kirjutavad ja loevad puhverdatud väljundit muudest allikatest. Eespool viitatud näitekood, mida saab alla laadida, sisaldab näidet ka memcached jaoks.

Kommenteeri

sulge
Saada link e-postiga

© DT 2012 | Creative Commons Attribution-Noncommercial 3.0 License | WordPress