Archive

Posts Tagged ‘.NET’

Compress/Decompress a String in C#

December 26, 2012 Comments off

The feature I was working on today involved saving some temporary data into an HTTP session cookie. The data was an object serialized into JSON. Writing and reading cookies is easy enough but, after testing my implementation a bit, I found out that my code was intermittently failing to save the cookie in my browser. After some deeper investigation, I found that the reason my cookie wasn’t being saved (sometimes) was because the JSON I was attempting to store in the cookie was exceeding the 4K limit of a cookie. The object I was serializing to JSON was a List of other classes so I could not prevent users from exceeding the limit without imposing arbitrary restrictions on the usage of the feature. I also wanted to keep the data on the client’s machine, as opposed to a DB or other storage medium, because the data really did seem to belong in the user’s session. The only option I could think of to solve my problem was to compress the JSON string.

Unfortunately, when I Google’d “C# compress string” (or something like that), the results weren’t very helpful. Most of the code I came across was either for .NET 2.0 or was doing File IO and byte array manipulation with pointers. Many examples didn’t even make proper usage of using() blocks to properly close Streams. What I needed was .NET 4.0 code to Compress and Decompress strings to strings, preferably without needing to do any byte pointer magic. Fortunately, I eventually came across this some-what helpful Stack Overflow Q&A which was close enough to what I was trying to do. The OP was looking for a .NET 2.0 solution and his compressed medium was a byte[] instead of a string but, with a few simple modifications, I was able to adapt the code to do exactly what I needed.

using System;
using System.IO;
using System.IO.Compression;
using System.Text;

...

public static string Compress(string s)
{
    var bytes = Encoding.Unicode.GetBytes(s);
    using (var msi = new MemoryStream(bytes))
    using (var mso = new MemoryStream())
    {
        using (var gs = new GZipStream(mso, CompressionMode.Compress))
        {
            msi.CopyTo(gs);
        }
        return Convert.ToBase64String(mso.ToArray());
    }
}

public static string Decompress(string s)
{
    var bytes = Convert.FromBase64String(s);
    using (var msi = new MemoryStream(bytes))
    using (var mso = new MemoryStream())
    {
        using (var gs = new GZipStream(msi, CompressionMode.Decompress))
        {
            gs.CopyTo(mso);
        }
        return Encoding.Unicode.GetString(mso.ToArray());
    }
}

It is simple, elegant, and best-of-all… it works! Luckily for me, JSON compresses extremely well. The previous data which was failing to save was about 4.5 K but I was able to reduce that down to only 1.5 K after compression! The only drawback I have noticed so far of storing compressed data in a cookie is that it is not human readable. You could spin that as a good thing because users will be less likely to want to see/modify obfuscated cookie values, but as a web-developer, I usually like knowing exactly what is being stored on my computer by the websites I visit. An (unintentional) positive side-effect of compressing the cookie is that it helps minimize the amount of data being sent back-and-forth from the users and our servers. 4K might not seem like a lot of data, but when it is being sent in every request from the user’s browser, it can add up. Either way, this simple code helped me solve this problem… moving on!

Advertisements

Specs and Selenium Together

August 25, 2009 1 comment

I recently had the chance to dive into a new project, this one with a rich web interface. In order to create acceptance tests around the (large and mostly untested) existing code, we’ve started writing specs acceptance tests.

Once we have our specs written to express what the existing functionality is, we can refactor and work on the codebase in more safety, our tests acting as a “motion detector” to let us know if we’ve broken something, while we write more detailed low-level tests (unit tests) to allow easier refactoring of smaller pieces of the application.

What’s interesting about our latest batch of specs is that they are written to express behaviours as experienced through a web browser – e.g. “when a user goes to this link and clicks this button on the page, he sees something happen”. In order to make this work we’ve paired up specs with Selenium, a well-known web testing framework.

By abstracting out the connection to Selenium into a parent Scala object, we can build a DSL-ish testing language that lets us say things like this:


object AUserChangesLanguages extends BaseSpecification {

  "a public user who visits the site" should beAbleTo {
    "Change their language to French" in {
      open("/")
      select("languageSelect", "value=fr")
      waitForPage
      location must include("/fr/")
    }
    "Change their language to German" in {
      select("languageSelect", "value=de")
      waitForPage
      location must include("/de/")
    }
    "Change their language to Polish" in {
      select("languageSelect", "value=pl")
      waitForPage
      location must include("/pl/")
    }
  }
}

This code simply expresses that as a user selects a language from a drop-down of languages, the page should refresh (via some Javascript on the page) and redirect them to a new URL. The new URL contains the language code, so we can tell we’ve arrived at the right page by the “location must include…” line.

Simple and expressive, these tests can be run with any of your choice of browsers (e.g. Firefox, Safari, or, if you insist, Internet Explorer).

Of course, there’s lots more to testing web pages, and we’re fleshing out our DSL day by day as it needs to express more sophisticated interactions with the application.

We can get elements of the page (via Xpath), make assertions about their values, click on things, type things into fields and submit forms, basically all the operations a user might want to do with a web application.

There are some frustrations, of course. The Xpath implementation on different browsers works a bit differently – well, ok, to be fair, it works on all browsers except Internet Exploder, where it fails in various frustrating ways. We’re working on ways to overcome this that don’t involve having any “if browser == ” kind of logic.

It’s also necessary to start the Selenium RC server before running the specs, but a bit of Ant magic fixes this.

We’ve got these specs running on our TeamCity continuous integration server, using the TeamCity runner supplied with Specs, where we get nicely formatted reports as to what’s pending (e.g. not finished being written yet), what’s passing, and what’s failing.

The specs written with Selenium this way are also a bit slow, as they must actually wait in some cases for the browser (and the underlying app!) to catch up. When run with IE as the browser, they’re more than just a bit slow, in fact…

They are, however, gratifyingly black-box, as they don’t have any connection to the code of the running application at all. For that matter, the application under test can be written in any language at all, and in this case is a combination of J2EE/JSP and some .NET.

There’s a lot of promise in this type of testing, even with it’s occasional frustrations and limitations, and I suspect we’ll be doing a lot more of it.

By: Mike Nash