namespace CommonConsole { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web; public class Program { public static void Main() { var uri = new URIHelper("/CSR?key=asdasdasd") .AddQuery(new { A = 123, B = "asd" }); Console.WriteLine(uri); } } public class URIHelper { private readonly string path; private readonly IDictionary query; public URIHelper(string value) { this.query = new Dictionary(); this.path = this.ParsePathAndQuery(value); } public URIHelper AddQuery(object query) { if (query != null) { if (query is string queryString) { var queryTokens = queryString.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries); foreach (var token in queryTokens) { var kvpTokens = token.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries); if (kvpTokens.Length == 2) { this.query[kvpTokens[0]] = kvpTokens[1]; } } } else if (query is IDictionary parameters) { foreach (var kvp in parameters) { this.query[kvp.Key] = kvp.Value; } } else { var properties = query .GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in properties) { var key = property.Name.ToLower(); var value = property.GetValue(query); this.query[key] = HttpUtility.UrlEncode($"{value}"); } } } return this; } public override string ToString() => $"{this.path}?{string.Join("&", this.query.Select(x => $"{x.Key}={x.Value}"))}"; private string ParsePathAndQuery(String value) { if (string.IsNullOrWhiteSpace(value)) { return "/"; } var routeTokens = value.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries); if (routeTokens.Length >= 2) { var queryTokens = routeTokens[1].Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries); foreach (var token in queryTokens) { var kvpTokens = token.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries); if (kvpTokens.Length == 2) { this.query[kvpTokens[0]] = kvpTokens[1]; } } } if (routeTokens.Length >= 1) { return routeTokens[0]; } return "/"; } } }