将字典转换为URL参数字符串?

34

有没有一种方法可以将代码中的字典转换为URL参数字符串?

例如:

// An example list of parameters
Dictionary<string, object> parameters ...;
foreach (Item in List)
{
    parameters.Add(Item.Name, Item.Value);
}

string url = "http://www.somesite.com?" + parameters.XX.ToString();

在MVC的HtmlHelpers中,可以使用UrlHelper(或者在控制器中使用Url)生成URL,但是在Web Forms的代码后台中,不存在此HtmlHelper。

string url = UrlHelper.GenerateUrl("Default", "Action", "Controller", 
    new RouteValueDictionary(parameters), htmlHelper.RouteCollection , 
    htmlHelper.ViewContext.RequestContext, true);

在 MVC/Web Forms 应用程序中,如何在 C# Web Forms 代码后台完成这个操作而不使用 MVC Helper?

13个回答

67

一个方法是:

var url = string.Format("http://www.yoursite.com?{0}",
    HttpUtility.UrlEncode(string.Join("&",
        parameters.Select(kvp =>
            string.Format("{0}={1}", kvp.Key, kvp.Value)))));

你也可以使用在C#6中引入的字符串插值:

var url = $"http://www.yoursite.com?{HttpUtility.UrlEncode(string.Join("&", parameters.Select(kvp => $"{kvp.Key}={kvp.Value}")))}";

如果您不需要,可以摆脱UrlEncode,我只是为了完整性而添加它。


不太高效:string.Format 重复了 (params.Count + 1) 次,创建了 IEnumerator<T> 对象,调用了很多方法。需要创建匿名方法。为了简单地连接字符串做了很多工作。 - Stas BZ
7
如果您不将http://www.yoursite.com?的部分放在UrlEncode之外,结果会像这样:http%3a%2f%2fwww.yoursite.com%3f ... 我会对键和值进行编码,而不是其他任何内容。类似这样:$"http ://www.yoursite.com?{string.Join("&", parameters.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}"))}" - Wolf5
19
这是一个无效的答案。 HttpUtility.UrlEncode("a=b&c=d")会编码'='和'&'字符,返回"a%3db%26c%3dd"。正确的方法是: $"https://example.com?{string.Join("&", parameters.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}"))}" - Cluster
3
我认为没有必要对字典键进行 URL 编码,而只需对值进行编码。以下方法对我来说是可行的:使用 string.Join("&", parameters.Select(kvp => $"{kvp.Key}={HttpUtility.UrlEncode(kvp.Value)}")) 对值进行 URL 编码。 - hubert17
1
这个功能无法正常工作,它也会编码 "=" 和 "&" 字符。 - MAXE

31
你可以使用Microsoft.AspNetCore.WebUtilities中的QueryHelpers:
string url = QueryHelpers.AddQueryString("https://me.com/xxx.js", dictionary);

1
这应该是被接受的答案(至少在.NET Core 3.1+中)。AddQueryString有一个重载,它接受一个字典,让您将查询键/值附加到现有字符串URL - 完美。 - qJake
Microsoft.AspNetCore.WebUtilities 已被弃用。 - Peter Riesz

15

也许可以创建一个静态辅助类:

public static string QueryString(IDictionary<string, object> dict)
{
    var list = new List<string>();
    foreach(var item in dict)
    {
        list.Add(item.Key + "=" + item.Value);
    }
    return string.Join("&", list);
}

15

我并不是说这个选项更好(个人认为它不是),但我在这里只是想说它存在。

QueryBuilder 类:

var queryStringDictionary = new Dictionary<string, string>
{
    { "username", "foo" },
    { "password", "bar" }
};

var queryBuilder = new QueryBuilder(queryStringDictionary);
queryBuilder.Add("type", "user");

//?username=foo&password=bar&type=user
QueryString result = queryBuilder.ToQueryString();

2
你为什么认为这不是更好的选择?我认为这更好,因为你不必自己编码值。这是一个更小的解决方案。 - Ryan Allen

5

最简单的方法:

string s = string.Join("&", dd.Select((x) => x.Key + "=" + x.Value.ToString()));

但是代码变短并不意味着更高效。最好使用 StringBuilderAppend 方法:

first = true;
foreach(var item in dd)
{
    if (first)
        first = false;
    else
        sb.Append('&');
    sb.Append(item.Key);
    sb.Append('=');
    sb.Append(item.Value.ToString());
}

1
一如既往,这要视情况而定。 - Chris McKee

4
您可以使用 IEnumerable<string>String.Join 来实现:
var parameters = new List<string>();
foreach (var item in List)
{
    parameters.Add(item.Name + "=" + item.Value.ToString());
}

string url = "http://www.somesite.com?" + String.Join("&", parameters);

或者更短
string baseUri = "http://www.somesite.com?";
string url = baseUri + String.Join("&", list.Select(i => $"{i.Name}={i.Value}"));

我显然漏掉了什么,因为看起来如果你传入 { "abc" -> "def", "ghi" -> "jkl" } 这将会产生 abc=&def&ghi=&jkl - anon

3
// this is wrong
var url = string.Format("http://www.yoursite.com?{0}",
    HttpUtility.UrlEncode(string.Join("&",
        parameters.Select(kvp =>
            string.Format("{0}={1}", kvp.Key, kvp.Value))))); 

我尝试了Mike的答案中提供的代码,但是它没有起作用。实际上这是错误的。让我们看看那个答案有什么问题。

如果你写HttpUtility.UrlEncode("a=1&b=2"),它会编码=&并返回"a%3d1%26b%3d2",这是不正确的。所以,你需要像这样只编码键和值:

// this works
var encodedUrl = string.Format("http://www.yoursite.com?{0}", 
    string.Join("&", parameters.Select(kvp => string.Format("{0}={1}", 
        HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value)))));

或者(使用字符串插值)

var encodedUrl = $"http://www.yoursite.com?{string.Join("&", parameters.Select(kvp => $"{HttpUtility.UrlEncode(kvp.Key)}={HttpUtility.UrlEncode(kvp.Value)}"))}";

2
我已经编写了这些扩展方法: 将查询字符串添加到基本URL:
public static string AddQueryString(this string url, IDictionary<string, object> parameters) => 
     $"{url}?{parameters.ToQueryString()}";

将参数字典转换为查询字符串:

private static string ToQueryString(this IDictionary<string, object> parameters) => 
    string.Join("&", parameters.Select(x => $"{x.Key}={x.Value}"));

转换为查询字符串的实际代码:

string.Join("&", parameters.Select(x => $"{x.Key}={x.Value}"));

编辑:

在生产环境中使用时,请考虑在此函数内使用URL.Encode对参数进行编码。如果您使用此功能,请确保字典中的参数尚未被编码。


@CarlosMuñoz 的实现细节 - Nick N.
3
是的,正确的实现细节很重要。否则可能会导致错误。 - Carlos Muñoz
同意Carlos的观点:string.Join("&", parameters.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value.ToString())}")); - Thymine
@Thymine 我添加了一条注释。在我的情况下,参数已经被编码在字典中。 - Nick N.

1
这是您正在寻找的内容(未测试的代码)吗?
StringBuilder sb = new StringBuilder();
sb.Append("http://www.somesite.com?");

foreach(var item in parameters)
{
sb.append(string.Format("{0}={1}&", item.Key, item.Value))
}
string finalUrl = sb.ToString();
finalUrl = finalUrl.Remove(finalUrl.LasIndexOf("&"));

1
你可以尝试这个:

var parameters = new Dictionary<string, string>(); // You pass this
var url = "http://www.somesite.com?";
int i = 0;
foreach (var item in parameters)
{
    url += item.Key + "=" + item.Value;
    url += i != parameters.Count ? "&" : string.Empty;
    i++;
}

return url;

我还没有运行这个逻辑,但这可能会帮助你。

如果你在WebForms中使用UrlRouting,那就是另一回事了。

请看:

http://msdn.microsoft.com/en-us/library/cc668201(v=vs.90).aspx


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接