|
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
|