2009-05-26 11 views
8

tôi muốn đạt được một cái gì đó như sau:Có trình tạo URL hỗ trợ nối tham số yêu cầu không?

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 

Có điều gì trong .NET, hoặc tôi sẽ phải tạo của riêng tôi?

Trả lời

11

Không có gì tồn tại mà tôi biết. Đây là một cái gì đó đơn giản mà làm những gì bạn muốn. Cách sử dụng sẽ là:

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

     string url=ub.ToString(); 

==

Mã là:

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 cho nỗ lực. Bạn cũng có thể làm cho AddQuery một phương thức của lớp Uri hoặc UriBuilder (hiện có trong khung công tác) - chỉ là một gợi ý. – shahkalpesh

+0

Yep cũng sẽ hoạt động, tôi đã thực sự nghĩ rằng điều này sẽ bao trùm UriBuilder, nhưng không có lý do cụ thể nào tôi đi theo cách tiếp cận này – JoshBerke

+0

Josh, tôi thực sự đánh giá cao nỗ lực của bạn. Tôi chắc chắn sẽ sử dụng nó một lần. Thời gian cụ thể này tôi tìm thấy mã tôi đăng dưới đây thuận tiện hơn với nhu cầu của tôi. Cảm ơn rất nhiều! – Shimmy

1

Trợ giúp lớp học UriBuilder có giúp ích không?

Nó không có bất kỳ phương pháp nào để thêm thông số chuỗi truy vấn. Hãy xem thuộc tính Truy vấn để đặt giá trị.

EDIT: Xem UriTemplate lớp học.

+0

Đối với câu hỏi ban đầu của bạn, tôi không tìm thấy bất kỳ điều gì cụ thể cho bạn đang tìm kiếm. Bạn không cần một & để tham gia các tham số chuỗi truy vấn? – shahkalpesh

+0

Có vẻ như đây là nỗ lực của Microsoft (nửa vời) để thực hiện chức năng mà Shimmy đang yêu cầu, nó chỉ rơi vào tình trạng thiếu khả năng sử dụng. – Abacus

1

tôi phát triển của riêng tôi, đó là phù hợp hơn cho nhu cầu của tôi, cảm ơn vì mã của bạn:

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

Tôi sẽ khuyên bạn hãy xem this bài viết trên CodeProject.

Tác giả đã mở rộng lớp System.UriBuilder và thêm thuộc tính QueryString hoạt động theo cùng cách với thuộc tính HttpRequest.QueryString.

Sử dụng lớp này ví dụ của bạn sẽ trở thành:

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 

Nó không có một fluent interface như Josh's solution nhưng có thể dễ dàng mở rộng để bao gồm một.

+1

Mã trong bài viết đó không phải là tuyệt vời. Nó không làm bất kỳ mã hóa/giải mã các giá trị chuỗi truy vấn. Vì vậy, bạn đang bị ràng buộc để chạy vào rắc rối với nó. –

0

Với Flurl [tiết lộ: Tôi là tác giả], ví dụ của bạn sẽ trông như thế này:

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

Trình tạo URL cơ bản có sẵn qua NuGet:

PM> Install-Package Flurl

Ngoài ra còn có một lib đồng hành mới mở rộng Flurl với fluent, testable HTTP:

PM> Install-Package Flurl.Http