/// <summary>
        /// Set query string params to the Uri. e.g. .?page=1&amp;filter=all'.
        /// </summary>
        /// <param name="queryParams">Query data to add/append. Can be either dictionary or object.</param>
        /// <param name="options">Query string options to use.</param>
        /// <returns>Returns request builder for chaining.</returns>
        public FluentHttpRequestBuilder WithQueryParams(object queryParams, QueryStringOptions options = null)
        {
            options = options ?? _queryStringOptions;

            _queryParams = queryParams;
            return(WithQueryParamsOptions(options));
        }
		/// <summary>
		/// Convert dictionary to querystring.
		/// </summary>
		/// <param name="dict">Dictionary</param>
		/// <param name="configure">Configuration function.</param>
		/// <returns>Returns querystring.</returns>
		public static string ToQueryString<TKey, TValue>(this IDictionary<TKey, TValue> dict, Action<QueryStringOptions> configure)
		{
			if (configure == null) throw new ArgumentNullException(nameof(configure));
			var opts = new QueryStringOptions();
			configure(opts);
			return dict.ToQueryString(opts);
		}
        /// <summary>
        /// Set query string params options.
        /// </summary>
        /// <param name="configure">Function to configure query string options.</param>
        /// <returns>Returns request builder for chaining.</returns>
        public FluentHttpRequestBuilder WithQueryParamsOptions(Action <QueryStringOptions> configure)
        {
            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }
            var options = new QueryStringOptions();

            configure(options);
            return(WithQueryParamsOptions(options));
        }
        private static string BuildUri(string uri, object queryParams, QueryStringOptions options)
        {
            var queryString = BuildQueryString(queryParams, options);

            if (string.IsNullOrEmpty(queryString))
            {
                return(uri);
            }

            if (uri.Contains("?"))
            {
                uri += $"&{queryString}";
            }
            else
            {
                uri += $"?{queryString}";
            }
            return(uri);
        }
        private static string BuildQueryString(object queryParams, QueryStringOptions options)
        {
            if (queryParams == null)
            {
                return(string.Empty);
            }

            var dict = queryParams.ToDictionary();

            if (dict.Count == 0)
            {
                return(string.Empty);
            }

            var queryCollection = new Dictionary <string, object>();

            foreach (var item in dict)
            {
                queryCollection[item.Key] = item.Value;
            }

            return(queryCollection.ToQueryString(options));
        }
        private static string BuildCollectionQueryString(string key, IEnumerable values, string qs, QueryStringOptions options)
        {
            switch (options.CollectionMode)
            {
            case QueryStringCollectionMode.KeyPerValue:
                foreach (var value in values)
                {
                    var valueStr = options.CollectionItemFormatter != null
                            ? options.CollectionItemFormatter(value)
                            : value.ToString();

                    qs = AddQueryString(key, valueStr, qs);
                }
                break;

            case QueryStringCollectionMode.CommaSeparated:
                var index = 0;
                foreach (var value in values)
                {
                    var valueStr = options.CollectionItemFormatter != null
                            ? options.CollectionItemFormatter(value)
                            : value.ToString();

                    if (index == 0)
                    {
                        qs = AddQueryString(key, valueStr, qs);
                    }
                    else
                    {
                        qs += $",{HttpUtility.UrlEncode(valueStr)}";
                    }

                    index++;
                }

                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(options), options.CollectionMode, $"Value provided {options.CollectionMode} is not supported.");
            }

            return(qs);
        }
        /// <summary>
        /// Convert dictionary to querystring.
        /// </summary>
        /// <param name="dict">Dictionary</param>
        /// <param name="options">Formatting options.</param>
        /// <returns>Returns querystring.</returns>
        public static string ToQueryString <TKey, TValue>(this IDictionary <TKey, TValue> dict, QueryStringOptions options = null)
        {
            options = options ?? DefaultQueryStringOptions;

            if (dict == null || dict.Count == 0)
            {
                return(string.Empty);
            }

            var qs = string.Empty;

            foreach (var item in dict)
            {
                if (item.Value == null)
                {
                    continue;
                }

                var key = options.KeyFormatter != null
                    ? options.KeyFormatter(item.Key.ToString())
                    : item.Key.ToString();

                if (item.Value is string)
                {
                    qs = AddQueryString(key, item.Value.ToString(), qs);
                    continue;
                }

                switch (item.Value)
                {
                case IEnumerable values:

                    qs = BuildCollectionQueryString(key, values, qs, options);
                    break;

                default:
                    qs = AddQueryString(key, item.Value.ToString(), qs);
                    break;
                }
            }

            return(qs);
        }
 /// <summary>
 /// Set query string params options.
 /// </summary>
 /// <param name="options">Query string options to use.</param>
 /// <returns>Returns request builder for chaining.</returns>
 public FluentHttpRequestBuilder WithQueryParamsOptions(QueryStringOptions options)
 {
     _queryStringOptions = options;
     return(this);
 }