Вопрос

Is there a way to convert a Dictionary in code into a url parameter string?

e.g.

// 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();

Inside MVC HtmlHelpers you can generate URLs with the UrlHelper (or Url in controllers) but in Web Forms code-behind the this HtmlHelper is not available.

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

How could this be done in C# Web Forms code-behind (in an MVC/Web Forms app) without the MVC helper?

Это было полезно?

Решение

One approach would be:

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

You could also use string interpolation as introduced in C#6:

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

And you could get rid of the UrlEncode if you don't need it, I just added it for completeness.

Другие советы

You can use QueryHelpers from Microsoft.AspNetCore.WebUtilities:

string url = QueryHelpers.AddQueryString("https://me.com/xxx.js", dictionary);

Make a static helper class perhaps:

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);
}

I'm not saying this option is better (I personally think it's not), but I'm here just to say it exists.

The QueryBuilder class:

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();

the most short way:

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

But shorter does not mean more efficiency. Better use StringBuilder and Append method:

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());
}

You could use a IEnumerable<string> and 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);

or shorter

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

I have written these extensions methods:

Add querystring to base url:

public static string AddQueryString(this string url, IDictionary<string, object> parameters) => 
     $"{url}?{parameters.ToQueryString()}";

Convert dictionary of parameters to query string:

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

Actual code to convert to query string:

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

Edit:

When using in production consider encoding the parameters with URL.Encode within this function. If you use this make sure the parameters in the dictionary are not already encoded.

// 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))))); 

I tried this code from the accepted answer (of Mike), but it did not worked. Actually that is wrong. Let's see what is wrong with that answer. If you write HttpUtility.UrlEncode("a=1&b=2"), it will also encode = and & and returns "a%3d1%26b%3d2" which is not correct. So, you need to encode just keys and values like this:

// 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)))));

Or (using string interpolation)

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

Is this what you looking for (untested code)?

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("&"));

You may try this:

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;

I have not run the logic, but this might help you.

If you would be UrlRouting in webforms then it would be a different story.

Check out:

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

Using Newtonsoft JSON you can can quickly serialize an anonymous object into a http query by making extension functions.

This method also supports passing arrays as parameters to PHP using brackets.

    public static string Join(this List<string> a, string seperator)
    {
        return string.Join(seperator, a.ToArray());
    }

    public static string ToHttpQuery(this object a)
    {
        string result = "";

        foreach (var b in JObject.FromObject(a))
        {
            if (result.Length > 0)
                result += "&";

            if (b.Value.Type == JTokenType.Array)
                result += b.Value.Select(x => b.Key + "[]=" + Uri.EscapeDataString(x.ToString())).ToList().Join("&");
            else
                result += b.Key + "=" + Uri.EscapeDataString(b.Value.ToString());
        }

        return result;
    }

Example usage:

        string query = new
        {
            test = new string[] { "ree", "roo" },
            myId = 123,
            port = PORTS.MAIN_INTERFACE_IO,
            targetUrl = "http://example.com/?fee=123"
        }.ToHttpQuery();
        
        string myUrl = "http://example.com/?" + query;

This is old also there are other correct answers.

However, the builtin HttpValueCollection already does escaping correctly, the only trick then is to rewrite the dictionary to it.

This means the following snippet reuses the implementation from the base class library and would be useful for anyone not using the NET.Core implementations (for example - people who still code against NET.Framework)

public static string ToQueryString( IDictionary<string, object> dict )
{
    var collection = HttpUtility.ParseQueryString(string.Empty);

    foreach ( var key in dict.Keys )
    {
        collection.Add( key, dict[key].ToString() );
    }

    return collection.ToString();
}

You can add the following class to the project and use the extension method.

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

public static class CollectionExtensions {
    public static string ToQueryString(this IDictionary<string, string> dict)
    {

    if (dict.Count == 0) return string.Empty;

    var buffer = new StringBuilder();
    int count = 0;
    bool end = false;

    foreach (var key in dict.Keys)
    {
        if (count == dict.Count - 1) end = true;

        if (end)
            buffer.AppendFormat("{0}={1}", key, dict[key]);
        else
            buffer.AppendFormat("{0}={1}&", key, dict[key]);

        count++;
    }

    return buffer.ToString();
}
}

to use the code:

var queryString = dictionary.ToQueryString();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top