2009-05-26 98 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