Существует ли конструктор URL, который также поддерживает конкатенацию параметров запроса? - PullRequest
8 голосов
/ 26 мая 2009

Я хочу добиться чего-то вроде следующего:

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, или мне придется создавать свое собственное?

Ответы [ 5 ]

11 голосов
/ 26 мая 2009

Ничего не существует, о чем я знаю. Вот что-то простое, что делает то, что вы хотите. Использование будет:

        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;
        }
    }
}
1 голос
/ 04 июля 2009

Я бы порекомендовал вам взглянуть на эту статью о 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

У него нет свободного интерфейса , как у решения Джоша , но его можно легко расширить, включив один.

1 голос
/ 26 мая 2009

Я разработал свой, это больше подходит для моих нужд, спасибо за ваш код:

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 голос
/ 26 мая 2009

Помогает ли класс UriBuilder ?

У него нет способа добавить параметры строки запроса. Посмотрите на свойство Query для установки значений.

РЕДАКТИРОВАТЬ: См. UriTemplate класс.

0 голосов
/ 21 февраля 2014

С Flurl [раскрытие: я автор], ваш пример будет выглядеть так:

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

Базовый конструктор URL доступен через NuGet:

PM> Install-Package Flurl

Существует также новая библиотека-компаньон, которая расширяет Flurl с помощью свободно , тестируемый HTTP:

PM> Install-Package Flurl.Http

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...