In-Memory Data Compression in .NET, PART III

By Peter A. Bromberg, Ph.D.

Peter Bromberg  

In my first article of this series, "In-Memory Data Compression in .NET", I illustrated the use of Mike Krüger of icSharpcode.net 's NZipLib 100% C# ZLib port to compress and decompress strings in memory. The next logical step, is "How do I send the stuff over the wire compressed, decompress it , do some work and then recompress it and send back the response?" If you are not familiar with ZLib or data compression, I suggest you review the first article before reading this one.



In the second article, In-Memory Data Compression in .NET, PART II I followed up with ASP.NET code showing how to dynamically compress and send any textual data to a "receiver.aspx" page, decompress on the server, do some work, then recompress and return the response, where the client page automatically decompresses it.

There is another important facet to in-memory data compression and web servers - namely, HTTP compression. By default, Internet Information Services (IIS) 5.0 uses the GZip and Deflate HTTP compression methods. Both compression methods are implemented through an ISAPI filter. HTTP compression is a subservice of IIS, which is handled through an ISAPI filter. Because this filter is installed at the WWW Service level, compression must be configured for the entire Web server. It cannot be configured for a specific Web site. The following two files handle this compression (located in the %WinDir%\System32\INETSERV folder):
CompFilt.dll
GZIP.dll
Compression Methods
GZIP file format specification - RFC 1952
DEFLATE Compressed Data Format Specification - RFC 1951

To tell the browser that the server is sending compressed content, we only need to set the "Content-Encoding" Response Header to "gzip". Unfortunately, all web servers that I know of are unable to generate dynamically compressed data - the files need to actually be set up as compressed in advance. Fortunately, with a compression library, we now have an easy way to take ANY textual content - XML, HTML etc. regardless of whether it is generated from an uncompressed file or generated in memory say, from the results of a database query, GZip it, set the header, and send it on it's merry way to the browser, nicely compressed! The code that follows is a simplified but complete example of how we would read a specified file from the filesystem, compress it, and send it on to the browser which should be able to handle the decompression by itself:

 
<% @ Page Language="C#" %>
<% @Import Namespace="System" %>
<% @Import Namespace="System.Text" %>
<% @Import Namespace="System.IO" %>
<% @Import Namespace="System.Net" %>
<% @Import Namespace="System.Text" %>
<% @Import Namespace="NZlib.GZip" %>
<% @Import Namespace="System.Xml" %>
<script language="C#" runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
Response.AppendHeader("Content-Encoding", "gzip");
Response.BinaryWrite(GzipCompress(@"C:\Inetpub\wwwroot\stuff\Mybigdocument.htm"));
}
private byte[] GzipCompress(string strFilePathName)
{
try
{

FileStream fs = File.OpenRead(strFilePathName);
byte[] writeData = new byte[fs.Length];
fs.Read(writeData, 0, (int)fs.Length);
MemoryStream ms = new MemoryStream();
NZlib.GZip.GZipOutputStream s = new NZlib.GZip.GZipOutputStream(ms);
s.Write(writeData, 0, writeData.Length);
s.Flush();
s.Close();
byte[] compressedData = (byte[])ms.ToArray();
return compressedData;
}
catch(Exception e)
{
Response.Write(e.Message);
return null;
}
}
</script>

Of course, we don't have to read the file from the file system, it could just as easily be in a string variable that we have just finished concatenating based on some specific processing code rules. Here is another example that takes string input and uses GZip compression to write it out to the browser:

<% @ Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<% @Import Namespace="NZlib.GZip" %>

<script language="C#" runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
Response.AppendHeader("Content-Encoding", "gzip");
string strInput ="<HTML><HEAD></HEAD><BODY><Table border=1 bordercolor=red cellspacing=2 cellpadding=2><TR BGCOLOR=lightgrey><TD>this is some data</TD></TR></TABLE></BODY></HTML>";
Response.BinaryWrite(GzipCompressString(strInput));
}

private byte[] GzipCompressString(string strInput)
{
try
{
byte[] writeData = System.Text.Encoding.ASCII.GetBytes(strInput);
MemoryStream ms = new MemoryStream();
NZlib.GZip.GZipOutputStream s = new NZlib.GZip.GZipOutputStream(ms);
s.Write(writeData, 0, writeData.Length);
s.Flush();
s.Close();
byte[] compressedData = (byte[])ms.ToArray();
return compressedData;
}
catch(Exception e)
{
Response.Write(e.Message);
return null;
}
}
</script>

 

 

HTTP compression reduces server load and bandwidth needs, and most modern browsers can decompress GZip or deflated compressed data. By using Dynamic GZip or Deflate compression to compress our dynamically generated content in ASP.NET, we can take advantage of the native HTTP decompression built into modern browsers and obtain valuable time and bandwidth savings, while reducing server load and increasing the scalability of our webserver(s).

This concludes my series on In - Memory Data Compression in .NET. I hope you found it useful!

Peter Bromberg is an independent consultant specializing in distributed .NET solutions in Orlando and a co-developer of the EggheadCafe.com developer website. He can be reached at pbromberg@yahoo.com

 
Do you have a question or comment about this article? Have a programming problem you need to solve? Post it at eggheadcafe.com forums and receive immediate email notification of responses.


Search

search