web-dev-qa-db-ja.com

NameValueCollection to URL Query?

私はこれができると知っています

var nv = HttpUtility.ParseQueryString(req.RawUrl);

しかし、これをURLに戻す方法はありますか?

var newUrl = HttpUtility.Something("/page", nv);
66
user34537

NameValueCollectionToString()を呼び出すだけで、name1=value1&name2=value2クエリ文字列の準備ができた形式で名前と値のペアが返されます。 NameValueCollection型はこれを実際にサポートしておらず、これを示唆するのは誤解を招く可能性がありますが、以下に説明するように、実際に返される内部型のために動作はここで動作します。

HttpUtility.ParseQueryStringメソッドが実際に通常のHttpValueCollectionではなく内部NameValueCollectionオブジェクトを返すことを指摘してくれた@mjwillsに感謝します( ドキュメントがNameValueCollection を指定しているにもかかわらず)。 HttpValueCollectionは、ToString()を使用するときにクエリ文字列を自動的にエンコードするため、コレクションをループしてUrlEncodeメソッドを使用するルーチンを作成する必要はありません。目的の結果はすでに返されています。

結果を入手したら、それをURLに追加してリダイレクトできます。

var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);

現在、HttpValueCollectionを使用する唯一の方法は、上記のParseQueryStringメソッドを使用することです(もちろん、リフレクション以外)。 このクラスを公開することを要求する接続の問題 は「修正しない」のステータスで閉じられているため、これは変わらないようです。

余談ですが、AddSetRemove、およびnameValuesメソッドを呼び出して、追加する前にクエリ文字列項目を変更できます。もしあなたがそれに興味があるなら 別の質問に対する私の回答を参照

101
Ahmad Mageed
string q = String.Join("&",
             nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
62
Denis

いくつかのループを使用する拡張メソッドを作成します。このソリューションは、読み取り可能で(linqなし)、System.Web.HttpUtilityを必要とせず、重複キーを処理するため、このソリューションを好みます。

public static string ToQueryString(this NameValueCollection nvc)
{
    if (nvc == null) return string.Empty;

    StringBuilder sb = new StringBuilder();

    foreach (string key in nvc.Keys)
    {
        if (string.IsNullOrWhiteSpace(key)) continue;

        string[] values = nvc.GetValues(key);
        if (values == null) continue;

        foreach (string value in values)
        {
            sb.Append(sb.Length == 0 ? "?" : "&");
            sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
        }
    }

    return sb.ToString();
}

var queryParams = new NameValueCollection()
{
    { "order_id", "0000" },
    { "item_id", "1111" },
    { "item_id", "2222" },
    { null, "skip entry with null key" },
    { "needs escaping", "special chars ? = &" },
    { "skip entry with null value", null }
};

Console.WriteLine(queryParams.ToQueryString());

出力

?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
13
Mathew Leger

これは、あまり多くのコードなしで動作するはずです。

_NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
_

アイデアは、_HttpUtility.ParseQueryString_を使用してHttpValueCollection型の空のコレクションを生成することです。このクラスはNameValueCollectionのサブクラスであり、internalとしてマークされているため、コードで簡単にインスタンスを作成できません。

HttpValueCollectionの良いところは、ToStringメソッドがエンコードを処理することです。 NameValueCollection.Add(NameValueCollection)メソッドを利用することで、最初に_Request.QueryString_コレクションをURLエンコードされた文字列に変換し、次に解析して戻すことなく、既存のクエリ文字列パラメーターを新しく作成されたオブジェクトに追加できます。コレクション。

この手法は、拡張メソッドとしても公開できます。

_public static string ToQueryString(this NameValueCollection nameValueCollection)
{
    NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty)
    httpValueCollection.Add(nameValueCollection);
    return httpValueCollection.ToString();
}
_
12
dana

実際には、値だけでなく、キーもエンコードする必要があります。

string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
5
user2397863

NameValueCollectionは同じキーに対して複数の値を持つことができるため、クエリ文字列の形式に関心がある場合(「配列表記」ではなくコンマ区切りの値として返されるため)、次のことを考慮できます。 。

var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");

に変換:key1=val1&key2[]=val2&empty&key2[]=val2b のではなく key1=val1&key2=val2,val2b&empty

コード

string qs = string.Join("&", 
    // "loop" the keys
    nvc.AllKeys.SelectMany(k => {
        // "loop" the values
        var values = nvc.GetValues(k);
        if(values == null) return new[]{ k };
        return nvc.GetValues(k).Select( (v,i) => 
            // 'gracefully' handle formatting
            // when there's 1 or more values
            string.Format(
                values.Length > 1
                    // pick your array format: k[i]=v or k[]=v, etc
                    ? "{0}[]={1}"
                    : "{0}={1}"
                , k, HttpUtility.UrlEncode(v), i)
        );
    })
);

または、Linqがあまり気に入らない場合は...

string qs = nvc.ToQueryString(); // using...

public static class UrlExtensions {
    public static string ToQueryString(this NameValueCollection nvc) {
        return string.Join("&", nvc.GetUrlList());
    }

    public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) {
        foreach(var k in nvc.AllKeys) {
            var values = nvc.GetValues(k);
            if(values == null)  { yield return k; continue; }
            for(int i = 0; i < values.Length; i++) {
                yield return
                // 'gracefully' handle formatting
                // when there's 1 or more values
                string.Format(
                    values.Length > 1
                        // pick your array format: k[i]=v or k[]=v, etc
                        ? "{0}[]={1}"
                        : "{0}={1}"
                    , k, HttpUtility.UrlEncode(values[i]), i);
            }
        }
    }
}

すでにコメントで指摘されているように、 this answer を除く他のほとんどの回答はシナリオに対応しています(Request.QueryStringは、リテラルの質問ではなく、HttpValueCollectionであり、NameValueCollectionではありません。

更新:コメントからのnull値の問題に対処しました。

3
drzaus

簡単な答えは、NameValueCollection.ToString()を使用し、それを元のURLと結合することです。

ただし、いくつかの点を指摘したいと思います。

_HttpUtility.ParseQueryString_で_Request.RawUrl_を使用することはできません。 ParseQueryString()メソッドは、_?var=value&var2=value2_のような値を探しています。

NameValueCollectionパラメーターのQueryStringを取得する場合は、Request.QueryString()を使用します。

_var nv = Request.QueryString;
_

URLを再構築するには、nv.ToString()を使用します。

_string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
_

Requestオブジェクトを使用する代わりにURL文字列を解析しようとする場合は、Uriおよび_HttpUtility.ParseQueryString_メソッドを使用します。

_Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
_
3
Jeremy

AspNet Core 2.0では、 QueryHelpers AddQueryStringメソッドを使用できます。

1
Atchitutchuk

これはあなたのために働くでしょうか?

public static string BuildUrl(string relativeUrl, params string[] queryString)
{
    // build queryString from string parameters
    char[] trimChars = { ' ', '&', '?' };
    StringBuilder builder = new StringBuilder();
    string sepChar = "&";
    string sep = String.Empty;
    foreach (string q in queryString)
    {
        builder.Append(sep).Append(q.Trim(trimChars));
        sep = sepChar;
    }

    if (String.IsNullOrEmpty(builder.ToString())) { return relativeUrl; }
    else { return relativeUrl + "?" + builder.ToString(); }
}

つかいます:

string url = BuildUrl("/mypage.apsx", "qs1=a", "qs2=b", "qs3=c");
1
Brad

@Atchitutchukが示唆したように、ASP.NET CoreでQueryHelpers.AddQueryStringを使用できます。

    public string FormatParameters(NameValueCollection parameters)
    {
        var queryString = "";
        foreach (var key in parameters.AllKeys)
        {
            foreach (var value in parameters.GetValues(key))
            {
                queryString = QueryHelpers.AddQueryString(queryString, key, value);
            }
        };

        return queryString.TrimStart('?');
    }
0
arni

私は常にUriBuilderを使用して、クエリ文字列を含むURLを有効で適切にエンコードされたURLに変換します。

var url = "http://my-link.com?foo=bar";

var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("yep", "foo&bar");

uriBuilder.Query = query.ToString();
var result = uriBuilder.ToString();

// http://my-link.com:80/?foo=bar&yep=foo%26bar
0
ms007

使用できます。

var ur = new Uri("/page",UriKind.Relative);

このnvが文字列型の場合、uriの最初のパラメーターに追加できます。いいね

var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);
0