using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Web; namespace ZeroLevel.Services.Web { public class UrlBuilder { private readonly Func _serializer; public UrlBuilder(Func serializer) { _serializer = serializer; } public Uri BuildRequestUrlFromDTO(string baseUri, string resource, T instance) { if (null == instance) { return BuildRequestUrl(baseUri, resource, null!); } var members = typeof(T).GetMembers( BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance); var parameters = new Dictionary(); foreach (var member in members) { switch (member.MemberType) { case MemberTypes.Property: parameters.Add(member.Name.ToLowerInvariant(), (member as PropertyInfo)!.GetValue(instance)); break; case MemberTypes.Field: parameters.Add(member.Name.ToLowerInvariant(), (member as FieldInfo)!.GetValue(instance)); break; default: continue; } } return BuildRequestUrl(baseUri, resource, parameters); } public Uri BuildRequestUrl(string baseUri, string resource, IDictionary parameters) { if (null == resource) throw new ArgumentNullException("resource"); var stringBuilder = new StringBuilder(baseUri); if (baseUri[baseUri.Length - 1] != '/') stringBuilder.Append('/'); if (resource[0] != '/') { stringBuilder.Append(resource); } else { stringBuilder.Append(resource.Substring(1)); } if (parameters != null && parameters.Count > 0) { stringBuilder.Append("?"); foreach (var pair in parameters) { if (pair.Value == null) { stringBuilder.Append(pair.Value); } else { var vtype = pair.Value.GetType(); if (vtype.IsArray) { if (vtype.GetElementType() == typeof(string)) { var arr = (string[])pair.Value; stringBuilder.Append(string.Join("&", arr.Select(i => $"{HttpUtility.UrlEncode(pair.Key)}[]={HttpUtility.UrlEncode(i)}"))); } else { var arr = (object[])pair.Value; stringBuilder.Append(string.Join("&", arr.Select(i => $"{HttpUtility.UrlEncode(pair.Key)}[]={HttpUtility.UrlEncode(_serializer(i))}"))); } } else { if (vtype == typeof(string)) { stringBuilder.Append($"{HttpUtility.UrlEncode(pair.Key)}={HttpUtility.UrlEncode((string)pair.Value)}"); } else { stringBuilder.Append($"{HttpUtility.UrlEncode(pair.Key)}={HttpUtility.UrlEncode(_serializer(pair.Value))}"); } } } stringBuilder.Append("&"); } } return new Uri(stringBuilder.ToString().TrimEnd('&')); } } }