How to build a query string for a URL in C#?

前端 未结 30 2502
借酒劲吻你
借酒劲吻你 2020-11-22 01:55

A common task when calling web resources from a code is building a query string to including all the necessary parameters. While by all means no rocket science, there are so

相关标签:
30条回答
  • 2020-11-22 02:28

    Assuming that you want to reduce dependencies to other assemblies and to keep things simple, you can do:

    var sb = new System.Text.StringBuilder();
    
    sb.Append("a=" + HttpUtility.UrlEncode("TheValueOfA") + "&");
    sb.Append("b=" + HttpUtility.UrlEncode("TheValueOfB") + "&");
    sb.Append("c=" + HttpUtility.UrlEncode("TheValueOfC") + "&");
    sb.Append("d=" + HttpUtility.UrlEncode("TheValueOfD") + "&");
    
    sb.Remove(sb.Length-1, 1); // Remove the final '&'
    
    string result = sb.ToString();
    

    This works well with loops too. The final ampersand removal needs to go outside of the loop.

    Note that the concatenation operator is used to improve readability. The cost of using it compared to the cost of using a StringBuilder is minimal (I think Jeff Atwood posted something on this topic).

    0 讨论(0)
  • 2020-11-22 02:30

    The code below is taken off the HttpValueCollection implementation of ToString, via ILSpy, which gives you a name=value querystring.

    Unfortunately HttpValueCollection is an internal class which you only ever get back if you use HttpUtility.ParseQueryString(). I removed all the viewstate parts to it, and it encodes by default:

    public static class HttpExtensions
    {
        public static string ToQueryString(this NameValueCollection collection)
        {
            // This is based off the NameValueCollection.ToString() implementation
            int count = collection.Count;
            if (count == 0)
                return string.Empty;
    
            StringBuilder stringBuilder = new StringBuilder();
    
            for (int i = 0; i < count; i++)
            {
                string text = collection.GetKey(i);
                text = HttpUtility.UrlEncodeUnicode(text);
                string value = (text != null) ? (text + "=") : string.Empty;
                string[] values = collection.GetValues(i);
                if (stringBuilder.Length > 0)
                {
                    stringBuilder.Append('&');
                }
                if (values == null || values.Length == 0)
                {
                    stringBuilder.Append(value);
                }
                else
                {
                    if (values.Length == 1)
                    {
                        stringBuilder.Append(value);
                        string text2 = values[0];
                        text2 = HttpUtility.UrlEncodeUnicode(text2);
                        stringBuilder.Append(text2);
                    }
                    else
                    {
                        for (int j = 0; j < values.Length; j++)
                        {
                            if (j > 0)
                            {
                                stringBuilder.Append('&');
                            }
                            stringBuilder.Append(value);
                            string text2 = values[j];
                            text2 = HttpUtility.UrlEncodeUnicode(text2);
                            stringBuilder.Append(text2);
                        }
                    }
                }
            }
    
            return stringBuilder.ToString();
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:30

    This is the identical to the accepted answer except slightly more compact:

    private string ToQueryString(NameValueCollection nvc)
    {
        return "?" + string.Join("&", nvc.AllKeys.Select(k => string.Format("{0}={1}", 
            HttpUtility.UrlEncode(k), 
            HttpUtility.UrlEncode(nvc[k]))));
    }
    
    0 讨论(0)
  • 2020-11-22 02:31

    While not elegant, I opted for a simpler version that doesn't use NameValueCollecitons - just a builder pattern wrapped around StringBuilder.

    public class UrlBuilder
    {
        #region Variables / Properties
    
        private readonly StringBuilder _builder;
    
        #endregion Variables / Properties
    
        #region Constructor
    
        public UrlBuilder(string urlBase)
        {
            _builder = new StringBuilder(urlBase);
        }
    
        #endregion Constructor
    
        #region Methods
    
        public UrlBuilder AppendParameter(string paramName, string value)
        {
            if (_builder.ToString().Contains("?"))
                _builder.Append("&");
            else
                _builder.Append("?");
    
            _builder.Append(HttpUtility.UrlEncode(paramName));
            _builder.Append("=");
            _builder.Append(HttpUtility.UrlEncode(value));
    
            return this;
        }
    
        public override string ToString()
        {
            return _builder.ToString();
        }
    
        #endregion Methods
    }
    

    Per existing answers, I made sure to use HttpUtility.UrlEncode calls. It's used like so:

    string url = new UrlBuilder("http://www.somedomain.com/")
                 .AppendParameter("a", "true")
                 .AppendParameter("b", "muffin")
                 .AppendParameter("c", "muffin button")
                 .ToString();
    // Result: http://www.somedomain.com?a=true&b=muffin&c=muffin%20button
    
    0 讨论(0)
  • 2020-11-22 02:32

    I added the following method to my PageBase class.

    protected void Redirect(string url)
        {
            Response.Redirect(url);
        }
    protected void Redirect(string url, NameValueCollection querystrings)
        {
            StringBuilder redirectUrl = new StringBuilder(url);
    
            if (querystrings != null)
            {
                for (int index = 0; index < querystrings.Count; index++)
                {
                    if (index == 0)
                    {
                        redirectUrl.Append("?");
                    }
    
                    redirectUrl.Append(querystrings.Keys[index]);
                    redirectUrl.Append("=");
                    redirectUrl.Append(HttpUtility.UrlEncode(querystrings[index]));
    
                    if (index < querystrings.Count - 1)
                    {
                        redirectUrl.Append("&");
                    }
                }
            }
    
            this.Redirect(redirectUrl.ToString());
        }
    

    To call:

    NameValueCollection querystrings = new NameValueCollection();    
    querystrings.Add("language", "en");
    querystrings.Add("id", "134");
    this.Redirect("http://www.mypage.com", querystrings);
    
    0 讨论(0)
  • 2020-11-22 02:33

    You can create a new writeable instance of HttpValueCollection by calling System.Web.HttpUtility.ParseQueryString(string.Empty), and then use it as any NameValueCollection. Once you have added the values you want, you can call ToString on the collection to get a query string, as follows:

    NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
    
    queryString.Add("key1", "value1");
    queryString.Add("key2", "value2");
    
    return queryString.ToString(); // Returns "key1=value1&key2=value2", all URL-encoded
    

    The HttpValueCollection is internal and so you cannot directly construct an instance. However, once you obtain an instance you can use it like any other NameValueCollection. Since the actual object you are working with is an HttpValueCollection, calling ToString method will call the overridden method on HttpValueCollection, which formats the collection as a URL-encoded query string.

    After searching SO and the web for an answer to a similar issue, this is the most simple solution I could find.

    .NET Core

    If you're working in .NET Core, you can use the Microsoft.AspNetCore.WebUtilities.QueryHelpers class, which simplifies this greatly.

    https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers

    Sample Code:

    const string url = "https://customer-information.azure-api.net/customers/search/taxnbr";
    var param = new Dictionary<string, string>() { { "CIKey", "123456789" } };
    
    var newUrl = new Uri(QueryHelpers.AddQueryString(url, param));
    
    0 讨论(0)
提交回复
热议问题