Tambahkan nilai ke string kueri


162

Saya telah mengatur URL yang mirip dengan yang di bawah ini dalam daftar

Saya telah berhasil mendapatkan string kueri menggunakan kode berikut:

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

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

Tetapi hanya mengembalikan parameter seperti id , server , lokasi dan sebagainya berdasarkan URL yang disediakan.

Yang saya butuhkan adalah menambahkan / menambahkan nilai ke string kueri yang ada.

Misalnya dengan URL:

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

Saya perlu mengubah nilai parameter string kueri:

action = login1

upaya = 11

Seperti yang Anda lihat, saya telah menambahkan "1" untuk setiap nilai. Saya perlu mendapatkan satu set URL dari string dengan string kueri yang berbeda di dalamnya dan menambahkan nilai ke setiap parameter di akhir & lagi menambahkannya ke daftar.

Jawaban:


329

Anda bisa menggunakan HttpUtility.ParseQueryStringmetode dan UriBuilderyang menyediakan cara yang bagus untuk bekerja dengan parameter string kueri tanpa perlu khawatir tentang hal-hal seperti penguraian, penyandian 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
Seperti yang Anda lihat dari contoh saya, Anda bisa menggunakan nama variabel untuk parameter. Dan itulah yang dilakukannya: menambahkan 2 parameter ke url yang ada yang telah saya hardcode di sini, tetapi mereka bisa saja dinamis.
Darin Dimitrov

1
Tidakkah seharusnya kita menggunakan HttpUtility.UrlEncode()ketika menetapkan nilai parameter?
UserControl

1
@UserControl, tidak, HttpUtility.ParseQueryStringmetode mengembalikan implementasi NameValueCollection khusus yang sudah menangani ini di belakang layar ketika Anda menetapkan nilai.
Darin Dimitrov

5
Sayangnya, ini memiliki ketergantungan pada System.Web: /
Pure.Krome

4
Perlu dicatat bahwa pendekatan ini dapat menyebabkan masalah dengan internasionalisasi karena karakter khusus akan dikonversi ke ekuivalen unicode mereka dalam metode query.ToString ().
tezromania

105

Saya telah memasukkan jawaban Darwin ke dalam metode ekstensi yang dapat digunakan kembali.

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

Saya harap ini membantu!


55

Jawaban yang diberikan memiliki masalah dengan Url relatif, seperti "/ some / path /" Ini adalah batasan dari kelas Uri dan UriBuilder, yang agak sulit dimengerti, karena saya tidak melihat alasan mengapa url relatif akan bermasalah. ketika datang ke manipulasi permintaan.

Berikut adalah solusi yang berfungsi untuk jalur absolut dan relatif, ditulis dan diuji dalam .NET 4:

(catatan kecil: ini juga harus bekerja di .NET 4.5, Anda hanya perlu mengubah propInfo.GetValue(values, null)ke 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; }
      ));
    }
  }

Dan di sini ada serangkaian unit test untuk menguji perilaku:

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

sayangnya solusi ini tidak berfungsi untuk ASP.NET 5 menggunakan cloud .NET karena HttpUtility tampaknya tidak tersedia. Tetapi ini adalah solusi yang bagus. Lihat stackoverflow.com/questions/29992848/…
diegosasw

1
"Add_to_query_string_dictionary_when_url_contains_hash_and_no_query_string_should_add_values" harus menguji apakah URL tersebut menjadi domain.com/test?param1=val1¶m2=val2#div
gliljas

Silakan cek cek, apakah Anda tidak lebih baik menggunakan uri.AbsoluteUridaripada uri.ToString()karena efek buruk yang tidak dapat dihindari.
Nico

2
Tambahan: uri.AbsoluteUrimelempar, jika uri tidak mutlak!
Nico

19

Catatan Anda dapat menambahkan Microsoft.AspNetCore.WebUtilitiespaket nuget dari Microsoft dan kemudian menggunakan ini untuk menambahkan nilai ke string kueri:

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

3
Pada ASP.NET Core 3.0 WebUtilities sekarang menjadi bagian dari ASP.NET SDK sehingga tidak diperlukan paket nuget.
user1069816

1
Masalahnya AddQueryStringadalah bahwa ia akan selalu menambahkan, jika sudah ada kunci, itu tidak akan memperbarui, tetapi membuat kunci duplikat, dengan buruk
Vencovsky

11

Solusi berikut ini berfungsi untuk ASP.NET 5 (vNext) dan menggunakan kelas QueryHelpers untuk membangun URI dengan parameter.

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

Hasilnya URI akan miliki http://iberia.com?param1=value1&param2=value2&param3=value3


Satu-satunya masalah dengan menggunakan Kamus sebagai penyimpan kunci dan nilai kueri adalah bahwa string kueri dapat memiliki kunci duplikat dengan nilai yang berbeda. Saya percaya bahwa permintaan ke situs ASP.NET mem-parsing itu sebagai array nilai untuk satu kunci.
Seth

2

Akhir semua kesedihan pengeditan string kueri URL

Setelah banyak kerja keras dan mengutak-atik kelas Uri, dan solusi lainnya, inilah metode ekstensi string saya untuk menyelesaikan masalah saya.

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
Saya akan mencegah orang menggunakan mentah stringuntuk mewakili URL seperti ini mengingat Urikelas sudah ada untuk tujuan itu. Baik gunakan itu, atau buat abstraksi baru jika fitur tidak ada.
julealgon

0

Saya suka jawaban Bjorn, namun solusi yang diberikannya menyesatkan, karena metode memperbarui parameter yang ada, daripada menambahkannya jika tidak ada .. Untuk membuatnya sedikit lebih aman, saya telah mengadaptasinya di bawah ini.

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

Saya benar-benar membuat sedikit mengedit kode, saya tidak menyediakannya (OP lakukan) ... apa bedanya?

1
Jika / tidak diperlukan, lakukan saja query[paramName] = paramValue;dalam semua kasus. Itu ada, akan ditimpa. Jika tidak ada, kunci akan dibuat.
Richard

-4

Pendekatan saya sangat sederhana, untuk pemula:

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

    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.