코드에서 웹 리소스를 호출 할 때 일반적인 작업은 필요한 모든 매개 변수를 포함하도록 쿼리 문자열을 작성하는 것입니다. 로켓 과학은 &
아니지만, 첫 번째 매개 변수가 아닌 경우 추가하고 매개 변수를 인코딩하는 등 몇 가지 멋진 세부 정보가 필요합니다 .
그것을하는 코드는 매우 간단하지만 약간 지루합니다.
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.Add("key1", "value1");
queryString.Add("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
샘플 코드 :
const string url = "https://customer-information.azure-api.net/customers/search/taxnbr";
var param = new Dictionary<string, string>() { { "CIKey", "123456789" } };
var newUrl = new Uri(QueryHelpers.AddQueryString(url, param));
답변
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
