2009-05-26 71 views
8

我想實現像下面這樣:是否有支持請求參數串聯的URL構建器?

UrlBuilder ub = new UrlBuilder("http://www.google.com/search"); 
ub.Parameters.Add("q","request"); 
ub.Parameters.Add("sourceid","ie8"); 

string uri = ub.ToString(); //http://www.google.com/search?q=request&sourceid=ie8 

是否有.NET東西,否則我將不得不建立自己的?

回答

11

我所知道的並不存在。這裏有一些簡單的東西,可以做你想做的事。用法是:

 UrlBuilder ub = new UrlBuilder("www.google.com/search") 
     .AddQuery("q", "request") 
     .AddQuery("sourceid", "ie8"); 

     string url=ub.ToString(); 

==

代碼是:

public class UrlBuilder 
    { 
     private string _authority; 
     private string _host; 
     private int? _port; 
     private Dictionary<string, object> _query = new Dictionary<string, object>(); 

     public UrlBuilder(string host) 
      : this("http", host, null) 
     { 

     } 
     public UrlBuilder(string authority, string host) 
      : this(authority, host, null) 
     { 
     } 
     public UrlBuilder(string authority, string host, int? port) 
     { 
      this._authority = authority; 
      this._host = host; 
      this._port = port; 
     } 

     public UrlBuilder AddQuery(string key, object value) 
     { 
      this._query.Add(key, value); 
      return this; 
     } 

     public override string ToString() 
     { 
      string url = _authority + "://" + _host; 
      if (_port.HasValue) 
      { 
       url += ":" + _port.ToString(); 
      } 


      return AppendQuery(url); 
     } 

     private string AppendQuery(string url) 
     { 
      if (_query.Count == 0) 
      { 
       return url; 
      } 

      url += "?"; 
      bool isNotFirst = false; 
      foreach (var key in this._query.Keys) 
      { 
       if (isNotFirst) 
       { 
        url += "&"; 
       } 
       url += HttpUtility.UrlEncode(key) + "=" + HttpUtility.UrlEncode(this._query[key].ToString()); 
       isNotFirst = true; 
      } 

      return url; 
     } 
    } 
} 
+0

@Josh:+1的努力。您也可以使AddQuery成爲Uri或UriBuilder類的一種方法(存在於框架中) - 只是一個建議。 – shahkalpesh 2009-05-26 01:57:12

1

UriBuilder班有幫助嗎?

它沒有任何方法來添加查詢字符串參數。查看Query屬性來設置值。

編輯:見UriTemplate類。

+0

對於你原來的問題,我沒有找到任何具體的東西你正在尋找。你不需要&加入查詢字符串參數嗎? – shahkalpesh 2009-05-26 01:12:48

+0

看起來這是微軟(半心半意的)試圖實現Shimmy所要求的功能,它只是缺乏可用性。 – Abacus 2013-10-03 19:40:17

1

我開發我自己的,這是比較適合我的需要,感謝您的代碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Collections.Specialized; 

namespace Utils 
{ 
    public class ParameterCollectionBuilder : NameValueCollection 
    { 
     #region NameValueCollection Implementation 
     public ParameterCollectionBuilder() : base() { } 
     public ParameterCollectionBuilder(string uri) 
     { 
      Init(uri); 
     } 
     public ParameterCollectionBuilder(Uri uri) : this(uri.OriginalString) { } 
     public ParameterCollectionBuilder(NameValueCollection baseCollection) 
     { 
      foreach (string key in baseCollection.Keys) this[key] = baseCollection[key]; 
      Init(ToString()); 
     } 
     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="baseCollection"></param> 
     /// <param name="uri"></param> 
     /// <remarks>Note: any existing params in the uri will override the params in the collection.</remarks> 
     public ParameterCollectionBuilder(NameValueCollection baseCollection, string uri) 
     { 
      foreach (string key in baseCollection.Keys) this[key] = baseCollection[key]; 
      Init(uri); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="baseCollection"></param> 
     /// <param name="uri"></param> 
     /// <remarks>Note: any existing params in the uri will override the params in the collection.</remarks> 
     public ParameterCollectionBuilder(NameValueCollection baseCollection, Uri uri) : this(baseCollection, uri.OriginalString) { } 

     public override string ToString() 
     { 
      return Prefix + Query + Suffix; 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="name"></param> 
     /// <param name="value"></param> 
     /// <remarks>Overides existing values.</remarks> 
     public new void Add(string name, object value) 
     { 
      Set(name, GetString(value)); 
     } 

     /// <summary> 
     /// Add an array of key-value pairs separated by colon char ':'. 
     /// </summary> 
     /// <param name="names">Invalid items will be ignored.</param> 
     public void AddRange(string[] names) 
     { 
      rangeFlag = true; 
      for (int i = 0; i < names.Length; i++) 
      { 
       string item = names[i]; 
       item = item.Replace("?", ""); 
       item = item.Replace("&", ""); 
       item = item.Replace("=", ":"); 
       string[] pair = item.Split(':'); 
       if (pair.Length == 2) Set(pair[0], pair[1]);     
      } 
      InitUri(FullString); 
      rangeFlag = false; 
     } 

     public void AppendQueryString(string query) 
     { 
      Add(BuildCollection(query)); 
     } 

     public void RemoveRange(string[] keys) 
     { 
      rangeFlag = true; 
      foreach (string key in keys) 
      { 
       Remove(key); 
      } 
      InitUri(FullString); 
      rangeFlag = false; 
     } 


     bool rangeFlag = false; 
     public new void Set(string name, object value) 
     { 
      base.Set(name, GetString(value)); 
      if (!rangeFlag && Uri != null) InitUri(FullString); 
     } 

     public override void Remove(string name) 
     { 
      base.Remove(name); 
      if (!rangeFlag && Uri != null) InitUri(FullString); 
     } 

     public override void Clear() 
     { 
      base.Clear(); 
      if (Uri != null) InitUri(FullString); 
     } 

     #endregion NameValueCollection Implementation 

     static string ParseQuery(string uri) 
     { 
      string query = ""; 

      if (!uri.Contains('=')) return query; 

      int 
       start = 0, 
       end = uri.Length; 

      if (uri.Contains('?')) start = uri.IndexOf('?'); 
      if (uri.Contains(':')) end = uri.LastIndexOf(':'); 

      query = uri.Substring(start, (start < end ? end : uri.Length) - start); 
      return query; 
     } 

     void Init(string uri) 
     { 
      if (Uri == null) 
      { 
       InitUri(uri); 
      } 
      OriginalQuery = ParseQuery(uri); 
      int qIndex = string.IsNullOrEmpty(OriginalQuery) ? uri.Length : uri.IndexOf(OriginalQuery); 
      Prefix = uri.Substring(0, qIndex); 
      Suffix = uri.Substring(qIndex + OriginalQuery.Length); 
      Merge(OriginalQuery); 
     } 

     void Merge(string query) 
     { 
      NameValueCollection col = BuildCollection(query); 
      foreach (string key in col.Keys) 
      { 
       string value = col[key]; 
       if (!string.IsNullOrEmpty(value)) this[key] = value; 
      } 
     } 
     void InitUri(string uri) 
     { 
      try 
      { 
       Uri = new Uri(uri); 
      } 
      catch { } 
     } 

     static string GetString(object value) 
     { 
      return value is string ? value as string : value.ToString(); 
     } 

     static NameValueCollection BuildCollection(string query) 
     { 
      NameValueCollection collection = new NameValueCollection(); 
      if (string.IsNullOrEmpty(query) || !query.Contains('=')) return new NameValueCollection(); 

      //Prepare string 
      query = query.ToLower(); 
      if (!query.StartsWith("?")) 
      { 
       if (query.Contains('?')) query = query.Substring(query.IndexOf('?')); 
      } 
      query = query.Replace("?", ""); 

      foreach (string pair in query.Split('&')) 
      { 
       string[] separated = pair.Split('='); 
       if (separated.Length == 2) collection[separated[0]] = separated[1]; 
      } 

      return collection; 
     } 

     static string BuildQuery(NameValueCollection parameters) 
     { 
      string query = ""; 
      Char separator = '?'; 
      bool first = true; 
      foreach (string key in parameters.Keys) 
      { 
       query += string.Format("{0}{1}={2}", separator, key, parameters[key]); 
       if (first) 
       { 
        first = false; 
        separator = '&'; 
       } 
      } 
      return query; 
     } 

     #region Properties 
     public Uri Uri { get; private set; } 

     public string Prefix { get; private set; } 
     public string OriginalQuery { get; private set; } 
     public string Suffix { get; private set; } 
     public string OriginalString 
     { 
      get 
      { 
       return Prefix + OriginalQuery + Suffix; 
      } 
     } 
     public string Query 
     { 
      get 
      { 
       return BuildQuery(this); 
      } 
     } 
     public string FullString 
     { 
      get 
      { 
       return ToString(); 
      } 
     } 
     #endregion Properties 
    } 
} 
1

我建議你看一看 CodeProject上的文章。

作者已經擴展了System.UriBuilder類,並添加了一個QueryString屬性,其行爲方式與HttpRequest.QueryString屬性非常相似。

使用這個類的例子將成爲:

UrlBuilder ub = new UrlBuilder("http://www.google.com/search"); 
ub.QueryString.Add("q", "request"); 
ub.QueryString.Add("sourceid", "ie8"); 
string uri = ub.ToString(); //http://www.google.com/search?q=request&sourceid=ie8 

它沒有一個像fluent interfaceJosh's solution可以很容易地擴展到包括一個。

0

隨着Flurl [披露:我是作者],你的榜樣應該是這樣的:

string uri = "http://www.google.com/search" 
    .SetQueryParams(new { q = "request", sourceid = "ie8" }); 

基本URL生成器通過的NuGet可:

PM> Install-Package Flurl

還有擴展Flurl的新伴侶庫,使用fluent,testable HTTP:

PM> Install-Package Flurl.Http