Bonjour,
Aujourd'hui nous allons parler de compression de la Session et du Cache ASP.NET afin d'optimiser l'espace mémoire de notre serveur web.
Scott Hanselman à discuté sur son blog de cet éventualité et ne traitait que l'utilisation de "String".
Je vous propose donc de mettre ceci en oeuvre de manière concrète mais cette fois ci non seulement pour des "String" mais aussi pour n'importe quel type d'objets, pour cela nous allons utiliser de la Serialization Binaire via un BinaryFormatter.
Nous allons donc créer un Wrapper permettant d'effectuer ces actions et ainsi rendre simple l'accès à la Session et au Cache.
Voici donc la notre classe CompressedCaching générique.
public static class CompressedCaching<T>
{
#region Public Methods
public static void SetInCache(String Key, T o)
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, o);
byte[] bts = ms.ToArray();
HttpContext.Current.Cache[Key] = Compress(bts);
}
}
public static T GetFromCache(String Key)
{
byte[] bts = (byte[])HttpContext.Current.Cache[Key];
byte[] uncompressed = DeCompress(bts);
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(uncompressed))
{
T o = (T)bf.Deserialize(ms);
return o;
}
}
public static void SetInSession(String Key, T o)
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, o);
byte[] bts = ms.ToArray();
HttpContext.Current.Session[Key] = Compress(bts);
}
}
public static T GetFromSession(String Key)
{
byte[] bts = (byte[])HttpContext.Current.Session[Key];
byte[] uncompressed = DeCompress(bts);
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(uncompressed))
{
T o = (T)bf.Deserialize(ms);
return o;
}
}
#endregion
#region Private Static Methods
private static byte[] Compress(byte[] bytes)
{
byte[] compressedBuffer = bytes;
using (MemoryStream stream = new MemoryStream())
{
using (GZipStream zip = new GZipStream(stream, CompressionMode.Compress))
{
zip.Write(compressedBuffer, 0, compressedBuffer.Length);
}
compressedBuffer = stream.ToArray();
}
return compressedBuffer;
}
private static byte[] DeCompress(byte[] bts)
{
int totalBytes = 0;
using (MemoryStream mem = new MemoryStream(bts))
{
using (GZipStream gz = new GZipStream(mem, CompressionMode.Decompress))
{
int offset = 0;
byte[] smallBuffer = new byte[100];
while (true)
{
int bytesRead = gz.Read(smallBuffer, 0, 100);
if (bytesRead == 0)
{
break;
}
offset += bytesRead;
totalBytes += bytesRead;
}
}
}
using (MemoryStream mem = new MemoryStream(bts))
{
using (GZipStream gz = new GZipStream(mem, CompressionMode.Decompress))
{
byte[] buffer = new byte[totalBytes];
gz.Read(buffer, 0, totalBytes);
return buffer;
}
}
}
#endregion
}
MAJ 18/11/08 : J'ai trouvé un article de Mads Kristensen qui discute au sujet des performance de compression entre GZipStream et DeflateStream, il semblerait que DeflateStream soit 40% plus rapide que GZipStream, je vous conseille donc d'essayer de remplacer toute les GZipStream dans le code par DeflateStream.
Afin de rendre plus simple l'utilisation de notre classe nous allons créer des Extensions de méthodes qui seront appliquées sur Page.Cache et Page.Session
Sans plus attendre, le code :)
public static class MyExtensions
{
public static T GetFromCache<T>(this Cache contextCache, string Key)
{
return CompressedCaching<T>.GetFromCache(Key);
}
public static void SetInCache<T>(this Cache contextCache, string Key, T obj)
{
CompressedCaching<T>.SetInCache(Key, obj);
}
public static T GetFromSession<T>(this HttpSessionState contextSession, string Key)
{
return CompressedCaching<T>.GetFromSession(Key);
}
public static void SetInSession<T>(this HttpSessionState contextSession, string Key, T obj)
{
CompressedCaching<T>.SetInSession(Key, obj);
}
}
Il est donc très simple d'utiliser notre classe CompressedCaching avec ses Extensions de méthodes de la manière suivante :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace HttpSessionCacheCompression
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
TestWithSession();
TestWithCache();
}
private void TestWithSession()
{
if (!IsPostBack)
{
// Using Session
List<int> UncompressedData = new List<int>();
for (int i = 0; i < 1000; i++)
{
UncompressedData.Add(i);
}
Session.SetInSession<List<int>>("Data", UncompressedData);
}
List<int> CompressedData = Session.GetFromSession<List<int>>("Data");
foreach (int i in CompressedData)
{
Response.Write(i.ToString() + "<br/>");
}
}
private void TestWithCache()
{
if (!IsPostBack)
{
// Using Cache
List<int> UncompressedData = new List<int>();
for (int i = 0; i < 1000; i++)
{
UncompressedData.Add(i);
}
Cache.SetInCache<List<int>>("Data", UncompressedData);
}
List<int> CompressedData = Cache.GetFromCache<List<int>>("Data");
foreach (int i in CompressedData)
{
Response.Write(i.ToString() + "<br/>");
}
}
}
}
Et voila, j'attend vos retours avec impatience ! :)
yield return this;
Views(1383)

