Last active
March 9, 2024 19:33
-
-
Save safakgur/10b8f8c4b3cf944968741b532b5e3c45 to your computer and use it in GitHub Desktop.
A URI extension to set query strings using anonymous objects.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Collections.Specialized; | |
using System.Globalization; | |
using System.Linq; | |
using System.Reflection; | |
using System.Web; | |
public static class UriHelpers | |
{ | |
/// <summary>Returns a new URI with a query set to the specified values.</summary> | |
/// <param name="uri">The URI.</param> | |
/// <param name="values"> | |
/// The query values, which can be one of: | |
/// <list type="bullet"> | |
/// <item> | |
/// <see cref="IEnumerable{T}" /> of | |
/// <see cref="string" />/<see cref="string" /> or | |
/// <see cref="string" />/<see cref="object" />. | |
/// </item> | |
/// <item><see cref="NameValueCollection" /></item> | |
/// <item><see cref="IDictionary" /></item> | |
/// <item><see cref="object" />, whose property names and values will be used.</item> | |
/// </list> | |
/// </param> | |
/// <returns>A new URI with the specified query values.</returns> | |
/// <exception cref="ArgumentNullException"> | |
/// <paramref name="uri" /> is null. | |
/// </exception> | |
/// <remarks> | |
/// This method removes the existing query of the URI and adds the specified values ordered | |
/// by key - performing a stable sort, that is, if two keys are identical, the original | |
/// order of values are preserved. | |
/// </remarks> | |
public static Uri WithQuery(this Uri uri, object? values) | |
{ | |
ArgumentNullException.ThrowIfNull(uri); | |
if (values is null) | |
return uri; | |
var query = string.Join( | |
"&", from p in GetQueryValues() | |
where !string.IsNullOrWhiteSpace(p.Key) | |
let k = HttpUtility.UrlEncode(p.Key.Trim()) | |
let v = HttpUtility.UrlEncode(p.Value) | |
orderby k | |
select string.IsNullOrEmpty(v) ? k : $"{k}={v}"); | |
if (query.Length != 0 || uri.Query.Length != 0) | |
uri = new UriBuilder(uri) { Query = query }.Uri; | |
return uri; | |
IEnumerable<KeyValuePair<string, string>> GetQueryValues() | |
{ | |
if (values is NameValueCollection nvc) | |
return from key in nvc.AllKeys | |
from val in nvc.GetValues(key) ?? [] | |
select KeyValuePair.Create(key, val); | |
if (values is IEnumerable<KeyValuePair<string, string>> ssd) | |
return ssd; | |
if (values is not IEnumerable<KeyValuePair<string, object>> sod) | |
sod = values is IDictionary ngd | |
? ngd.Cast<dynamic>().ToDictionary<dynamic, string, object>( | |
p => ToString(p.Key), | |
p => p.Value) | |
: from p in values.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) | |
let v = p.GetValue(values) | |
select KeyValuePair.Create(p.Name, v); | |
return from pair in sod | |
from val in pair.Value as IEnumerable<string?> ?? [ToString(pair.Value)] | |
select KeyValuePair.Create(pair.Key, val); | |
} | |
static string ToString(object value) => | |
string.Create(CultureInfo.InvariantCulture, $"{value}"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment