将值附加到查询字符串

我有一组类似于下面列表中的url

  • http://somesite.example/backup/lol.php?id=1&server=4&location=us
  • http://somesite.example/news.php?article=1&lang=en

我已经设法获得查询字符串使用以下代码:

myurl = longurl.Split('?');
NameValueCollection qs = HttpUtility.ParseQueryString(myurl [1]);


foreach (string lol in qs)
{
// results will return
}
但是它只返回参数像 id服务器位置等等,基于提供的URL。

我需要的是向现有的查询字符串添加/追加值。

例如,使用URL:

http://somesite.example/backup/index.php?action=login&attempts=1

我需要改变查询字符串参数的值:

action = login1

尝试= 11

如你所见,我在后面加了“;1”;对于每个值。我需要从一个字符串中获得一组url,其中包含不同的查询字符串,并在结尾为每个参数添加一个值。再次将它们添加到列表中。

240921 次浏览

你可以使用HttpUtility.ParseQueryString方法和UriBuilder方法,它提供了一种很好的方式来处理查询字符串参数,而不用担心解析、URL编码、…

string longurl = "http://somesite.example/news.php?article=1&lang=en";
var uriBuilder = new UriBuilder(longurl);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query["action"] = "login1";
query["attempts"] = "11";
uriBuilder.Query = query.ToString();
longurl = uriBuilder.ToString();
// "http://somesite.example:80/news.php?article=1&lang=en&action=login1&attempts=11"

我将达林的回答包装成一个很好地可重用的扩展方法。

public static class UriExtensions
{
/// <summary>
/// Adds the specified parameter to the Query String.
/// </summary>
/// <param name="url"></param>
/// <param name="paramName">Name of the parameter to add.</param>
/// <param name="paramValue">Value for the parameter to add.</param>
/// <returns>Url with added parameter.</returns>
public static Uri AddParameter(this Uri url, string paramName, string paramValue)
{
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query[paramName] = paramValue;
uriBuilder.Query = query.ToString();


return uriBuilder.Uri;
}
}

我希望这能有所帮助!

提供的答案有相对url的问题,如"/some/path/" 这是URI和UriBuilder类的一个限制,这是相当难以理解的,因为我不认为在查询操作时相对url会有任何问题

下面是一个在。net 4中编写和测试的解决方法,它既适用于绝对路径也适用于相对路径:

(小提示:这应该也适用于。net 4.5,你只需要将propInfo.GetValue(values, null)改为propInfo.GetValue(values))

  public static class UriExtensions{
/// <summary>
///     Adds query string value to an existing url, both absolute and relative URI's are supported.
/// </summary>
/// <example>
/// <code>
///     // returns "www.domain.example/test?param1=val1&amp;param2=val2&amp;param3=val3"
///     new Uri("www.domain.example/test?param1=val1").ExtendQuery(new Dictionary&lt;string, string&gt; { { "param2", "val2" }, { "param3", "val3" } });
///
///     // returns "/test?param1=val1&amp;param2=val2&amp;param3=val3"
///     new Uri("/test?param1=val1").ExtendQuery(new Dictionary&lt;string, string&gt; { { "param2", "val2" }, { "param3", "val3" } });
/// </code>
/// </example>
/// <param name="uri"></param>
/// <param name="values"></param>
/// <returns></returns>
public static Uri ExtendQuery(this Uri uri, IDictionary<string, string> values) {
var baseUrl = uri.ToString();
var queryString = string.Empty;
if (baseUrl.Contains("?")) {
var urlSplit = baseUrl.Split('?');
baseUrl = urlSplit[0];
queryString = urlSplit.Length > 1 ? urlSplit[1] : string.Empty;
}


NameValueCollection queryCollection = HttpUtility.ParseQueryString(queryString);
foreach (var kvp in values ?? new Dictionary<string, string>()) {
queryCollection[kvp.Key] = kvp.Value;
}
var uriKind = uri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative;
return queryCollection.Count == 0
? new Uri(baseUrl, uriKind)
: new Uri(string.Format("{0}?{1}", baseUrl, queryCollection), uriKind);
}


/// <summary>
///     Adds query string value to an existing url, both absolute and relative URI's are supported.
/// </summary>
/// <example>
/// <code>
///     // returns "www.domain.example/test?param1=val1&amp;param2=val2&amp;param3=val3"
///     new Uri("www.domain.example/test?param1=val1").ExtendQuery(new { param2 = "val2", param3 = "val3" });
///
///     // returns "/test?param1=val1&amp;param2=val2&amp;param3=val3"
///     new Uri("/test?param1=val1").ExtendQuery(new { param2 = "val2", param3 = "val3" });
/// </code>
/// </example>
/// <param name="uri"></param>
/// <param name="values"></param>
/// <returns></returns>
public static Uri ExtendQuery(this Uri uri, object values) {
return ExtendQuery(uri, values.GetType().GetProperties().ToDictionary
(
propInfo => propInfo.Name,
propInfo => { var value = propInfo.GetValue(values, null); return value != null ? value.ToString() : null; }
));
}
}

下面是一组测试行为的单元测试:

  [TestFixture]
public class UriExtensionsTests {
[Test]
public void Add_to_query_string_dictionary_when_url_contains_no_query_string_and_values_is_empty_should_return_url_without_changing_it() {
Uri url = new Uri("http://www.domain.example/test");
var values = new Dictionary<string, string>();
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test")));
}


[Test]
public void Add_to_query_string_dictionary_when_url_contains_hash_and_query_string_values_are_empty_should_return_url_without_changing_it() {
Uri url = new Uri("http://www.domain.example/test#div");
var values = new Dictionary<string, string>();
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test#div")));
}


[Test]
public void Add_to_query_string_dictionary_when_url_contains_no_query_string_should_add_values() {
Uri url = new Uri("http://www.domain.example/test");
var values = new Dictionary<string, string> { { "param1", "val1" }, { "param2", "val2" } };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test?param1=val1&param2=val2")));
}


[Test]
public void Add_to_query_string_dictionary_when_url_contains_hash_and_no_query_string_should_add_values() {
Uri url = new Uri("http://www.domain.example/test#div");
var values = new Dictionary<string, string> { { "param1", "val1" }, { "param2", "val2" } };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test#div?param1=val1&param2=val2")));
}


[Test]
public void Add_to_query_string_dictionary_when_url_contains_query_string_should_add_values_and_keep_original_query_string() {
Uri url = new Uri("http://www.domain.example/test?param1=val1");
var values = new Dictionary<string, string> { { "param2", "val2" } };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test?param1=val1&param2=val2")));
}


[Test]
public void Add_to_query_string_dictionary_when_url_is_relative_contains_no_query_string_should_add_values() {
Uri url = new Uri("/test", UriKind.Relative);
var values = new Dictionary<string, string> { { "param1", "val1" }, { "param2", "val2" } };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("/test?param1=val1&param2=val2", UriKind.Relative)));
}


[Test]
public void Add_to_query_string_dictionary_when_url_is_relative_and_contains_query_string_should_add_values_and_keep_original_query_string() {
Uri url = new Uri("/test?param1=val1", UriKind.Relative);
var values = new Dictionary<string, string> { { "param2", "val2" } };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("/test?param1=val1&param2=val2", UriKind.Relative)));
}


[Test]
public void Add_to_query_string_dictionary_when_url_is_relative_and_contains_query_string_with_existing_value_should_add_new_values_and_update_existing_ones() {
Uri url = new Uri("/test?param1=val1", UriKind.Relative);
var values = new Dictionary<string, string> { { "param1", "new-value" }, { "param2", "val2" } };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("/test?param1=new-value&param2=val2", UriKind.Relative)));
}


[Test]
public void Add_to_query_string_object_when_url_contains_no_query_string_should_add_values() {
Uri url = new Uri("http://www.domain.example/test");
var values = new { param1 = "val1", param2 = "val2" };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test?param1=val1&param2=val2")));
}


[Test]
public void Add_to_query_string_object_when_url_contains_query_string_should_add_values_and_keep_original_query_string() {
Uri url = new Uri("http://www.domain.example/test?param1=val1");
var values = new { param2 = "val2" };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("http://www.domain.example/test?param1=val1&param2=val2")));
}


[Test]
public void Add_to_query_string_object_when_url_is_relative_contains_no_query_string_should_add_values() {
Uri url = new Uri("/test", UriKind.Relative);
var values = new { param1 = "val1", param2 = "val2" };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("/test?param1=val1&param2=val2", UriKind.Relative)));
}


[Test]
public void Add_to_query_string_object_when_url_is_relative_and_contains_query_string_should_add_values_and_keep_original_query_string() {
Uri url = new Uri("/test?param1=val1", UriKind.Relative);
var values = new { param2 = "val2" };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("/test?param1=val1&param2=val2", UriKind.Relative)));
}


[Test]
public void Add_to_query_string_object_when_url_is_relative_and_contains_query_string_with_existing_value_should_add_new_values_and_update_existing_ones() {
Uri url = new Uri("/test?param1=val1", UriKind.Relative);
var values = new { param1 = "new-value", param2 = "val2" };
var result = url.ExtendQuery(values);
Assert.That(result, Is.EqualTo(new Uri("/test?param1=new-value&param2=val2", UriKind.Relative)));
}
}

下面的解决方案适用于ASP。NET 5 (vNext),它使用QueryHelpers类来构建带有参数的URI。

    public Uri GetUri()
{
var location = _config.Get("http://iberia.com");
Dictionary<string, string> values = GetDictionaryParameters();


var uri = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(location, values);
return new Uri(uri);
}


private Dictionary<string,string> GetDictionaryParameters()
{
Dictionary<string, string> values = new Dictionary<string, string>
{
{ "param1", "value1" },
{ "param2", "value2"},
{ "param3", "value3"}
};
return values;
}

结果URI将有http://iberia.com?param1=value1&param2=value2&param3=value3

我喜欢Bjorn的答案,但他提供的解决方案是误导性的,因为该方法更新一个现有的参数,而不是添加它,如果它不存在。为了更安全一点,我在下面对它进行了修改。

public static class UriExtensions
{
/// <summary>
/// Adds or Updates the specified parameter to the Query String.
/// </summary>
/// <param name="url"></param>
/// <param name="paramName">Name of the parameter to add.</param>
/// <param name="paramValue">Value for the parameter to add.</param>
/// <returns>Url with added parameter.</returns>
public static Uri AddOrUpdateParameter(this Uri url, string paramName, string paramValue)
{
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);


if (query.AllKeys.Contains(paramName))
{
query[paramName] = paramValue;
}
else
{
query.Add(paramName, paramValue);
}
uriBuilder.Query = query.ToString();


return uriBuilder.Uri;
}
}

结束了所有URL查询字符串编辑的麻烦

在对Uri类和其他解决方案进行了大量的辛劳和摆弄之后,下面是我的字符串扩展方法来解决我的问题。

using System;
using System.Collections.Specialized;
using System.Linq;
using System.Web;


public static class StringExtensions
{
public static string AddToQueryString(this string url, params object[] keysAndValues)
{
return UpdateQueryString(url, q =>
{
for (var i = 0; i < keysAndValues.Length; i += 2)
{
q.Set(keysAndValues[i].ToString(), keysAndValues[i + 1].ToString());
}
});
}


public static string RemoveFromQueryString(this string url, params string[] keys)
{
return UpdateQueryString(url, q =>
{
foreach (var key in keys)
{
q.Remove(key);
}
});
}


public static string UpdateQueryString(string url, Action<NameValueCollection> func)
{
var urlWithoutQueryString = url.Contains('?') ? url.Substring(0, url.IndexOf('?')) : url;
var queryString = url.Contains('?') ? url.Substring(url.IndexOf('?')) : null;
var query = HttpUtility.ParseQueryString(queryString ?? string.Empty);


func(query);


return urlWithoutQueryString + (query.Count > 0 ? "?" : string.Empty) + query;
}
}

注意,你可以添加微软的Microsoft.AspNetCore.WebUtilities nuget包,然后使用它将值附加到查询字符串:

QueryHelpers.AddQueryString(longurl, "action", "login1")
QueryHelpers.AddQueryString(longurl, new Dictionary<string, string> { { "action", "login1" }, { "attempts", "11" } });

这更令人沮丧,因为现在(.net 5) MS已经将许多(所有)采用字符串而不是Uri的方法标记为过时。

不管怎样,可能操作相对Uris更好的方法是给它它想要的:

var requestUri = new Uri("x://x").MakeRelativeUri(
new UriBuilder("x://x") { Path = path, Query = query }.Uri);

您可以使用其他答案实际构建查询字符串。