C# HttpUtility.ParseQueryString的可移植类库(PCL)版本

C# HttpUtility.ParseQueryString的可移植类库(PCL)版本,c#,asp.net,.net,portable-class-library,system.web,C#,Asp.net,.net,Portable Class Library,System.web,System.Web中是否包含HttpUtility.ParseQueryString的可移植类库(PCL)版本或我可以使用的代码?我想读取一个非常复杂的URL。HttpUtility.ParseQueryString返回从NameValueCollection继承的HttpValueCollection(内部类)NameValueCollection是键值对的集合,类似于字典,但它支持重复项,维护顺序,并且只实现IEnumerable(此集合是预泛型)名称值集合 我的解决方案(部分从.NET

System.Web中是否包含HttpUtility.ParseQueryString的可移植类库(PCL)版本或我可以使用的代码?我想读取一个非常复杂的URL。

HttpUtility.ParseQueryString
返回从
NameValueCollection
继承的
HttpValueCollection
(内部类)
NameValueCollection
是键值对的集合,类似于字典,但它支持重复项,维护顺序,并且只实现
IEnumerable
(此集合是预泛型)名称值集合

我的解决方案(部分从.NET framework中提升和修改)是将HttpValueCollection替换为
Collection
,其中
HttpValue
只是一个键值对

public sealed class HttpUtility
{
    public static HttpValueCollection ParseQueryString(string query)
    {
        if (query == null)
        {
            throw new ArgumentNullException("query");
        }

        if ((query.Length > 0) && (query[0] == '?'))
        {
            query = query.Substring(1);
        }

        return new HttpValueCollection(query, true);
    }
}

public sealed class HttpValue
{
    public HttpValue()
    {
    }

    public HttpValue(string key, string value)
    {
        this.Key = key;
        this.Value = value;
    }

    public string Key { get; set; }
    public string Value { get; set; }
}

public class HttpValueCollection : Collection<HttpValue>
{
    #region Constructors

    public HttpValueCollection()
    {
    }

    public HttpValueCollection(string query)
        : this(query, true)
    {
    }

    public HttpValueCollection(string query, bool urlencoded)
    {
        if (!string.IsNullOrEmpty(query))
        {
            this.FillFromString(query, urlencoded);
        }
    } 

    #endregion

    #region Parameters

    public string this[string key]
    {
        get { return this.First(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase)).Value; }
        set { this.First(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase)).Value = value; }
    }

    #endregion

    #region Public Methods

    public void Add(string key, string value)
    {
        this.Add(new HttpValue(key, value));
    }

    public bool ContainsKey(string key)
    {
        return this.Any(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
    }

    public string[] GetValues(string key)
    {
        return this.Where(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase)).Select(x => x.Value).ToArray();
    }

    public void Remove(string key)
    {
        this.Where(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase))
            .ToList()
            .ForEach(x => this.Remove(x));
    }

    public override string ToString()
    {
        return this.ToString(true);
    }

    public virtual string ToString(bool urlencoded)
    {
        return this.ToString(urlencoded, null);
    }

    public virtual string ToString(bool urlencoded, IDictionary excludeKeys)
    {
        if (this.Count == 0)
        {
            return string.Empty;
        }

        StringBuilder stringBuilder = new StringBuilder();

        foreach (HttpValue item in this)
        {
            string key = item.Key;

            if ((excludeKeys == null) || !excludeKeys.Contains(key))
            {
                string value = item.Value;

                if (urlencoded)
                {
                    // If .NET 4.5 and above (Thanks @Paya)
                    key = WebUtility.UrlDecode(key);
                    // If .NET 4.0 use this instead.
                    // key = Uri.EscapeDataString(key);
                }

                if (stringBuilder.Length > 0)
                {
                    stringBuilder.Append('&');
                }

                stringBuilder.Append((key != null) ? (key + "=") : string.Empty);

                if ((value != null) && (value.Length > 0))
                {
                    if (urlencoded)
                    {
                        value = Uri.EscapeDataString(value);
                    }

                    stringBuilder.Append(value);
                }
            }
        }

        return stringBuilder.ToString();
    } 

    #endregion

    #region Private Methods

    private void FillFromString(string query, bool urlencoded)
    {
        int num = (query != null) ? query.Length : 0;
        for (int i = 0; i < num; i++)
        {
            int startIndex = i;
            int num4 = -1;
            while (i < num)
            {
                char ch = query[i];
                if (ch == '=')
                {
                    if (num4 < 0)
                    {
                        num4 = i;
                    }
                }
                else if (ch == '&')
                {
                    break;
                }
                i++;
            }
            string str = null;
            string str2 = null;
            if (num4 >= 0)
            {
                str = query.Substring(startIndex, num4 - startIndex);
                str2 = query.Substring(num4 + 1, (i - num4) - 1);
            }
            else
            {
                str2 = query.Substring(startIndex, i - startIndex);
            }

            if (urlencoded)
            {
                this.Add(Uri.UnescapeDataString(str), Uri.UnescapeDataString(str2));
            }
            else
            {
                this.Add(str, str2);
            }

            if ((i == (num - 1)) && (query[i] == '&'))
            {
                this.Add(null, string.Empty);
            }
        }
    } 

    #endregion
}
公共密封类HttpUtility
{
公共静态HttpValueCollection ParseQueryString(字符串查询)
{
if(查询==null)
{
抛出新的ArgumentNullException(“查询”);
}
如果((query.Length>0)和&(query[0]=='?'))
{
query=query.Substring(1);
}
返回新的HttpValueCollection(查询,true);
}
}
公共密封类HttpValue
{
公共HttpValue()
{
}
公共HttpValue(字符串键、字符串值)
{
这个。键=键;
这个。值=值;
}
公共字符串密钥{get;set;}
公共字符串值{get;set;}
}
公共类HttpValueCollection:集合
{
#区域构造函数
公共HttpValueCollection()
{
}
公共HttpValueCollection(字符串查询)
:this(查询,true)
{
}
公共HttpValueCollection(字符串查询,boolUrlEncoded)
{
如果(!string.IsNullOrEmpty(查询))
{
this.FillFromString(查询,urlencoded);
}
} 
#端区
#区域参数
公共字符串此[字符串键]
{
获取{返回this.First(x=>string.Equals(x.Key,Key,StringComparison.OrdinalIgnoreCase)).Value;}
设置{this.First(x=>string.Equals(x.Key,Key,StringComparison.OrdinalIgnoreCase)).Value=Value;}
}
#端区
#区域公共方法
公共void添加(字符串键、字符串值)
{
添加(新的HttpValue(key,value));
}
公共bool ContainsKey(字符串键)
{
返回这个.Any(x=>string.Equals(x.Key,Key,StringComparison.OrdinalIgnoreCase));
}
公共字符串[]获取值(字符串键)
{
返回这个.Where(x=>string.Equals(x.Key,Key,StringComparison.OrdinalIgnoreCase)).Select(x=>x.Value.ToArray();
}
公共无效删除(字符串键)
{
其中(x=>string.Equals(x.Key,Key,StringComparison.OrdinalIgnoreCase))
托利斯先生()
.ForEach(x=>this.Remove(x));
}
公共重写字符串ToString()
{
返回此.ToString(true);
}
公共虚拟字符串ToString(bool-urlencoded)
{
返回此.ToString(urlencoded,null);
}
公共虚拟字符串到字符串(bool urlencoded,IDictionary excludeKeys)
{
如果(this.Count==0)
{
返回字符串。空;
}
StringBuilder StringBuilder=新的StringBuilder();
foreach(本文件中的HttpValue项)
{
字符串键=item.key;
如果((excludeKeys==null)| |!excludeKeys.Contains(key))
{
字符串值=item.value;
如果(URL编码)
{
//如果.NET 4.5及以上版本(谢谢@Paya)
key=WebUtility.UrlDecode(key);
//如果使用.NET4.0,请改用此选项。
//key=Uri.EscapeDataString(key);
}
如果(stringBuilder.Length>0)
{
stringBuilder.Append('&');
}
stringBuilder.Append((key!=null)?(key+“=”):string.Empty);
如果((value!=null)&&(value.Length>0))
{
如果(URL编码)
{
value=Uri.EscapeDataString(值);
}
stringBuilder.Append(值);
}
}
}
返回stringBuilder.ToString();
} 
#端区
#区域私有方法
私有void FillFromString(字符串查询,bool-urlencoded)
{
int num=(查询!=null)?查询。长度:0;
for(int i=0;i=0)
{
str=query.Substring(startIndex,num4-startIndex);
str2=query.Substring(num4+1,(i-num4)-1);
}
其他的
{
str2=query.Substring(startIndex,i-startIndex);
}
如果(URL编码)
{
Add(Uri.unescapedastring(str),Uri.unescapedastring(str2));
}
其他的
{
添加(str,str2);
}
if((i==(num-1))&&(查询[i]='&'))
{
this.Add(null,string.Empty);
}
}
} 
#端区
}
更新

更新后,HttpValueCollection现在继承自集合,而不是注释中突出显示的列表

更新2

更新为使用WebUtili
public static class HttpUtility
{
    public static Dictionary<string, string> ParseQueryString(Uri uri)
    {
        var query = uri.Query.Substring(uri.Query.IndexOf('?') + 1); // +1 for skipping '?'
        var pairs = query.Split('&');
        return pairs
            .Select(o => o.Split('='))
            .Where(items => items.Count() == 2)
            .ToDictionary(pair => Uri.UnescapeDataString(pair[0]),
                pair => Uri.UnescapeDataString(pair[1]));
    }
}
public class HttpParseQueryValuesTests
{
    [TestCase("http://www.example.com", 0, "", "")]
    [TestCase("http://www.example.com?query=value", 1, "query", "value")]
    public void When_parsing_http_query_then_should_have_these_values(string uri, int expectedParamCount,
        string expectedKey, string expectedValue)
    {
        var queryParams = HttpUtility.ParseQueryString(new Uri(uri));
        queryParams.Count.Should().Be(expectedParamCount);

        if (queryParams.Count > 0)
            queryParams[expectedKey].Should().Be(expectedValue);
    }
}
using Flurl;

var url = new Url("http://...");
// get values from url.QueryParams dictionary