“Can you do something to make this application run faster?”
At this point I’ve got a glimpse on the codes and found so many sign telling me this is garbage and I calmly said:
“My recommendation is to burn this piece of s**t, piss on it, and never look back”
Yeah I wish, but hey he’s my supervisor, so as always I obediently said, “I’ll see what I can do Sir”.
So here I am on the job, firing up Google on the first thing that crosses my little mind, Compression. Some recommendations quickly offered:
- Create a pair of Web Service Filter (Input and Output) by utilizing WSE (Web Service Enhancement) to compress and uncompress data transmitted between Server and Client. This is nice in the way that the application core doesn’t have to be changed, on simple modification on the Web Method declaration and the generated proxy (usually named Reference.cs), and even nicer various open source implementations were already available. The not-so-nice part is that somehow it does not work with my garbage codes.
- Utilize standard HTTP Compression by adding Web Service request with “Accept-Encoding: gzip, deflate” and then uncompress the data at the client side. This is done by slight modification on the GetWebRequest and GetWebResponse at the proxy. Sounds nice, but Gzip is only “normally” supported on IIS 6.0 bundled with Windows Server 2003, while the IIS 5.0 requires so much effort to make it work, and according to the community (and my own frustrating experiment) there’s no guarantee that the same steps will work on different machine. Even if I make it work most probably it will mean hours of support for the installation guys, no way I’m gonna go for it.
So I’ve come to a conclusion that maybe I should use a brutal approach for this brutal application, that is directly compress the DataSet. This certainly defy good programming practice, since it would require major changes on the Web Method including its return value, not to mention it’s not scalable and so forth, but thankfully my brutal application centralize its data call only at one method which mean I only have to deal with that method only.
So here we go, the previously mentioned QueryData method is originally returns DataSet, like this:
public DataSet QueryData (string UserName, string Password, string Database, string Server, string Query, string TableName)
What I would do is to rename this Web Method to QueryDataWithCompression with byte array contains compressed DataSet as the return value, in this method DataSet is compressed then returned as byte array. What will we need is the use of GZipStream class in System.IO.Compression (available at .NET 2.0), you can also use the popular SharpZipLib (available at http://www.icsharpcode.net/OpenSource/SharpZipLib/) if you’re still using .NET 1.1, all you have to do is use GZipInputStream instead of GZipStream to compress the DataSet.
public byte QueryDataWithCompression (string UserName, string Password, string Database, string Server, string Query, string TableName)
... //generate DataSet here
MemoryStream memStream = new MemoryStream();
GZipStream zipStream = new GZipStream(memStream, CompressionMode.Compress);
byte data = memStream.ToArray();
NOTE: Do remember that when you update Web Reference from the Visual Studio IDE, the changes you made in Reference.cs (the proxy) will be lost, so be careful.
Then to avoid changing function calls to the original QueryData method, at the proxy class we will create a public method called QueryData which is actually a wrapper for the generated QueryDataWithCompression method.
public DataSet QueryData(string UserName, string Password, string Database, string Server, string query, string TableName)
byte data = QueryDataWithCompression(UserName, Password, Database, Server, query, TableName);
MemoryStream memStream = new MemoryStream(data);
GZipInputStream unzipStream = new GZipInputStream(memStream);
DataSet ds = new DataSet();
That’s it! Now my Dataset will be compressed before transmitted, but what about performance improvement? I tested a query by using Web Browser calling to the service, the code manage to optimize from 5.3 MB of XML DataSet down to about 300 KB or about 1/18 from the uncompressed size! Yes, it works.