La última entrega usamos Compresión GZip que viene incluída en la framework para comprimir el ViewState, porqué no experimentamos un poco y usamos algún otro método de compresión?.
Qué tal si jugamos con la compresión Zip? (usando la ICSharpZipLib) o hasta la novedosa y mucho más poderosa compresión LZMA (conocida como 7Zip). Veamos cuanto podríamos ganar con cada una de ellas. Intentemos primero con Zip:
(C# Code)
using System;
using System.IO;
using System.Text;
using System.Web.UI;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace ViewStateCompressCS
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e) {}
protected override void SavePageStateToPersistenceMedium(object state)
{
string vstate = string.Empty;
using (var sw = new StringWriter()) {
var formatter = new LosFormatter();
formatter.Serialize(sw, state);
vstate = sw.ToString();
}
var memory_stream = new MemoryStream();
using (var zip_stream = new DeflaterOutputStream(memory_stream, new Deflater(Deflater.BEST_COMPRESSION))) {
byte[] buffer = Encoding.UTF8.GetBytes(vstate);
zip_stream.Write(buffer, 0, buffer.Length);
}
byte[] vstate_bytes = memory_stream.ToArray();
memory_stream.Close();
vstate = Convert.ToBase64String(vstate_bytes);
ClientScript.RegisterHiddenField("__VSTATE", vstate);
}
protected override object LoadPageStateFromPersistenceMedium()
{
string vstate = Request.Form["__VSTATE"];
if (string.IsNullOrEmpty(vstate))
throw new InvalidOperationException("Something wrong goes with my ViewState!");
var vstate_stream = new MemoryStream();
var memory_stream = new MemoryStream(Convert.FromBase64String(vstate));
using (var zip_stream = new InflaterInputStream(memory_stream, new Inflater())) {
int read;
var buffer = new byte[4096];
while ((read = zip_stream.Read(buffer, 0, buffer.Length)) != 0) {
vstate_stream.Write(buffer, 0, read);
}
}
byte[] vstate_bytes = vstate_stream.ToArray();
vstate_stream.Close();
memory_stream.Close();
vstate = Encoding.UTF8.GetString(vstate_bytes);
var formatter = new LosFormatter();
return formatter.Deserialize(vstate);
}
}
}
(VB.net Code)
Imports System.IO
Imports System.IO.Compression
Imports ICSharpCode.SharpZipLib.Zip.Compression
Imports ICSharpCode.SharpZipLib.Zip.Compression.Streams
Partial Public Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
Dim vState As String = String.Empty
Using sw As New StringWriter()
Dim formatter = New LosFormatter()
formatter.Serialize(sw, vState)
vState = sw.ToString()
End Using
If String.IsNullOrEmpty(vState) Then
Throw New InvalidOperationException("Something wrong goes with my ViewState!")
End If
Dim memStream = New MemoryStream()
Using zipStream = New DeflaterOutputStream(memStream, New Deflater(Deflater.BEST_COMPRESSION))
Dim buffer = Encoding.UTF8.GetBytes(vState)
zipStream.Write(buffer, 0, buffer.Length)
End Using
Dim vStateBytes = memStream.ToArray()
vState = Convert.ToBase64String(vStateBytes)
ClientScript.RegisterHiddenField("__VSTATE", vState)
End Sub
Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
Dim vState As String = Request.Form("__VSTATE")
If String.IsNullOrEmpty(vState) Then
Throw New InvalidOperationException("Something wrong goes with my ViewState!")
End If
Dim vStateStream = New MemoryStream()
Dim memStream = New MemoryStream()
Using zipStream = New InflaterInputStream(memStream, New Inflater())
Dim read As Integer
Dim buffer(4096) As Byte
While ((read = zipStream.Read(buffer, 0, buffer.Length) <> 0))
vStateStream.Write(buffer, 0, read)
End While
End Using
Dim vStateBytes = vStateStream.ToArray()
vStateStream.Close()
memStream.Close()
vState = Encoding.UTF8.GetString(vStateBytes)
Dim formatter = New LosFormatter()
Return formatter.Deserialize(vState)
End Function
End Class
Obviamente como se daran cuenta el código es muy similar al código usando GZip, quizás por eso es tan bonito la ICSharpLib
Veamos ahora los números:
Sin Comprimir
Carácteres: 6032
Tamaño (KB): 5.89
Comprimido (Zip)
Carácteres: 2508
Tamaño: 2.45
Wow! ahora tenemos una reducción del 58.42%, y eso que este es nuestro segundo intento
Intentemos ahora cambiando un “poco” nuestra página, ahora usemos compresión por 7zip, usando el 7Zip C# SDK y una clase Helper hecha por Peter Bromberg, publicada en Eggheadcafe.
(C# Code)
using System;
using System.IO;
using System.Text;
using System.Web.UI;
using Rioshu.Utils.Compression.SevenZip;
namespace ViewStateCompressCS
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e) {}
protected override void SavePageStateToPersistenceMedium(object state)
{
string vstate = string.Empty;
using (var sw = new StringWriter()) {
var formatter = new LosFormatter();
formatter.Serialize(sw, state);
vstate = sw.ToString();
}
byte[] vstate_bytes = Encoding.UTF8.GetBytes(vstate);
vstate_bytes = SevenZipHelper.Compress(vstate_bytes);
vstate = Convert.ToBase64String(vstate_bytes);
ClientScript.RegisterHiddenField("__VSTATE", vstate);
}
protected override object LoadPageStateFromPersistenceMedium()
{
string vstate = Request.Form["__VSTATE"];
if (string.IsNullOrEmpty(vstate))
throw new InvalidOperationException("Something wrong goes with my ViewState!");
byte[] vstate_bytes = Convert.FromBase64String(vstate);
vstate_bytes = SevenZipHelper.Decompress(vstate_bytes);
vstate = Encoding.UTF8.GetString(vstate_bytes);
var formatter = new LosFormatter();
return formatter.Deserialize(vstate);
}
}
}
(VB.net Code)
Imports System.IO
Imports Rioshu.Utils.Compression.SevenZip
Partial Public Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
Dim vState As String = String.Empty
Using sw As New StringWriter()
Dim formatter = New LosFormatter()
formatter.Serialize(sw, vState)
vState = sw.ToString()
End Using
If String.IsNullOrEmpty(vState) Then
Throw New InvalidOperationException("Something wrong goes with my ViewState!")
End If
Dim vStateBytes = Encoding.UTF8.GetBytes(vState)
vStateBytes = SevenZipHelper.Compress(vStateBytes)
vState = Convert.ToBase64String(vStateBytes)
ClientScript.RegisterHiddenField("__VSTATE", vState)
End Sub
Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
Dim vState As String = Request.Form("__VSTATE")
If String.IsNullOrEmpty(vState) Then
Throw New InvalidOperationException("Something wrong goes with my ViewState!")
End If
Dim vStateBytes = Convert.FromBase64String(vState)
vStateBytes = SevenZipHelper.Decompress(vStateBytes)
vState = Encoding.UTF8.GetString(vStateBytes)
Dim formatter = New LosFormatter()
Return formatter.Deserialize(vState)
End Function
End Class
Y ahora veamos los cambios:
Sin Comprimir
Carácteres: 6032
Tamaño (KB): 5.89
Diferencia: NA
Comprimido (Zip)
Carácteres: 2508
Tamaño (KB): 2.45
Diferencia: 58.42%
Comprimido (7Zip)
Carácteres: 2412
Tamaño (KB): 2.36
Diferencia: 60%
Wow!, como nos percatamos logramos quitarle un 60% del tamaño de nuestro ViewState original, eso involucra que si nuestro ViewState es de 900kB (algo que hace varios meses resultó positivo en una aplicación a mi cargo), este se tornará en 360kB, un “poco más” manejable.
Escoger entre 7Zip y Zip es cuestión de gustos, personalmente prefiero Zip por el soporte de la maravillosa Library de Zip que viene en ICSharpZipLib. Pero bueno, es cuestion de gustos!
Pero esto no queda aquí, veremos que otras opciones tenemos para manipular nuestro ViewState, aún quedan varias!
El ejemplo podemos bajarlo de aquí.
