8

我想实现以下目标:

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 中是否有任何内容,或者我必须自己创建?

4

5 回答 5

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;
        }
    }
}
于 2009-05-26T01:22:37.657 回答
1

UriBuilder类帮助吗?

它没有任何添加查询字符串参数的方法。查看 Query 属性以设置值。

编辑:见UriTemplate类。

于 2009-05-26T01:05:51.840 回答
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
    }
}
于 2009-05-26T06:39:25.360 回答
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

它没有像Josh 的解决方案那样流畅的界面,但可以轻松扩展以包含一个。

于 2009-07-04T09:50:19.720 回答
0

使用Flurl [披露:我是作者],您的示例将如下所示:

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

基本 URL 构建器可通过 NuGet 获得:

PM> Install-Package Flurl

还有一个新的配套库,它使用流畅可测试的HTTP 扩展 Flurl:

PM> Install-Package Flurl.Http

于 2014-02-21T16:49:25.940 回答