Cách phân tích chuỗi truy vấn thành NameValueCollection trong .NET


186

Tôi muốn phân tích một chuỗi như p1=6&p2=7&p3=8vào mộtNameValueCollection .

Cách thức thanh lịch nhất để làm điều này khi bạn không có quyền truy cập vào Page.Requestđối tượng là gì?

Câu trả lời:


356

Có một tiện ích .NET tích hợp sẵn cho việc này: HttpUtility.PudeQueryString

// C#
NameValueCollection qscoll = HttpUtility.ParseQueryString(querystring);
' VB.NET
Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(querystring)

Bạn có thể cần phải thay thế querystringbằng new Uri(fullUrl).Query.


26
Omar, nó không hoạt động với tôi trên ASP.NET 4, nó đã trả về một khóa " stackoverflow.com?para " thay vì "para". Vì vậy, tôi đang sử dụng HttpUtility.PudeQueryString (Uri mới (fullUrl) .Query) hoạt động chính xác với tôi.
Michael

2
qscoll ["p1"], qscoll ["p2"] và qscoll ["p3"]
SMUsamaShah

5
ParseQueryString thực sự là ý tưởng tồi để sử dụng trong ứng dụng máy tính để bàn, vì nó không được bao gồm trong Hồ sơ khách hàng; Tại sao phải cài đặt 100 M thư viện bổ sung trên máy khách để chỉ sử dụng một phương pháp đơn giản? Tuy nhiên, có vẻ như Microsoft không có ý tưởng nào tốt hơn. Cách duy nhất là thực hiện phương thức riêng hoặc sử dụng triển khai nguồn mở.
Vitalii

2
VASoftOnline: Trong trường hợp đó, bạn có thể sử dụng triển khai Mono của ParseQueryString: github.com/mono/mono/blob/master/mcs/ class / System.Web / giấy phép cho đó là MIT X11: github.com/mono/mono / blob / master / PHÉP
sw.

3
HttpUtility.ParseQueryStringsẽ là đề xuất của tôi ngoại trừ trong trường hợp HttpUtility.ParseQueryString("&X=1&X=2&X=3")kết quả là ....X=1,2,3...Có nhiều thông số cùng tên là không phổ biến nhưng cần hỗ trợ các tham số của bộ điều khiển như int [], IEnumerable <int> etc (các thông số như vậy có thể được sử dụng để hỗ trợ nhiều hộp kiểm) xem "Nhiều lần xuất hiện của cùng một biến chuỗi truy vấn được hợp nhất trong một mục nhập" theo trang web MS . Một phiên bản thủ công của phương pháp có thể là lựa chọn duy nhất của bạn
dunxz

43

HttpUtility.PudeQueryString sẽ hoạt động miễn là bạn đang ở trong một ứng dụng web hoặc không bận tâm bao gồm cả sự phụ thuộc vào System.Web. Một cách khác để làm điều này là:

NameValueCollection queryParameters = new NameValueCollection();
string[] querySegments = queryString.Split('&');
foreach(string segment in querySegments)
{
   string[] parts = segment.Split('=');
   if (parts.Length > 0)
   {
      string key = parts[0].Trim(new char[] { '?', ' ' });
      string val = parts[1].Trim();

      queryParameters.Add(key, val);
   }
}

5
bạn nên kiểm tra xem các bộ phận. Độ dài> 1, để chắc chắn bạn có thể gọi các bộ phận [1]
Alexandru Pupsa

2
Nếu không có giá trị thì sao? ví dụ một chuỗi truy vấn có thể trông giống như ?foo=1&bar. HttpUtilitysẽ phân tích nó như là{ key = null, value = "bar" }
Thomas Levesque

Điều này thật tuyệt vời so với HttpUtility.PudeQueryString vì nó không giải mã được các giá trị (vì vậy các giá trị được mã hóa base64 được giữ nguyên)
CRice 7/07/17

1
Trên thực tế, bạn vẫn cần cho phép giá trị '=' ví dụ & code = A0SYw34Hj / m ++ lH0s7r0l / yg6GWdymzSCbI2zOn3V4o = sẽ xóa ký tự '=' cuối cùng. Tôi viết lại một phần mã của bạn để lấy chỉ mục đầu tiên là '=' và chuỗi con khóa và giá trị để sửa lỗi này (thay vì sử dụng phân tách).
CRice

28

Rất nhiều câu trả lời đang cung cấp các ví dụ tùy chỉnh vì sự phụ thuộc của câu trả lời được chấp nhận vào System.Web . Từ gói NuGet của Microsoft.AspNet.WebApi.Client có một phương thức UriExtensions.PudeQueryString , cũng có thể được sử dụng:

var uri = new Uri("https://stackoverflow.com/a/22167748?p1=6&p2=7&p3=8");
NameValueCollection query = uri.ParseQueryString();

Vì vậy, nếu bạn muốn tránh sự phụ thuộc của System.Web và không muốn tự mình thực hiện, đây là một lựa chọn tốt.


3
Hàm tương tự tồn tại như một phần mở rộng trong không gian tên System.Net.Http (xem câu trả lời của tôi bên dưới), không cần phụ thuộc hoàn toàn khác ...
jvenema

@jvenema Bạn đang thêm gói phụ thuộc System.Net.Http.Formatted từ đâu, tôi tin rằng nó chỉ được cung cấp bằng cách thêm gói Microsoft.AspNet.WebApi.Client NuGet.
James Skuration

19

Tôi muốn loại bỏ sự phụ thuộc vào System.Web để tôi có thể phân tích chuỗi truy vấn của triển khai ClickOnce, trong khi có các điều kiện tiên quyết giới hạn trong "Tập hợp khung chỉ dành cho khách hàng".

Tôi thích câu trả lời của rp. Tôi đã thêm một số logic bổ sung.

public static NameValueCollection ParseQueryString(string s)
    {
        NameValueCollection nvc = new NameValueCollection();

        // remove anything other than query string from url
        if(s.Contains("?"))
        {
            s = s.Substring(s.IndexOf('?') + 1);
        }

        foreach (string vp in Regex.Split(s, "&"))
        {
            string[] singlePair = Regex.Split(vp, "=");
            if (singlePair.Length == 2)
            {
                nvc.Add(singlePair[0], singlePair[1]);
            }
            else
            {
                // only one key with no value specified in query string
                nvc.Add(singlePair[0], string.Empty);
            }
        }

        return nvc;
    }

Điều này thực sự hữu ích cho windows phone, bạn chỉ cần thay thế "NameValueCollection" bằng "SortedDictionnary <chuỗi, chuỗi>"
Mike Bryant

4
Hãy cẩn thận khi chuyển NameValueCollection cho một từ điển - chúng không giống nhau! Chuỗi truy vấn hỗ trợ nhiều khóa có cùng giá trị và NameValueCollection cũng vậy.
Matt DeKrey

7

Tôi cần một chức năng linh hoạt hơn một chút so với những gì đã được cung cấp khi làm việc với các truy vấn OLSC.

  • Các giá trị có thể chứa nhiều dấu bằng
  • Giải mã các ký tự được mã hóa theo cả tên và giá trị
  • Có khả năng chạy trên Khung khách hàng
  • Có khả năng chạy trên Mobile Framework.

Đây là giải pháp của tôi:

Public Shared Function ParseQueryString(ByVal uri As Uri) As System.Collections.Specialized.NameValueCollection
    Dim result = New System.Collections.Specialized.NameValueCollection(4)
    Dim query = uri.Query
    If Not String.IsNullOrEmpty(query) Then
        Dim pairs = query.Substring(1).Split("&"c)
        For Each pair In pairs
            Dim parts = pair.Split({"="c}, 2)

            Dim name = System.Uri.UnescapeDataString(parts(0))
            Dim value = If(parts.Length = 1, String.Empty,
                System.Uri.UnescapeDataString(parts(1)))

            result.Add(name, value)
        Next
    End If
    Return result
End Function

Nó có thể không phải là một ý tưởng tồi để giải quyết <Extension()>vấn đề đó để thêm khả năng cho chính Uri.


7

Để thực hiện việc này mà không cần System.Web, không cần tự viết và không có gói NuGet bổ sung:

  1. Thêm một tham chiếu đến System.Net.Http.Formatting
  2. Thêm vào using System.Net.Http;
  3. Sử dụng mã này:

    new Uri(uri).ParseQueryString()

https://msdn.microsoft.com/en-us/l Library / system.net.http.uriextensions (v = vs.118) .aspx


3
Từ đâu bạn thêm phụ thuộc System.Net.Http.Formatted, tôi tin rằng nó chỉ được cung cấp bằng cách thêm gói Microsoft.AspNet.WebApi.Client NuGet.
James Skuration

Huh, xấu của tôi. Tôi đoán nó đi kèm với khung MVC được cài đặt tự động, vì vậy tôi không phải thêm bất kỳ gói add'l nào (Tệp chương trình (x86) \ Microsoft ASP.NET \ ASP.NET MVC 4 \ Assemblies \ System.Net. Http.Formatted.dll)
jvenema

System.Net.Formatted EXTENSION VS2019 là một danh sách hoặc tab riêng biệt từ các tham chiếu khung truyền thống
Sql Surfer

3

Nếu bạn muốn tránh sự phụ thuộc vào System.Web được yêu cầu sử dụng HttpUtility.PudeQueryString , bạn có thể sử dụng Uriphương thức tiện ích mở rộng ParseQueryStringđược tìm thấy trong System.Net.Http.

Đảm bảo thêm một tham chiếu (nếu bạn chưa có) vào System.Net.Http vào dự án của bạn.

Lưu ý rằng bạn phải chuyển đổi nội dung phản hồi thành hợp lệ Uriđể ParseQueryString(trong System.Net.Http) hoạt động.

string body = "value1=randomvalue1&value2=randomValue2";

// "http://localhost/query?" is added to the string "body" in order to create a valid Uri.
string urlBody = "http://localhost/query?" + body;
NameValueCollection coll = new Uri(urlBody).ParseQueryString();

System.Net.Formatted EXTENSION VS2019 đặt các tham chiếu mở rộng tách biệt với các tham chiếu khung truyền thống.
Sql Surfer

2
    private void button1_Click( object sender, EventArgs e )
    {
        string s = @"p1=6&p2=7&p3=8";
        NameValueCollection nvc = new NameValueCollection();

        foreach ( string vp in Regex.Split( s, "&" ) )
        {
            string[] singlePair = Regex.Split( vp, "=" );
            if ( singlePair.Length == 2 )
            {
                nvc.Add( singlePair[ 0 ], singlePair[ 1 ] );    
            }    
        }
    }

5
dấu chấm phẩy cũng được cho phép như một dấu tách tham số trong http, tốt hơn là không phát minh lại bánh xe
Matthew Lock

2

Tôi mới nhận ra rằng Web API Client có một ParseQueryStringphương thức mở rộng hoạt động trên Urivà trả về HttpValueCollection:

var parameters = uri.ParseQueryString();
string foo = parameters["foo"];

1

Chỉ cần truy cập Request.QueryString. AllKeys được đề cập như một câu trả lời khác chỉ giúp bạn có một loạt các khóa.


1

HttpUtility.ParseQueryString(Request.Url.Query)trả lại là HttpValueCollection(lớp nội bộ). Nó thừa hưởng từ NameValueCollection.

    var qs = HttpUtility.ParseQueryString(Request.Url.Query);
    qs.Remove("foo"); 

    string url = "~/Default.aspx"; 
    if (qs.Count > 0)
       url = url + "?" + qs.ToString();

    Response.Redirect(url); 

1

Nếu bạn không muốn phụ thuộc System.Web, chỉ cần dán mã nguồn này từ lớp HttpUtility.

Tôi vừa đánh cái này từ mã nguồn của Mono . Nó chứa httpUtility và tất cả các phụ thuộc của nó (như IHtmlString, Helpers, HttpEncoder, HttpQSCollection).

Sau đó sử dụng HttpUtility.ParseQueryString.

https://gist.github.com/bjorn-ali-goransson/b04a7c44808bb2de8cca3fc9a3762f9c


1

Vì mọi người dường như đang dán giải pháp của anh ấy .. đây là của tôi :-) Tôi cần điều này từ trong thư viện lớp mà không cần System.Web tìm nạp các tham số id từ các siêu liên kết được lưu trữ.

Tôi muốn chia sẻ vì tôi thấy giải pháp này nhanh hơn và đẹp hơn.

public static class Statics
    public static Dictionary<string, string> QueryParse(string url)
    {
        Dictionary<string, string> qDict = new Dictionary<string, string>();
        foreach (string qPair in url.Substring(url.IndexOf('?') + 1).Split('&'))
        {
            string[] qVal = qPair.Split('=');
            qDict.Add(qVal[0], Uri.UnescapeDataString(qVal[1]));
        }
        return qDict;
    }

    public static string QueryGet(string url, string param)
    {
        var qDict = QueryParse(url);
        return qDict[param];
    }
}

Sử dụng:

Statics.QueryGet(url, "id")

1
Chỉ có một vấn đề với phương thức này: một chuỗi truy vấn có thể có nhiều hơn một giá trị cho một tham số đã cho. Trong trường hợp này, phương thức của bạn sẽ đưa ra một lỗi khóa trùng lặp.
Thomas Levesque

có, ít nhất là sử dụng NameValueCollection, các truy vấn có khóa trùng lặp là hoàn toàn hợp pháp.
Chad Grant

Ngoài ra, từ điển của bạn phân biệt chữ hoa chữ thường, vì vậy X = 1 và x = 1 sẽ là các khóa khác nhau. Cần từ điển mới <chuỗi, chuỗi> (StringComparer.OrdinalIgnoreCase);
Chad Grant

0

Nhấn lên Request.QueryString.Keys cho NameValueCollection của tất cả các tham số chuỗi truy vấn.


0

Để nhận tất cả các giá trị chuỗi truy vấn, hãy thử điều này:

    Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(querystring)

Dim sb As New StringBuilder("<br />")
For Each s As String In qscoll.AllKeys

  Response.Write(s & " - " & qscoll(s) & "<br />")

Next s

0
        var q = Request.QueryString;
        NameValueCollection qscoll = HttpUtility.ParseQueryString(q.ToString());

0
let search = window.location.search;

console.log(search);

let qString = search.substring(1);

while(qString.indexOf("+") !== -1)

   qString  = qString.replace("+", "");

let qArray = qString.split("&");

let values = [];

for(let i = 0; i < qArray.length; i++){
   let pos = qArray[i].search("=");
   let keyVal = qArray[i].substring(0, pos);
   let dataVal = qArray[i].substring(pos + 1);
   dataVal = decodeURIComponent(dataVal);
   values[keyVal] = dataVal;
}

-1

Tôi dịch sang phiên bản C # của josh-brown trong VB

private System.Collections.Specialized.NameValueCollection ParseQueryString(Uri uri)
{
    var result = new System.Collections.Specialized.NameValueCollection(4);
    var query = uri.Query;
    if (!String.IsNullOrEmpty(query))
    {
        var pairs = query.Substring(1).Split("&".ToCharArray());
        foreach (var pair in pairs)
        {
            var parts = pair.Split("=".ToCharArray(), 2);
            var name = System.Uri.UnescapeDataString(parts[0]);
            var value = (parts.Length == 1) ? String.Empty : System.Uri.UnescapeDataString(parts[1]);
            result.Add(name, value);
        }
    }
    return result;
}

-2

Đây là mã của tôi, tôi nghĩ nó rất hữu ích:

public String GetQueryString(string ItemToRemoveOrInsert = null, string InsertValue = null )
{
    System.Collections.Specialized.NameValueCollection filtered = new System.Collections.Specialized.NameValueCollection(Request.QueryString);
    if (ItemToRemoveOrInsert != null)
    {
        filtered.Remove(ItemToRemoveOrInsert);
        if (!string.IsNullOrWhiteSpace(InsertValue))
        {
            filtered.Add(ItemToRemoveOrInsert, InsertValue);
        }
    }

    string StrQr = string.Join("&", filtered.AllKeys.Select(key => key + "=" + filtered[key]).ToArray());
    if (!string.IsNullOrWhiteSpace(StrQr)){
        StrQr="?" + StrQr;
    }

    return StrQr;
}
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.