C #에서 URL에 대한 쿼리 문자열을 작성하는 방법은 무엇입니까?
코드에서 웹 리소스를 호출 할 때 일반적인 작업은 필요한 모든 매개 변수를 포함하도록 쿼리 문자열을 작성하는 것입니다. 로켓 과학은 &
아니지만, 첫 번째 매개 변수가 아닌 경우 추가하고 매개 변수를 인코딩하는 등 몇 가지 멋진 세부 정보가 필요합니다 .
그것을하는 코드는 매우 간단하지만 약간 지루합니다.
StringBuilder SB = new StringBuilder();
if (NeedsToAddParameter A)
{
SB.Append("A="); SB.Append(HttpUtility.UrlEncode("TheValueOfA"));
}
if (NeedsToAddParameter B)
{
if (SB.Length>0) SB.Append("&");
SB.Append("B="); SB.Append(HttpUtility.UrlEncode("TheValueOfB")); }
}
이것은 더 우아하고 읽기 쉬운 유틸리티 클래스가 존재할 것으로 예상되는 일반적인 작업입니다. MSDN을 검색 할 때 하나를 찾지 못했습니다. 다음과 같은 질문이 나타납니다.
위의 작업을 수행하는 가장 우아한 방법은 무엇입니까?
후드를 보면 QueryString 속성은 NameValueCollection입니다. 비슷한 작업을 수행하면 일반적으로 직렬화 및 역 직렬화에 관심이 있었으므로 NameValueCollection을 빌드 한 다음 전달하는 것이 좋습니다.
using System.Linq;
using System.Web;
using System.Collections.Specialized;
private string ToQueryString(NameValueCollection nvc)
{
var array = (
from key in nvc.AllKeys
from value in nvc.GetValues(key)
select string.Format(
"{0}={1}",
HttpUtility.UrlEncode(key),
HttpUtility.UrlEncode(value))
).ToArray();
return "?" + string.Join("&", array);
}
LINQ 에서도이 작업을 수행하는 매우 우아한 방법이 있다고 생각합니다.
HttpValueCollection
을 호출 하여 새 쓰기 가능한 인스턴스를 System.Web.HttpUtility.ParseQueryString(string.Empty)
만든 다음 any로 사용할 수 있습니다 NameValueCollection
. 원하는 값을 추가하면 ToString
다음과 같이 컬렉션을 호출 하여 쿼리 문자열을 얻을 수 있습니다.
NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
queryString["key1"] = "value1";
queryString["key2"] = "value2";
return queryString.ToString(); // Returns "key1=value1&key2=value2", all URL-encoded
은 HttpValueCollection
내부에 그래서 당신이 직접 인스턴스를 생성 할 수 없습니다. 그러나 일단 인스턴스를 얻으면 다른 인스턴스처럼 사용할 수 있습니다 NameValueCollection
. 작업하고있는 실제 객체는이므로 HttpValueCollection
ToString 메서드를 호출하면 재정의 된 메서드를 on으로 호출 HttpValueCollection
하여 컬렉션을 URL 인코딩 된 쿼리 문자열로 형식화합니다.
비슷한 문제에 대한 답변을 위해 SO와 웹을 검색 한 후에 이것은 내가 찾을 수있는 가장 간단한 솔루션입니다.
.NET 코어
.NET Core에서 작업하는 경우 Microsoft.AspNetCore.WebUtilities.QueryHelpers
클래스를 사용 하면이를 단순화 할 수 있습니다 .
https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.webutilities.queryhelpers
Roy Tinker의 의견에서 영감을 받아 Uri 클래스에서 간단한 확장 메서드를 사용하여 코드를 간결하고 깨끗하게 유지했습니다.
using System.Web;
public static class HttpExtensions
{
public static Uri AddQuery(this Uri uri, string name, string value)
{
var httpValueCollection = HttpUtility.ParseQueryString(uri.Query);
httpValueCollection.Remove(name);
httpValueCollection.Add(name, value);
var ub = new UriBuilder(uri);
ub.Query = httpValueCollection.ToString();
return ub.Uri;
}
}
용법:
Uri url = new Uri("http://localhost/rest/something/browse").
AddQuery("page", "0").
AddQuery("pageSize", "200");
편집-표준 호환 변형
여러 사람들이 지적했듯이 httpValueCollection.ToString()
유니 코드 문자를 비표준 호환 방식으로 인코딩 합니다. 이것은 HttpUtility.UrlEncode
사용되지 않는 HttpUtility.UrlEncodeUnicode
메소드 대신 메소드를 호출하여 이러한 문자를 처리하는 동일한 확장 메소드의 변형입니다 .
using System.Web;
public static Uri AddQuery(this Uri uri, string name, string value)
{
var httpValueCollection = HttpUtility.ParseQueryString(uri.Query);
httpValueCollection.Remove(name);
httpValueCollection.Add(name, value);
var ub = new UriBuilder(uri);
// this code block is taken from httpValueCollection.ToString() method
// and modified so it encodes strings with HttpUtility.UrlEncode
if (httpValueCollection.Count == 0)
ub.Query = String.Empty;
else
{
var sb = new StringBuilder();
for (int i = 0; i < httpValueCollection.Count; i++)
{
string text = httpValueCollection.GetKey(i);
{
text = HttpUtility.UrlEncode(text);
string val = (text != null) ? (text + "=") : string.Empty;
string[] vals = httpValueCollection.GetValues(i);
if (sb.Length > 0)
sb.Append('&');
if (vals == null || vals.Length == 0)
sb.Append(val);
else
{
if (vals.Length == 1)
{
sb.Append(val);
sb.Append(HttpUtility.UrlEncode(vals[0]));
}
else
{
for (int j = 0; j < vals.Length; j++)
{
if (j > 0)
sb.Append('&');
sb.Append(val);
sb.Append(HttpUtility.UrlEncode(vals[j]));
}
}
}
}
}
ub.Query = sb.ToString();
}
return ub.Uri;
}
얼마 전에 비슷한 질문 에 대답했습니다 . 기본적으로 가장 좋은 방법은 HttpValueCollection
ASP.NET의 Request.QueryString
속성이 실제로 클래스 인 클래스를 사용하는 것입니다. 불행히도 .NET 프레임 워크의 내부 클래스 입니다. Reflector를 사용하여 잡아서 (Utils 클래스에 배치) 할 수 있습니다. 이 방법으로 NameValueCollection과 같은 쿼리 문자열을 조작 할 수 있지만 모든 URL 인코딩 / 디코딩 문제가 해결됩니다.
HttpValueCollection
extends NameValueCollection
이고 인코딩 된 쿼리 문자열 (앰퍼샌드 및 물음표 포함) 을 취하는 생성자가 있으며 ToString()
나중에 기본 컬렉션에서 쿼리 문자열을 다시 작성 하는 메서드를 재정의합니다 .
예:
var coll = new HttpValueCollection();
coll["userId"] = "50";
coll["paramA"] = "A";
coll["paramB"] = "B";
string query = coll.ToString(true); // true means use urlencode
Console.WriteLine(query); // prints: userId=50¶mA=A¶mB=B
다음은 동일한 키에 대해 여러 값을 지원하는 확장 방법 (이전 게시물의 개념 결합)으로서의 유창하고 복잡한 방법입니다. 개인적으로 선호하는 것은 다른 팀 구성원이 이와 같은 것을 발견 할 수 있도록 래퍼보다 확장 된 것입니다. 인코딩 방법, 스택 오버플로 (이러한 게시물 중 하나 ) 및 MSDN 블로거 (이와 같은) 에 대한 많은 게시물이 인코딩 방법에 대해 논란 이 있습니다.
public static string ToQueryString(this NameValueCollection source)
{
return String.Join("&", source.AllKeys
.SelectMany(key => source.GetValues(key)
.Select(value => String.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value))))
.ToArray());
}
편집 : null 지원으로 특정 상황에 맞게 조정해야 할 수도 있습니다.
public static string ToQueryString(this NameValueCollection source, bool removeEmptyEntries)
{
return source != null ? String.Join("&", source.AllKeys
.Where(key => !removeEmptyEntries || source.GetValues(key)
.Where(value => !String.IsNullOrEmpty(value))
.Any())
.SelectMany(key => source.GetValues(key)
.Where(value => !removeEmptyEntries || !String.IsNullOrEmpty(value))
.Select(value => String.Format("{0}={1}", HttpUtility.UrlEncode(key), value != null ? HttpUtility.UrlEncode(value) : string.Empty)))
.ToArray())
: string.Empty;
}
Flurl [Disclosure : I 'm is the author]은 익명 객체를 통해 쿼리 문자열 작성을 지원합니다 (다른 방법 중에서도).
var url = "http://www.some-api.com".SetQueryParams(new
{
api_key = ConfigurationManager.AppSettings["SomeApiKey"],
max_results = 20,
q = "Don't worry, I'll get encoded!"
});
선택적 Flurl.Http 컴패니언 라이브러리를 사용하면 유동적 인 동일한 호출 체인에서 HTTP 호출을 수행하여 완전한 REST 클라이언트로 확장 할 수 있습니다.
T result = await "https://api.mysite.com"
.AppendPathSegment("person")
.SetQueryParams(new { ap_key = "my-key" })
.WithOAuthBearerToken("MyToken")
.PostJsonAsync(new { first_name = firstName, last_name = lastName })
.ReceiveJson<T>();
전체 패키지는 NuGet에서 사용할 수 있습니다.
PM> Install-Package Flurl.Http
또는 독립형 URL 작성기 :
PM> Install-Package Flurl
여기 내 늦은 입장입니다. 나는 여러 가지 이유로 다른 사람들을 좋아하지 않아서 내 자신을 썼습니다.
이 버전의 특징 :
StringBuilder 만 사용하십시오. ToArray () 호출 또는 다른 확장 메소드가 없습니다. 그것은 다른 응답들만큼 아름답게 보이지는 않지만, 이것이 핵심 기능이라고 생각하므로 비 효율성을 숨기는 "유창한", "한 줄짜리"코드를 갖는 것보다 효율성이 더 중요합니다.
키당 여러 값을 처리합니다. (나 자신이 필요하지는 않지만 Mauricio를 침묵시키기 위해;)
public string ToQueryString(NameValueCollection nvc) { StringBuilder sb = new StringBuilder("?"); bool first = true; foreach (string key in nvc.AllKeys) { foreach (string value in nvc.GetValues(key)) { if (!first) { sb.Append("&"); } sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value)); first = false; } } return sb.ToString(); }
사용법 예
var queryParams = new NameValueCollection()
{
{ "x", "1" },
{ "y", "2" },
{ "foo", "bar" },
{ "foo", "baz" },
{ "special chars", "? = &" },
};
string url = "http://example.com/stuff" + ToQueryString(queryParams);
Console.WriteLine(url);
산출
http://example.com/stuff?x=1&y=2&foo=bar&foo=baz&special%20chars=%3F%20%3D%20%26
이와 같이 유창한 스타일로 매개 변수를 추가 할 수있는 확장 메소드를 작성하는 것은 어떻습니까?
string a = "http://www.somedomain.com/somepage.html"
.AddQueryParam("A", "TheValueOfA")
.AddQueryParam("B", "TheValueOfB")
.AddQueryParam("Z", "TheValueOfZ");
string b = new StringBuilder("http://www.somedomain.com/anotherpage.html")
.AddQueryParam("A", "TheValueOfA")
.AddQueryParam("B", "TheValueOfB")
.AddQueryParam("Z", "TheValueOfZ")
.ToString();
다음을 사용하는 과부하가 있습니다 string
.
public static string AddQueryParam(
this string source, string key, string value)
{
string delim;
if ((source == null) || !source.Contains("?"))
{
delim = "?";
}
else if (source.EndsWith("?") || source.EndsWith("&"))
{
delim = string.Empty;
}
else
{
delim = "&";
}
return source + delim + HttpUtility.UrlEncode(key)
+ "=" + HttpUtility.UrlEncode(value);
}
그리고 다음을 사용하는 과부하가 있습니다 StringBuilder
.
public static StringBuilder AddQueryParam(
this StringBuilder source, string key, string value)
{
bool hasQuery = false;
for (int i = 0; i < source.Length; i++)
{
if (source[i] == '?')
{
hasQuery = true;
break;
}
}
string delim;
if (!hasQuery)
{
delim = "?";
}
else if ((source[source.Length - 1] == '?')
|| (source[source.Length - 1] == '&'))
{
delim = string.Empty;
}
else
{
delim = "&";
}
return source.Append(delim).Append(HttpUtility.UrlEncode(key))
.Append("=").Append(HttpUtility.UrlEncode(value));
}
작업중 인 PCL (Portable Class Library)에 대해 동일한 문제를 해결해야했습니다. 이 경우 System.Web에 액세스 할 수 없으므로 ParseQueryString을 사용할 수 없습니다.
대신 나는 이렇게 사용 System.Net.Http.FormUrlEncodedContent
했다 :
var url = new UriBuilder("http://example.com");
url.Query = new FormUrlEncodedContent(new Dictionary<string,string>()
{
{"param1", "val1"},
{"param2", "val2"},
{"param3", "val3"},
}).ReadAsStringAsync().Result;
public static string ToQueryString(this Dictionary<string, string> source)
{
return String.Join("&", source.Select(kvp => String.Format("{0}={1}", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value))).ToArray());
}
public static string ToQueryString(this NameValueCollection source)
{
return String.Join("&", source.Cast<string>().Select(key => String.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(source[key]))).ToArray());
}
이 클래스를 프로젝트에 추가
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class QueryStringBuilder
{
private readonly List<KeyValuePair<string, object>> _list;
public QueryStringBuilder()
{
_list = new List<KeyValuePair<string, object>>();
}
public void Add(string name, object value)
{
_list.Add(new KeyValuePair<string, object>(name, value));
}
public override string ToString()
{
return String.Join("&", _list.Select(kvp => String.Concat(Uri.EscapeDataString(kvp.Key), "=", Uri.EscapeDataString(kvp.Value.ToString()))));
}
}
그리고 이것을 다음과 같이 사용하십시오 :
var actual = new QueryStringBuilder {
{"foo", 123},
{"bar", "val31"},
{"bar", "val32"}
};
actual.Add("a+b", "c+d");
actual.ToString(); // "foo=123&bar=val31&bar=val32&a%2bb=c%2bd"
내 제안 :
public static Uri AddQuery(this Uri uri, string name, string value)
{
// this actually returns HttpValueCollection : NameValueCollection
// which uses unicode compliant encoding on ToString()
var query = HttpUtility.ParseQueryString(uri.Query);
query.Add(name, value);
var uriBuilder = new UriBuilder(uri)
{
Query = query.ToString()
};
return uriBuilder.Uri;
}
용법:
var uri = new Uri("http://stackoverflow.com").AddQuery("such", "method")
.AddQuery("wow", "soFluent");
// http://stackoverflow.com?such=method&wow=soFluent
테스트를 거치지 않았지만이 라인을 따라 뭔가가 잘 작동한다고 생각합니다.
public class QueryString
{
private Dictionary<string,string> _Params = new Dictionary<string,string>();
public overide ToString()
{
List<string> returnParams = new List<string>();
foreach (KeyValuePair param in _Params)
{
returnParams.Add(String.Format("{0}={1}", param.Key, param.Value));
}
// return String.Format("?{0}", String.Join("&", returnParams.ToArray()));
// credit annakata
return "?" + String.Join("&", returnParams.ToArray());
}
public void Add(string key, string value)
{
_Params.Add(key, HttpUtility.UrlEncode(value));
}
}
QueryString query = new QueryString();
query.Add("param1", "value1");
query.Add("param2", "value2");
return query.ToString();
빠른 확장 방법 기반 버전 :
class Program
{
static void Main(string[] args)
{
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("A", "AValue"),
new KeyValuePair<string, string>("B", "BValue")
};
string output = "?" + string.Join("&", parameters.ConvertAll(param => param.ToQueryString()).ToArray());
}
}
public static class KeyValueExtensions
{
public static string ToQueryString(this KeyValuePair<string, string> obj)
{
return obj.Key + "=" + HttpUtility.UrlEncode(obj.Value);
}
}
where 절을 사용하여 문자열에 추가 할 매개 변수를 선택할 수 있습니다.
다른 어셈블리에 대한 종속성을 줄이고 단순하게 유지하려는 경우 다음을 수행 할 수 있습니다.
var sb = new System.Text.StringBuilder();
sb.Append("a=" + HttpUtility.UrlEncode("TheValueOfA") + "&");
sb.Append("b=" + HttpUtility.UrlEncode("TheValueOfB") + "&");
sb.Append("c=" + HttpUtility.UrlEncode("TheValueOfC") + "&");
sb.Append("d=" + HttpUtility.UrlEncode("TheValueOfD") + "&");
sb.Remove(sb.Length-1, 1); // Remove the final '&'
string result = sb.ToString();
이것은 루프에서도 잘 작동합니다. 최종 앰퍼샌드 제거는 루프 외부로 이동해야합니다.
연결 연산자는 가독성을 향상시키는 데 사용됩니다. StringBuilder를 사용하는 비용과 비교하여 사용 비용이 최소화됩니다 ( Jeff Atwood 가이 주제에 뭔가를 게시 했다고 생각합니다 ).
익명의 객체 버전 을 만들기 위해 최고의 답변을 결합했습니다 .
var queryString = HttpUtility2.BuildQueryString(new
{
key2 = "value2",
key1 = "value1",
});
이것은 이것을 생성합니다 :
key2 = value2 & key1 = value1
코드는 다음과 같습니다.
public static class HttpUtility2
{
public static string BuildQueryString<T>(T obj)
{
var queryString = HttpUtility.ParseQueryString(string.Empty);
foreach (var property in TypeDescriptor.GetProperties(typeof(T)).Cast<PropertyDescriptor>())
{
var value = (property.GetValue(obj) ?? "").ToString();
queryString.Add(property.Name, value);
}
return queryString.ToString();
}
}
[또한 늦게 입장]
HttpValueCollection에 대한 체인 가능 래퍼 클래스 :
namespace System.Web.Mvc {
public class QueryStringBuilder {
private NameValueCollection collection;
public QueryStringBuilder() {
collection = System.Web.HttpUtility.ParseQueryString(string.Empty);
}
public QueryStringBuilder Add(string key, string value) {
collection.Add(key, value);
return this;
}
public QueryStringBuilder Remove(string key) {
collection.Remove(key);
return this;
}
public string this[string key] {
get { return collection[key]; }
set { collection[key] = value; }
}
public string ToString() {
return collection.ToString();
}
}
}
사용법 예 :
QueryStringBuilder parameters = new QueryStringBuilder()
.Add("view", ViewBag.PageView)
.Add("page", ViewBag.PageNumber)
.Add("size", ViewBag.PageSize);
string queryString = parameters.ToString();
허용 된 솔루션과 동일하지만 LINQ 구문을 "dot"로 변환합니다.
private string ToQueryString(NameValueCollection nvc)
{
if (nvc == null) return String.Empty;
var queryParams =
string.Join("&", nvc.AllKeys.Select(key =>
string.Join("&", nvc.GetValues(key).Select(v => string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(v))))));
return "?" + queryParams;
}
Uri 의 확장 방법 이 있습니다.
- 익명 객체를 허용합니다.
uri.WithQuery(new { name = "value" })
string/string
쌍 모음 (예 : Dictionary`2 )을 허용합니다.string/object
쌍의 컬렉션을 허용합니다 (예 : RouteValueDictionary ).- NameValueCollection을 승인합니다 .
- 동일한 값이 동일한 URI를 생성하도록 쿼리 값을 키별로 정렬합니다.
- 원래 순서를 유지하면서 키당 여러 값을 지원합니다.
확장 :
public static Uri WithQuery(this Uri uri, object values)
{
if (uri == null)
throw new ArgumentNullException(nameof(uri));
if (values != null)
{
var query = string.Join(
"&", from p in ParseQueryValues(values)
where !string.IsNullOrWhiteSpace(p.Key)
let k = HttpUtility.UrlEncode(p.Key.Trim())
let v = HttpUtility.UrlEncode(p.Value)
orderby k
select string.IsNullOrEmpty(v) ? k : $"{k}={v}");
if (query.Length != 0 || uri.Query.Length != 0)
uri = new UriBuilder(uri) { Query = query }.Uri;
}
return uri;
}
쿼리 파서 :
private static IEnumerable<KeyValuePair<string, string>> ParseQueryValues(object values)
{
// Check if a name/value collection.
var nvc = values as NameValueCollection;
if (nvc != null)
return from key in nvc.AllKeys
from val in nvc.GetValues(key)
select new KeyValuePair<string, string>(key, val);
// Check if a string/string dictionary.
var ssd = values as IEnumerable<KeyValuePair<string, string>>;
if (ssd != null)
return ssd;
// Check if a string/object dictionary.
var sod = values as IEnumerable<KeyValuePair<string, object>>;
if (sod == null)
{
// Check if a non-generic dictionary.
var ngd = values as IDictionary;
if (ngd != null)
sod = ngd.Cast<dynamic>().ToDictionary<dynamic, string, object>(
p => p.Key.ToString(), p => p.Value as object);
// Convert object properties to dictionary.
if (sod == null)
sod = new RouteValueDictionary(values);
}
// Normalize and return the values.
return from pair in sod
from val in pair.Value as IEnumerable<string>
?? new[] { pair.Value?.ToString() }
select new KeyValuePair<string, string>(pair.Key, val);
}
테스트는 다음과 같습니다.
var uri = new Uri("https://stackoverflow.com/yo?oldKey=oldValue");
// Test with a string/string dictionary.
var q = uri.WithQuery(new Dictionary<string, string>
{
["k1"] = string.Empty,
["k2"] = null,
["k3"] = "v3"
});
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?k1&k2&k3=v3"));
// Test with a string/object dictionary.
q = uri.WithQuery(new Dictionary<string, object>
{
["k1"] = "v1",
["k2"] = new[] { "v2a", "v2b" },
["k3"] = null
});
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?k1=v1&k2=v2a&k2=v2b&k3"));
// Test with a name/value collection.
var nvc = new NameValueCollection()
{
["k1"] = string.Empty,
["k2"] = "v2a"
};
nvc.Add("k2", "v2b");
q = uri.WithQuery(nvc);
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?k1&k2=v2a&k2=v2b"));
// Test with any dictionary.
q = uri.WithQuery(new Dictionary<int, HashSet<string>>
{
[1] = new HashSet<string> { "v1" },
[2] = new HashSet<string> { "v2a", "v2b" },
[3] = null
});
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?1=v1&2=v2a&2=v2b&3"));
// Test with an anonymous object.
q = uri.WithQuery(new
{
k1 = "v1",
k2 = new[] { "v2a", "v2b" },
k3 = new List<string> { "v3" },
k4 = true,
k5 = null as Queue<string>
});
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?k1=v1&k2=v2a&k2=v2b&k3=v3&k4=True&k5"));
// Keep existing query using a name/value collection.
nvc = HttpUtility.ParseQueryString(uri.Query);
nvc.Add("newKey", "newValue");
q = uri.WithQuery(nvc);
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?newKey=newValue&oldKey=oldValue"));
// Merge two query objects using the RouteValueDictionary.
var an1 = new { k1 = "v1" };
var an2 = new { k2 = "v2" };
q = uri.WithQuery(
new RouteValueDictionary(an1).Concat(
new RouteValueDictionary(an2)));
Debug.Assert(q == new Uri(
"https://stackoverflow.com/yo?k1=v1&k2=v2"));
PageBase 클래스에 다음 메소드를 추가했습니다.
protected void Redirect(string url)
{
Response.Redirect(url);
}
protected void Redirect(string url, NameValueCollection querystrings)
{
StringBuilder redirectUrl = new StringBuilder(url);
if (querystrings != null)
{
for (int index = 0; index < querystrings.Count; index++)
{
if (index == 0)
{
redirectUrl.Append("?");
}
redirectUrl.Append(querystrings.Keys[index]);
redirectUrl.Append("=");
redirectUrl.Append(HttpUtility.UrlEncode(querystrings[index]));
if (index < querystrings.Count - 1)
{
redirectUrl.Append("&");
}
}
}
this.Redirect(redirectUrl.ToString());
}
전화 :
NameValueCollection querystrings = new NameValueCollection();
querystrings.Add("language", "en");
querystrings.Add("id", "134");
this.Redirect("http://www.mypage.com", querystrings);
QueryStrings로 작업 할 때 매우 유용한 확장 메소드를 작성했습니다. 종종 현재 QueryString으로 시작하여 사용하기 전에 수정하고 싶습니다. 같은 것
var res = Request.QueryString.Duplicate()
.ChangeField("field1", "somevalue")
.ChangeField("field2", "only if following is true", true)
.ChangeField("id", id, id>0)
.WriteLocalPathWithQuery(Request.Url)); //Uses context to write the path
자세한 내용 및 출처 : http://www.charlesrcook.com/archive/2008/07/23/c-extension-methods-for-asp.net-query-string-operations.aspx
기본이지만 스타일이 마음에 듭니다.
방금 내 2 센트를 던지고 싶었습니다.
public static class HttpClientExt
{
public static Uri AddQueryParams(this Uri uri, string query)
{
var ub = new UriBuilder(uri);
ub.Query = string.IsNullOrEmpty(uri.Query) ? query : string.Join("&", uri.Query.Substring(1), query);
return ub.Uri;
}
public static Uri AddQueryParams(this Uri uri, IEnumerable<string> query)
{
return uri.AddQueryParams(string.Join("&", query));
}
public static Uri AddQueryParams(this Uri uri, string key, string value)
{
return uri.AddQueryParams(string.Join("=", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value)));
}
public static Uri AddQueryParams(this Uri uri, params KeyValuePair<string,string>[] kvps)
{
return uri.AddQueryParams(kvps.Select(kvp => string.Join("=", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value))));
}
public static Uri AddQueryParams(this Uri uri, IDictionary<string, string> kvps)
{
return uri.AddQueryParams(kvps.Select(kvp => string.Join("=", HttpUtility.UrlEncode(kvp.Key), HttpUtility.UrlEncode(kvp.Value))));
}
public static Uri AddQueryParams(this Uri uri, NameValueCollection nvc)
{
return uri.AddQueryParams(nvc.AllKeys.SelectMany(nvc.GetValues, (key, value) => string.Join("=", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value))));
}
}
워드 프로세서는 그 말 uri.Query
와 함께 시작됩니다?
비어 있지 않은 경우로 수정하려는 경우 잘라야한다고 말합니다.
그 내용 HttpUtility.UrlEncode
은System.Web
.
용법:
var uri = new Uri("https://api.del.icio.us/v1/posts/suggest").AddQueryParam("url","http://stackoverflow.com")
우아한 아니지만, 내가 사용하지 않는 간단한 버전을 선택했다 NameValueCollecitons
감싸 단지 빌더 패턴 - StringBuilder
.
public class UrlBuilder
{
#region Variables / Properties
private readonly StringBuilder _builder;
#endregion Variables / Properties
#region Constructor
public UrlBuilder(string urlBase)
{
_builder = new StringBuilder(urlBase);
}
#endregion Constructor
#region Methods
public UrlBuilder AppendParameter(string paramName, string value)
{
if (_builder.ToString().Contains("?"))
_builder.Append("&");
else
_builder.Append("?");
_builder.Append(HttpUtility.UrlEncode(paramName));
_builder.Append("=");
_builder.Append(HttpUtility.UrlEncode(value));
return this;
}
public override string ToString()
{
return _builder.ToString();
}
#endregion Methods
}
기존 답변에 따라 HttpUtility.UrlEncode
전화 를 사용했습니다 . 다음과 같이 사용됩니다.
string url = new UrlBuilder("http://www.somedomain.com/")
.AppendParameter("a", "true")
.AppendParameter("b", "muffin")
.AppendParameter("c", "muffin button")
.ToString();
// Result: http://www.somedomain.com?a=true&b=muffin&c=muffin%20button
// USAGE
[TestMethod]
public void TestUrlBuilder()
{
Console.WriteLine(
new UrlBuilder("http://www.google.com?A=B")
.AddPath("SomePathName")
.AddPath("AnotherPathName")
.SetQuery("SomeQueryKey", "SomeQueryValue")
.AlterQuery("A", x => x + "C"));
}
산출:
http://www.google.com/SomePathName/AnotherPathName?A=BC&SomeQueryKey=SomeQueryValue
코드; 어딘가에 고마워 할 수 있습니다. : D
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
// By Demetris Leptos
namespace TheOperator.Foundation.Web
{
public class UrlBuilder
{
public string Scheme { get; set; }
public string Host { get; set; }
public int? Port { get; set; }
public List<string> Paths { get; set; }
public SortedDictionary<string, string> QueryPairs { get; set; }
public UrlBuilder(string url)
{
this.Paths = new List<string>();
this.QueryPairs = new SortedDictionary<string, string>();
string path = null;
string query = null;
Uri relativeUri = null;
if (!Uri.TryCreate(url, UriKind.Relative, out relativeUri))
{
var uriBuilder = new UriBuilder(url);
this.Scheme = uriBuilder.Scheme;
this.Host = uriBuilder.Host;
this.Port = uriBuilder.Port;
path = uriBuilder.Path;
query = uriBuilder.Query;
}
else
{
var queryIndex = url.IndexOf('?');
if (queryIndex >= 0)
{
path = url.Substring(0, queryIndex);
query = url.Substring(queryIndex + 1);
}
else
{
path = url;
}
}
this.Paths.AddRange(path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries));
if (query != null)
{
var queryKeyValuePairs = HttpUtility.ParseQueryString(query);
foreach (var queryKey in queryKeyValuePairs.AllKeys)
{
this.QueryPairs[queryKey] = queryKeyValuePairs[queryKey];
}
}
}
public UrlBuilder AddPath(string value)
{
this.Paths.Add(value);
return this;
}
public UrlBuilder SetQuery(string key, string value)
{
this.QueryPairs[key] = value;
return this;
}
public UrlBuilder RemoveQuery(string key)
{
this.QueryPairs.Remove(key);
return this;
}
public UrlBuilder AlterQuery(string key, Func<string, string> alterMethod, bool removeOnNull = false)
{
string value;
this.QueryPairs.TryGetValue(key, out value);
value = alterMethod(value);
if (removeOnNull && value == null)
{
return this.RemoveQuery(key);
}
else
{
return this.SetQuery(key, value);
}
}
public override string ToString()
{
var path = !string.IsNullOrWhiteSpace(this.Host)
? string.Join("/", this.Host, string.Join("/", this.Paths))
: string.Join("/", this.Paths);
var query = string.Join("&", this.QueryPairs.Select(x => string.Concat(x.Key, "=", HttpUtility.UrlEncode(x.Value))));
return string.Concat(
!string.IsNullOrWhiteSpace(this.Scheme) ? string.Concat(this.Scheme, "://") : null,
path,
!string.IsNullOrWhiteSpace(query) ? string.Concat("?", query) : null);
}
}
}
DSO가 제안한 솔루션 (7 월 29 일 8 월 2 일에 답변 됨)과 함께 갔으며 그의 솔루션에는 HttpUtility를 사용할 필요가 없습니다. 그러나 Dotnetpearls에 게시 된 기사에 따르면 NameValueCollection 을 사용하는 것보다 Dictionary를 사용하는 것이 성능이 더 빠릅니다. 다음은 NameValueCollection 대신 Dictionary를 사용하도록 수정 된 DSO의 솔루션입니다.
public static Dictionary<string, string> QueryParametersDictionary()
{
var dictionary = new Dictionary<string, string>();
dictionary.Add("name", "John Doe");
dictionary.Add("address.city", "Seattle");
dictionary.Add("address.state_code", "WA");
dictionary.Add("api_key", "5352345263456345635");
return dictionary;
}
public static string ToQueryString(Dictionary<string, string> nvc)
{
StringBuilder sb = new StringBuilder();
bool first = true;
foreach (KeyValuePair<string, string> pair in nvc)
{
if (!first)
{
sb.Append("&");
}
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(pair.Key), Uri.EscapeDataString(pair.Value));
first = false;
}
return sb.ToString();
}
다른 답변의 힌트를 사용하여 면도기 프로젝트 도우미를 작성했습니다.
ParseQueryString 비즈니스는 현재 요청의 QueryString 오브젝트를 조작 할 수 없으므로 필요합니다.
@helper GetQueryStringWithValue(string key, string value) {
var queryString = System.Web.HttpUtility.ParseQueryString(HttpContext.Current.Request.QueryString.ToString());
queryString[key] = value;
@Html.Raw(queryString.ToString())
}
나는 이것을 다음과 같이 사용한다 :
location.search = '?@Helpers.GetQueryStringWithValue("var-name", "var-value")';
둘 이상의 값을 사용하려면 매개 변수를 Dictionary로 변경하고 쌍을 쿼리 문자열에 추가하십시오.
아래 코드는 ILSpy를 통해 의 HttpValueCollection
구현 에서 제외되어 ToString
name = value 쿼리 문자열을 제공합니다.
불행히도 HttpValueCollection은를 사용하는 경우에만 반환되는 내부 클래스입니다 HttpUtility.ParseQueryString()
. 모든 viewstate 부분을 제거하고 기본적으로 인코딩합니다.
public static class HttpExtensions
{
public static string ToQueryString(this NameValueCollection collection)
{
// This is based off the NameValueCollection.ToString() implementation
int count = collection.Count;
if (count == 0)
return string.Empty;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < count; i++)
{
string text = collection.GetKey(i);
text = HttpUtility.UrlEncodeUnicode(text);
string value = (text != null) ? (text + "=") : string.Empty;
string[] values = collection.GetValues(i);
if (stringBuilder.Length > 0)
{
stringBuilder.Append('&');
}
if (values == null || values.Length == 0)
{
stringBuilder.Append(value);
}
else
{
if (values.Length == 1)
{
stringBuilder.Append(value);
string text2 = values[0];
text2 = HttpUtility.UrlEncodeUnicode(text2);
stringBuilder.Append(text2);
}
else
{
for (int j = 0; j < values.Length; j++)
{
if (j > 0)
{
stringBuilder.Append('&');
}
stringBuilder.Append(value);
string text2 = values[j];
text2 = HttpUtility.UrlEncodeUnicode(text2);
stringBuilder.Append(text2);
}
}
}
}
return stringBuilder.ToString();
}
}
이것은 약간 더 컴팩트 한 것을 제외하고는 허용되는 답변과 동일합니다.
private string ToQueryString(NameValueCollection nvc)
{
return "?" + string.Join("&", nvc.AllKeys.Select(k => string.Format("{0}={1}",
HttpUtility.UrlEncode(k),
HttpUtility.UrlEncode(nvc[k]))));
}
VB.NET 버전의 최고 답변이 필요한 사람들을 위해 :
Public Function ToQueryString(nvc As System.Collections.Specialized.NameValueCollection) As String
Dim array As String() = nvc.AllKeys.SelectMany(Function(key As String) nvc.GetValues(key), Function(key As String, value As String) String.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(key), System.Web.HttpUtility.UrlEncode(value))).ToArray()
Return "?" + String.Join("&", array)
End Function
그리고 LINQ가없는 버전 :
Public Function ToQueryString(nvc As System.Collections.Specialized.NameValueCollection) As String
Dim lsParams As New List(Of String)()
For Each strKey As String In nvc.AllKeys
Dim astrValue As String() = nvc.GetValues(strKey)
For Each strValue As String In astrValue
lsParams.Add(String.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(strKey), System.Web.HttpUtility.UrlEncode(strValue)))
Next ' Next strValue
Next ' strKey
Dim astrParams As String() = lsParams.ToArray()
lsParams.Clear()
lsParams = Nothing
Return "?" + String.Join("&", astrParams)
End Function ' ToQueryString
그리고 LINQ가없는 C # 버전 :
public static string ToQueryString(System.Collections.Specialized.NameValueCollection nvc)
{
List<string> lsParams = new List<string>();
foreach (string strKey in nvc.AllKeys)
{
string[] astrValue = nvc.GetValues(strKey);
foreach (string strValue in astrValue)
{
lsParams.Add(string.Format("{0}={1}", System.Web.HttpUtility.UrlEncode(strKey), System.Web.HttpUtility.UrlEncode(strValue)));
} // Next strValue
} // Next strKey
string[] astrParams =lsParams.ToArray();
lsParams.Clear();
lsParams = null;
return "?" + string.Join("&", astrParams);
} // End Function ToQueryString
NameValueCollection의 키당 여러 값에 작동합니다.
예 : { {"k1", "v1"}, {"k1", "v1"} }
=>?k1=v1&k1=v1
/// <summary>
/// Get query string for name value collection.
/// </summary>
public static string ToQueryString(this NameValueCollection collection,
bool prefixQuestionMark = true)
{
collection.NullArgumentCheck();
if (collection.Keys.Count == 0)
{
return "";
}
var buffer = new StringBuilder();
if (prefixQuestionMark)
{
buffer.Append("?");
}
var append = false;
for (int i = 0; i < collection.Keys.Count; i++)
{
var key = collection.Keys[i];
var values = collection.GetValues(key);
key.NullCheck();
values.NullCheck();
foreach (var value in values)
{
if (append)
{
buffer.Append("&");
}
append = true;
buffer.AppendFormat("{0}={1}", key.UrlEncode(), value.UrlEncode());
}
}
return buffer.ToString();
}
참고 URL : https://stackoverflow.com/questions/829080/how-to-build-a-query-string-for-a-url-in-c
'Programming' 카테고리의 다른 글
컴포넌트 템플릿에서 요소를 어떻게 선택할 수 있습니까? (0) | 2020.02.16 |
---|---|
가장자리가 아닌 div 내부에 테두리 배치 (0) | 2020.02.16 |
속성의 값으로 인덱스를 갖는 ngFor (0) | 2020.02.16 |
우리는 항상 Swift에서 [소유하지 않은 자체] 클로저를 사용해야합니까? (0) | 2020.02.16 |
C #에서 선택적 매개 변수를 어떻게 사용할 수 있습니까? (0) | 2020.02.16 |