programing

C#에서 URL에 대한 쿼리 문자열을 작성하는 방법은 무엇입니까?

javajsp 2023. 6. 3. 08:15

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을 검색하는 중에 MSDN을 찾지 못했습니다. 다음과 같은 질문이 나옵니다.

위와 같은 일을 할 때 당신이 알고 있는 가장 우아하고 깨끗한 방법은 무엇입니까?

쓰가인기생수있다니습성할를스의 쓰기 를 새로 수 .HttpValueCollection화로로 System.Web.HttpUtility.ParseQueryString(string.Empty)그리고 나서 그것을 아무 것이나 사용합니다.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에서 됩니다.HttpValueCollection컬렉션을 URL로 인코딩된 쿼리 문자열로 형식을 지정합니다.

SO와 웹에서 유사한 문제에 대한 답을 검색한 후, 이것이 제가 찾을 수 있는 가장 간단한 해결책입니다.

.NET 코어

Core에서 .NET Core를 할 수 .Microsoft.AspNetCore.WebUtilities.QueryHelpers클래스, 이것을 크게 단순화합니다.

https://learn.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));

후드 아래를 보면 QueryString 속성이 NameValueCollection입니다.비슷한 일을 해본 적이 있을 때, 저는 보통 연속화와 역직렬화에 관심이 있었기 때문에 NameValue Collection을 구축한 다음 다음에 전달하는 것이 좋습니다.

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에서도 아주 우아한 방법이 있을 거라고 생각합니다.

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");

편집 - 표준 준수 변형 모델

처럼, 몇사람지이듯적했이들몇,이▁as듯,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;
}

Flurl [공개:I'm 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 companion lib를 사용하면 동일한 유창한 콜 체인에서 바로 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

아무도 AspNet의 QueryBuilder를 언급하지 않은 것이 궁금합니다.코어.

은복키가있쿼는리있유때다니용합을가음중▁▁like▁▁key와 같은 중복된 키가 쿼리가 때 ?filter=a&filter=b

var qb = new QueryBuilder();
qb.Add("filter", new string[] {"A", "B"});

그런 다음 qb를 URI에 추가하면 자동으로 문자열로 변환됩니다.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.extensions.querybuilder?view=aspnetcore-5.0

저는 얼마 전에 비슷한 질문에 답했습니다.기본적으로 가장 좋은 방법은 ASP.NET의 클래스를 사용하는 것입니다.Request.QueryString속성은 실제로 .NET 프레임워크의 내부에 있습니다.Reflector를 사용하여 이를 가져와 Utils 클래스에 배치할 수 있습니다.이렇게 하면 NameValueCollection과 같이 쿼리 문자열을 조작할 수 있지만 URL 인코딩/디코딩 문제는 모두 해결됩니다.

HttpValueCollection 확된장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&paramA=A&paramB=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;
}

이것이 제가 늦게 입장한 것입니다.저는 여러 가지 이유로 다른 어떤 것도 마음에 들지 않아서 저만의 글을 썼습니다.

이 버전의 특징은 다음과 같습니다.

  • 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

제가 작업 중인 휴대용 클래스 라이브러리(PCL)에서도 동일한 문제를 해결해야 했습니다.이 경우 시스템에 액세스할 수 없습니다.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;

이렇게 유창한 스타일로 매개 변수를 추가할 수 있는 확장 방법을 만들면 어떨까요?

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(); 

▁a▁▁uses를 사용하는 과부하가 여기 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);
}

▁a▁that▁▁uses다있▁and를 사용하는 과부하가 있습니다.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));
}
    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 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();

내 제안:

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

도트넷 코어 쿼리 도우미입니다.AddQueryString()은 키-값 쌍의 ID사전<string,string>을 허용합니다.몇 개의 메모리 할당 및 CPU 주기를 저장하려면 Dictionary<,> 대신 SortedList<,>를 사용하여 적절한 용량과 항목을 정렬 순서로 추가할 수 있습니다...

var queryParams = new SortedList<string,string>(2);
queryParams.Add("abc", "val1");
queryParams.Add("def", "val2");

string requestUri = QueryHelpers.AddQueryString("https://localhost/api", queryParams);

상위 답변을 결합하여 익명 개체 버전을 만듭니다.

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

빠른 확장 방법 기반 버전:

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 절을 사용하여 문자열에 추가할 매개 변수를 선택할 수 있습니다.

여기에는 많은 좋은 답변들이 있지만 최신 C#을 사용하는 사람들에게는 이것이 유지하기에 좋은 유틸리티 클래스일 수 있습니다.

public class QueryParamBuilder
{
    private readonly Dictionary<string, string> _fields = new();
    public QueryParamBuilder Add(string key, string value)
    {
        _fields.Add(key, value);
        return this;
    }
    public string Build()
    {
        return $"?{String.Join("&", _fields.Select(pair => $"{HttpUtility.UrlEncode(pair.Key)}={HttpUtility.UrlEncode(pair.Value)}"))}";
    }
    public static QueryParamBuilder New => new();
}

나는 내부를 사용합니다.Dictionary키 값 쌍이기 에 기서 사 전 로 내 열 가 쌍 때 보 그 문 에 것 만 듭 다 니 쉽 게 에 씬 훨 반 대 들 복 여 한 을 다 기 이 능 값 은 한 키 거 부 적으 ▁a ▁over ▁than ▁easier ▁here ▁value ▁diction ▁iter ▁much ▁intern ▁them ▁because 다 니 ▁key ▁enum ▁makes ▁are ▁pairs 여 듭 NameValueCollection.

그러면 쿼리 문자열 자체가 조인이 있는 단순 보간 문자열입니다.

저는 을 매우 된 방법을 합니다.Add새 쿼리 매개 변수 값을 추가합니다.으로 마막으로종료니다합인을체로 체인을 종료합니다.Build()실제로 마지막 끈을 얻는 것.

다음은 사용법의 예입니다.

var queryString = QueryParamBuilder.New
     .Add("id", "0123")
     .Add("value2", 1234.ToString())
     .Add("valueWithSpace","value with spa12!@#@!ce")
     .Build();

결과는 예상대로입니다.

?id=0123&value2=1234&valueWithSpace=value+with+spa12!%40%23%40!ce

여러분 중 몇몇은 이것이 멋지고 우아하다는 것을 알게 되기를 바랍니다.

다른 어셈블리에 대한 종속성을 줄이고 단순성을 유지하기 위해 다음을 수행할 수 있습니다.

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();

이것은 루프에도 잘 작동합니다.최종 앰퍼샌드 제거는 루프 밖으로 나가야 합니다.

가독성 향상을 위해 연결 연산자가 사용됩니다.String Builder를 사용하는 비용에 비해 사용하는 비용은 미미합니다(Jeff Atwood가 이 주제에 대해 무언가를 게시했다고 생각합니다.

우아하지는 않지만 사용하지 않는 간단한 버전을 선택했습니다.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

URI에 대한 확장 방법이 있습니다.

  • 개체를 할 수 있습니다.uri.WithQuery(new { name = "value" })
  • 의컬을수다니의 을 사용할 수 .string/string쌍(예: Dictionary "2).
  • 의컬을수다니의 을 사용할 수 .string/object쌍(예: RouteValueDictionary).
  • NameValueCollections를 사용할 수 있습니다.
  • 동일한 값이 동일한 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"));

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();

승인된 솔루션과 동일하지만 "dot" LINQ 구문으로 변환됨...

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

쿼리 문자열은 다음을 통해 URL에 추가할 수 있습니다.

  1. 이름 값 컬렉션 개체 생성
  2. 쿼리 문자열 항목 및 항목 값을 이 개체에 추가합니다.
  3. 이 이름 값 컬렉션 개체를 코드가 아래 링크에 제공된 URL로 인코딩합니다.

https://blog.codingnovice.com/blog

public ActionResult Create()
{
    //declaring name value collection object
    NameValueCollection collection = new NameValueCollection();

    //adding new value to the name value collection object
    collection.Add("Id1", "wwe323");
    collection.Add("Id2", "454w");
    collection.Add("Id3", "tyt5656");
    collection.Add("Id4", "343wdsd");

    //generating query string
    string url = GenerateQueryString(collection);

    return View();
}

private string GenerateQueryString(NameValueCollection collection)
{
    var querystring = (
        from key in collection.AllKeys
        from value in collection.GetValues(key)
        select string.Format("{0}={1}",
            HttpUtility.UrlEncode(key),
            HttpUtility.UrlEncode(value))
    ).ToArray();
    return "?" + string.Join("&", querystring);
}

다음 메소드를 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")
// 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가 제안한 솔루션(2011년 8월 2일 7시 29분에 답변)을 진행했는데, 그의 솔루션은 HttpUtility를 사용할 필요가 없습니다.그러나 Dotnetpears에 게시된 기사에 따르면 사전을 사용하는 것이 NameValueCollection을 사용하는 것보다 성능이 더 빠릅니다.다음은 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();
    }

저는 다른 답변에서 힌트를 얻어 면도기 프로젝트의 도우미를 썼습니다.

현재 요청의 QueryString 개체를 조작할 수 없으므로 ParseQueryString 비즈니스가 필요합니다.

@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")';

둘 이상의 값을 사용하려면 매개 변수를 사전으로 변경하고 쿼리 문자열에 쌍을 추가합니다.

언급URL : https://stackoverflow.com/questions/829080/how-to-build-a-query-string-for-a-url-in-c