Get params from a URL
I figure HttpUtility.ParseQueryString is just incredibly robust, and you likely are missing something. But I can't spot anything in particular and it's likely that without deep research you won't be able to cover all the cases which were clearly studied and thought out in Microsoft's implementation. However, I think your implementation can be refactored to be easier to read and maintain by using regular expressions instead of brute force string splitting. I present the following in F# which hopefully you can translate easily enough to C# (the key functionality relies on the same .NET libraries available in both languages). I'm still new to regex writing myself, so I'm sure it's not as robust as it could be, but it seems to work well for all the typical cases I tested (generally assumes query string is not malformed, allows no query string, allows empty values but not empty keys, accounts for possible # delimiter after query string part):

open System
open System.Text.RegularExpressions
let uriParams uri =
    let matches = Regex.Matches(uri, @"[\?&amp;](([^&amp;=]+)=([^&amp;=#]*))", RegexOptions.Compiled)
    seq { //create a sequence of key, value tuples extracted from the matches
        for m in matches do 
            yield Uri.UnescapeDataString(m.Groups.[2].Value), Uri.UnescapeDataString(m.Groups.[3].Value)
    } |&gt; dict // convert the sequence of key, value tuples into an immutable IDictionary


Update

I went ahead and translated to C#:

using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;

...

static Dictionary&lt;string, string&gt; GetParams(string uri)
{
    var matches = Regex.Matches(uri, @"[\?&amp;](([^&amp;=]+)=([^&amp;=#]*))", RegexOptions.Compiled);
    var keyValues = new Dictionary&lt;string, string&gt;(matches.Count);
    foreach (Match m in matches)
        keyValues.Add(Uri.UnescapeDataString(m.Groups[2].Value), Uri.UnescapeDataString(m.Groups[3].Value));

    return keyValues;
}


Update 2

Here's a more functional C# version:

using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;

...

static Dictionary&lt;string, string&gt; GetParams(string uri)
{
    var matches = Regex.Matches(uri, @"[\?&amp;](([^&amp;=]+)=([^&amp;=#]*))", RegexOptions.Compiled);
    return matches.Cast&lt;Match&gt;().ToDictionary(
        m =&gt; Uri.UnescapeDataString(m.Groups[2].Value),
        m =&gt; Uri.UnescapeDataString(m.Groups[3].Value)
    );
}


Edit

I updated the regex to address the very important consideration of the # delimiter that @Visionary pointed out. That is probably the biggest thing missing from your own implementation functionality-wise.  Also, here is a list of some cases I tested (using the F# version):

uriParams "http://www.foo.com" // []
uriParams "http://www.foo.com?" // []
uriParams "http://www.foo.com?q=" // [("q","")]
uriParams "http://www.foo.com?q=search&amp;doit=no" // [("q","search"), ("doit","no")]
uriParams "http://www.foo.com?q=search&amp;doit=no&amp;go=further" // [("q","search"), ("doit","no"), ("go","further")]
uriParams "http://www.foo.com?q=&amp;doit=no" // [("q",""), ("doit","no")]
uriParams "http://www.foo.com?q=&amp;doit=no&amp;=&amp;test&amp;good=true" //[("q",""), ("doit","no"), ("good","true")]
uriParams "http://www.foo.com?q=search&amp;doit=no#validationError"  // [("q","search"), ("doit","no")]
uriParams "http://www.foo.com?q=search&amp;doit=no#validationError=true"  // [("q","search"), ("doit","no")]
uriParams "http://www.foo.com?q=se%20arch&amp;do%20it=no" // [("q","se arch"), ("do it","no")]
uriParams "http://www.foo.com?q=search&amp;doit=#validationError"  // [("q","search"), ("doit","")]