public static string BuildUrl(string[] parts, IDictionary <string, object> query, string fragment) { var sb = new StringBuilder(); if (!ArrayUtils.IsNullOrEmpty(parts)) { var part = parts[0]; var delimiter = !string.IsNullOrEmpty(part) && part[0] == '/' ? "/" : null; for (int i = 0, n = parts.Length; i < n; i++) { sb.Append(delimiter); part = parts[i]; if (!string.IsNullOrEmpty(part)) { var endIndex = part.Length - 1; if (part[0] == '/') { sb.Append(part, 1, endIndex); } else { sb.Append(part); } delimiter = endIndex > 0 && part[endIndex] != '/' ? "/" : null; } else { delimiter = null; } } } if (query != null) { var separator = '?'; foreach (KeyValuePair <string, object> queryPart in query) { foreach (var value in queryPart.Value is string || !(queryPart.Value is IEnumerable enumerable) ? EnumerableUtils.Return(queryPart.Value) : enumerable.Cast <object>()) { sb.Append(separator); separator = '&'; sb.Append(queryPart.Key); sb.Append('='); sb.Append(value != null ? Uri.EscapeDataString(value.ToString()) : string.Empty); } } } if (!string.IsNullOrEmpty(fragment)) { sb.Append('#'); sb.Append(Uri.EscapeDataString(fragment)); } return(sb.ToString()); }