쿼리 문자열에 값 추가


162

목록에서 아래 URL과 비슷한 URL 세트를 가지고 있습니다

다음 코드를 사용하여 쿼리 문자열을 가져 왔습니다.

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

foreach (string lol in qs)
{
    // results will return
}

그러나 제공된 URL을 기반으로 id , server , location 등과 같은 매개 변수 만 반환합니다 .

내가 필요한 것은 기존 쿼리 문자열에 값을 추가 / 추가하는 것입니다.

예를 들어 URL을 사용하여 :

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

쿼리 문자열 매개 변수의 값을 변경해야합니다.

action = login1

시도 = 11

보시다시피 각 값에 "1"을 추가했습니다. 다른 쿼리 문자열이있는 문자열에서 URL 집합을 가져 와서 끝에 각 매개 변수에 값을 추가하고 다시 목록에 추가해야합니다.

답변:


328

HttpUtility.ParseQueryString메소드를 사용하면 UriBuilder구문 분석, URL 인코딩 등을 걱정하지 않고 쿼리 문자열 매개 변수를 사용하는 좋은 방법을 제공 할 수 있습니다 .

string longurl = "http://somesite.com/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.com:80/news.php?article=1&lang=en&action=login1&attempts=11"

5
내 예제에서 볼 수 있듯이 매개 변수에 변수 이름을 사용할 수 있습니다. 그리고 그것이 정확히하는 것입니다 : 여기에 하드 코딩 한 기존 URL에 2 개의 매개 변수를 추가하지만 완벽하게 동적 일 수 있습니다.
Darin Dimitrov

1
HttpUtility.UrlEncode()파라미터 값을 할당 할 때 사용하지 않아야 합니까?
UserControl

1
@UserControl, 아니오, HttpUtility.ParseQueryString메소드는 값을 설정할 때 이미 뒤에서이를 처리하는 특수한 NameValueCollection 구현을 리턴합니다.
Darin Dimitrov

5
이것이 System.Web : /
Pure.Krome

4
특수 문자가 query.ToString () 메소드에서 고유 문자로 변환되므로이 방법으로 국제화에 문제가 발생할 수 있습니다.
tezromania

104

Darin의 답변 을 재사용 가능한 확장 방법으로 감쌌습니다 .

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

이게 도움이 되길 바란다!


55

제공된 답변에는 "/ some / path /"와 같은 상대 URL에 문제가 있습니다. 이것은 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.com/test?param1=val1&amp;param2=val2&amp;param3=val3"
    ///     new Uri("www.domain.com/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.com/test?param1=val1&amp;param2=val2&amp;param3=val3"
    ///     new Uri("www.domain.com/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.com/test");
      var values = new Dictionary<string, string>();
      var result = url.ExtendQuery(values);
      Assert.That(result, Is.EqualTo(new Uri("http://www.domain.com/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.com/test#div");
      var values = new Dictionary<string, string>();
      var result = url.ExtendQuery(values);
      Assert.That(result, Is.EqualTo(new Uri("http://www.domain.com/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.com/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.com/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.com/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.com/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.com/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.com/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.com/test");
      var values = new { param1 = "val1", param2 = "val2" };
      var result = url.ExtendQuery(values);
      Assert.That(result, Is.EqualTo(new Uri("http://www.domain.com/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.com/test?param1=val1");
      var values = new { param2 = "val2" };
      var result = url.ExtendQuery(values);
      Assert.That(result, Is.EqualTo(new Uri("http://www.domain.com/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)));
    }
  }

불행히도 HttpUtility를 사용할 수없는 것처럼 클라우드 .NET을 사용하는 ASP.NET 5에서는이 솔루션이 작동하지 않습니다. 그러나 그렇지 않으면 훌륭한 솔루션입니다. 참조 stackoverflow.com/questions/29992848/...
diegosasw

1
"Add_to_query_string_dictionary_when_url_contains_hash_and_no_query_string_should_add_values"는 URL이 될 것을 테스트해야 domain.com/test?param1=val1¶m2=val2#div
gliljas

거친 이스케이프 효과 uri.AbsoluteUriuri.ToString()인해 대신 사용 하는 것이 좋지 않은지 여부를 확인하십시오 .
니코

2
추가 : uri.AbsoluteUriURI가 절대적이지 않으면 던집니다!
Nico

19

Microsoft.AspNetCore.WebUtilitiesMicrosoft 의 nuget 패키지를 추가 한 다음이를 사용하여 쿼리 문자열에 값을 추가 할 수 있습니다.

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

3
ASP.NET Core 3.0부터 WebUtilities는 이제 ASP.NET SDK의 일부이므로 nuget 패키지가 필요하지 않습니다.
user1069816

1
문제 AddQueryString는 키가 이미있는 경우 항상 추가하고 업데이트하지는 않지만 중복 키를 만드는 것은 좋지 않다는 것입니다
Vencovsky

11

다음 솔루션은 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


쿼리 키 및 값의 저장소로 사전을 사용하는 유일한 문제는 쿼리 문자열에 다른 값을 가진 중복 키가있을 수 있다는 것입니다. ASP.NET 사이트에 대한 요청은 해당 키를 하나의 키에 대한 값의 배열로 구문 분석한다고 생각합니다.
세스

2

모든 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;
    }
}

1
클래스가 이미 그 목적을 위해 존재한다는 것을 string고려할 때 사람들이 이와 같은 URL을 나타내는 데 raw s를 사용하지 않도록 권장 Uri합니다. 기능을 사용하거나 기능이 누락 된 경우 완전히 새로운 추상화를 작성하십시오.
julealgon

0

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

코드를 거의 편집하지 않고 코드를 제공하지 않았지만 (OP는 제공하지 않았습니다.) 차이점은 무엇입니까?

1
if / else는 필요하지 않으며 query[paramName] = paramValue;모든 경우에 수행하십시오. 그것이 존재하고 재정의되어야합니다. 존재하지 않으면 키가 생성됩니다.
Richard

-4

초보자에게는 내 접근 방식이 매우 간단합니다.

// --> Prototype : https://ctrader.guru/?id=1#reload

    public static string AddGetParamToUrl(string url, string pname, string pvalue)
    { 

        pvalue = Uri.EscapeDataString(pvalue);

        if (url.IndexOf("?") > -1)
        {

            url = url.Replace("?", string.Format("?{0}={1}&", pname, pvalue));

        }
        else if (url.IndexOf("#") > -1)
        {

            url = url.Replace("#", string.Format("?{0}={1}#", pname, pvalue));

        }
        else
        {

            url = string.Format("{0}?{1}={2}", url, pname, pvalue);

        }

        return url;

    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.