Nối các giá trị vào chuỗi truy vấn


161

Tôi có bộ URL tương tự như các URL bên dưới trong danh sách

Tôi đã quản lý để có được các chuỗi truy vấn bằng cách sử dụng mã sau đây:

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

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

Nhưng nó chỉ trả về các tham số như id , máy chủ , vị trí , v.v dựa trên URL được cung cấp.

Điều tôi cần là thêm / nối các giá trị vào các chuỗi truy vấn hiện có.

Ví dụ với URL:

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

Tôi cần thay đổi các giá trị của các tham số chuỗi truy vấn:

hành động = đăng nhập1

cố gắng = 11

Như bạn có thể thấy, tôi đã thêm "1" cho mỗi giá trị. Tôi cần lấy một bộ URL từ một chuỗi có các chuỗi truy vấn khác nhau trong đó và thêm một giá trị cho mỗi tham số ở cuối & một lần nữa thêm chúng vào danh sách.

Câu trả lời:


327

Bạn có thể sử dụng HttpUtility.ParseQueryStringphương thức và một phương thức UriBuildercung cấp một cách hay để làm việc với các tham số chuỗi truy vấn mà không phải lo lắng về những thứ như phân tích cú pháp, mã hóa 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
Như bạn có thể thấy từ ví dụ của tôi, bạn có thể sử dụng tên biến cho các tham số. Và đó chính xác là những gì nó làm: nó nối thêm 2 tham số vào url hiện có mà tôi đã mã hóa ở đây nhưng chúng hoàn toàn có thể ổn định.
Darin Dimitrov

1
Chúng ta không nên sử dụng HttpUtility.UrlEncode()khi gán giá trị tham số?
UserControl

1
@UserControl, không, HttpUtility.ParseQueryStringphương thức trả về một triển khai NameValueCollection đặc biệt đã xử lý việc này phía sau hậu trường khi bạn đặt giá trị.
Darin Dimitrov

5
Bummer rằng điều này có một sự phụ thuộc vào System.Web: /
Pure.Krom

4
điều đáng chú ý là cách tiếp cận này có thể gây ra vấn đề với quốc tế hóa vì các ký tự đặc biệt sẽ được chuyển đổi thành tương đương unicode của chúng trong phương thức query.ToString ().
tezromania

104

Tôi đã gói câu trả lời của Darin vào một phương pháp mở rộng có thể tái sử dụng độc đáo.

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

Tôi hi vọng cái này giúp được!


55

Các câu trả lời được cung cấp có vấn đề với Url tương đối, chẳng hạn như "/ some / path /" Đây là một hạn chế của lớp Uri và UriBuilder, điều này khá khó hiểu, vì tôi không thấy bất kỳ lý do nào khiến các url tương đối có vấn đề khi nói đến thao tác truy vấn.

Đây là một cách giải quyết phù hợp với cả đường dẫn tuyệt đối và tương đối, được viết và thử nghiệm trong .NET 4:

(lưu ý nhỏ: điều này cũng sẽ hoạt động trong .NET 4.5, bạn sẽ chỉ phải thay đổi propInfo.GetValue(values, null)thành 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; }
      ));
    }
  }

Và đây là một bộ các bài kiểm tra đơn vị để kiểm tra hành vi:

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

Thật không may, giải pháp này không hoạt động đối với ASP.NET 5 bằng cách sử dụng đám mây .NET vì dường như không có sẵn HTTPUtility. Nhưng đó là một giải pháp tuyệt vời khác. Xem stackoverflow.com/questions/29992848/ từ
diegosasw

1
"Add_to_query_string_dictionary_when_url_contains_hash_and_no_query_string_should_add_values" nên kiểm tra xem URL sẽ domain.com/test?param1=val1¶m2=val2#div
gliljas

Vui lòng kiểm tra lại, cho dù bạn không sử dụng tốt hơn uri.AbsoluteUrithay uri.ToString()vì các hiệu ứng không thoát khó chịu.
Nico

2
Ngoài ra: uri.AbsoluteUriném, nếu uri không tuyệt đối!
Nico

19

Lưu ý rằng bạn có thể thêm Microsoft.AspNetCore.WebUtilitiesgói nuget từ Microsoft và sau đó sử dụng gói này để nối các giá trị vào chuỗi truy vấn:

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

3
Kể từ ASP.NET Core 3.0 WebUtilities hiện là một phần của ASP.NET SDK nên không cần gói nuget.
dùng1069816

1
Vấn đề với AddQueryStringlà nó sẽ luôn luôn thêm, nếu đã có khóa, nó sẽ không cập nhật, nhưng tạo các khóa trùng lặp, rất tệ
Vencovsky

11

Giải pháp sau đây hoạt động cho ASP.NET 5 (vNext) và nó sử dụng lớp QueryHelpers để xây dựng URI với các tham số.

    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 kết quả sẽ có http://iberia.com?param1=value1&param2=value2&param3=value3


Vấn đề duy nhất với việc sử dụng Từ điển làm kho lưu trữ các khóa và giá trị truy vấn là các chuỗi truy vấn có thể có các khóa trùng lặp với các giá trị khác nhau. Tôi tin rằng một yêu cầu đến một trang web ASP.NET phân tích cú pháp đó như là một mảng các giá trị cho một khóa đó.
Seth

2

Kết thúc cho tất cả các tai ương chỉnh sửa chuỗi truy vấn URL

Sau rất nhiều công việc và loay hoay với lớp Uri và các giải pháp khác, đây là phương pháp mở rộng chuỗi của tôi để giải quyết vấn đề của tôi.

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
Tôi không khuyến khích mọi người sử dụng strings thô để thể hiện các URL như thế này khi xem xét Urilớp đã tồn tại cho mục đích đó. Sử dụng hoặc tạo ra một bản tóm tắt hoàn toàn mới nếu thiếu các tính năng.
julealgon

0

Tôi thích câu trả lời của Bjorn, tuy nhiên giải pháp mà anh ấy cung cấp là sai lệch, vì phương thức cập nhật một tham số hiện có, thay vì thêm nó nếu nó không tồn tại .. Để an toàn hơn một chút, tôi đã điều chỉnh nó bên dưới.

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

Tôi thực sự đã thực hiện một chỉnh sửa cận biên của mã, tôi đã không cung cấp nó (OP đã làm) ... sự khác biệt sẽ là gì?

1
Nếu / khác là không cần thiết, chỉ cần làm query[paramName] = paramValue;trong mọi trường hợp. Nó tồn tại, nó sẽ bị ghi đè. Nếu nó không tồn tại, khóa sẽ được tạo.
Richard

-4

Cách tiếp cận của tôi rất đơn giản, cho người mới bắt đầu:

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

    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.