views:

343

answers:

5

Hi, I need to express a collection of about 10-15 short strings (and maybe some ints) as a fairly compact alphanumeric string - one which I can send as a parameter in a get request.

Basically, I'm thinking that my collection will be a hashtable, and I'd like to serialize it so it looks sort of like a viewstate string (only hopefully not so long!).

eg. testpage.aspx?code=rO0ABXNyAAlTb21lQ2xhc3PSHbLk6OgfswIAA0kAAWl

and then testpage.aspx can deserialize this back to the original collection.

Is this possible?

+3  A: 

Why don't you just serialize the data using protobuf-net and pass it through the Session? Or, if it has to be a string, just use XmlSerializer?

Personally, passing serialized data through the URL seems really bad to me!

GenericTypeTea
Gets my vote! ;-p
Marc Gravell
Heh, but you're Biased Marc ;)
GenericTypeTea
Very true... ;-p
Marc Gravell
XmlSerializer + base64 would be my suggestion.
Matthew Scharley
@Matthew Scharley, protobuf produces much more compact output.
arbiter
+3  A: 

One option here is to pick a delimiter, for example ¤; join the strings, encode them (perhaps UTF8), and pack the bytes as base-64...

    string[] data = {"abc","123", "def"};
    string s = string.Join("¤", data);
    byte[] raw = Encoding.UTF8.GetBytes(s);
    string alphaNumeric = Convert.ToBase64String(raw); // send this

(you may need to handle the few non-alphanumeric characters that base-64 uses).

And to reverse it:

    raw = Convert.FromBase64String(alphaNumeric);
    s = Encoding.UTF8.GetString(raw);
    data = s.Split('¤');


If you want to send key/value pairs... well, the obvious choice would be query-string parameters themselves, since they are designed for this. But if you need it as a byte-stream:

    var data = new DbConnectionStringBuilder();
    data["foo"] = "abc";
    data["bar"] = "123 + ;la";
    string s = data.ConnectionString;

    byte[] raw = Encoding.UTF8.GetBytes(s);
    string alphaNumeric = Convert.ToBase64String(raw); // send this

    raw = Convert.FromBase64String(alphaNumeric);
    s = Encoding.UTF8.GetString(raw);
    data.ConnectionString = s;
    foreach (string key in data.Keys)
    {
        Console.WriteLine(key + "=" + data[key]);
    }
Marc Gravell
I like the idea of using the DbConnectionStringBuilder. Never thought of using it this way :-)
Rune Grimstad
A: 

you can serialize your dictionary/hashtable to JSON, and then change it to base64 (just to make it a tad less visible and resolve possible usage of URL characters etc). or you can just URLEncode it.

Yonatan Karni
A: 

You can use standard .Net serialization and serialize your object to a MemoryStream. You can then read out the contents of the MemoryStream as a byte array and use Convert.ToBase64String on the array to get a string representation of it.

To deserialize it you can do the opposite.

If you are worried that the serialized object is too large, you can wrap the MemoryStream in a System.IO.Compression.DeflateStream to compress it.

Rune Grimstad
That seems overkill just to send a few strings - and it is entirely non-portable...?
Marc Gravell
@marc - It may be overkill, but his question is vague (... and maybe a few ints) and using serialization (and possibly deflate) is a general solution that will work in most cases.
Rune Grimstad
A: 

Thank you all, putting it together I wrote a test console app. I was a bit disappointed that the resulting string was so long.

My example implements a DeflateStream, which for my datasize probably introduces more overhead than it saves with compression. But even without the compression it was still pretty big.

What I was hoping to achieve was to make something slightly more compact (obfuscation for the user was a plus, but not critical) - I suspect that it'd actually be better for me to use a plain old parameterized string. Maybe JSON might be ok, but I'm using ASP.net 2.0, and I don't think that I get a readybaked json serializer there.

Nonetheless, I learnt something new and interesting, so thanks for that!

    static void Main(string[] args)
    {
        Hashtable ht1 = new Hashtable(1);
        ht1.Add("name", "bob");
        Console.WriteLine(ToCompactString(ht1));

        Console.WriteLine();

        string str = "name:bob";
        Console.WriteLine(ToCompactString(str));
        Console.ReadLine();
    }

    private static string ToCompactString(object obj)
    {
        var ms = new MemoryStream();
        var ds = new DeflateStream(ms, CompressionMode.Compress);
        var bf = new BinaryFormatter();

        bf.Serialize(ds, obj);
        byte[] bytes = ms.ToArray();
        ds.Close();
        ms.Close();
        string result = Convert.ToBase64String(bytes);
        return result;
    }
With the second way I mentioned (DbConnectionStringBuilder, UTF8, base-64), this "name"="bob" example is "bmFtZT1ib2I=" - is that so huge? By the way - compression on short data often *increases* the size... perhaps if you'd tried the two upvoted answers?
Marc Gravell
I agree with Marc here. This solution is most probably much more complex than what you need.
Rune Grimstad