diff --git a/Directory.Build.targets b/Directory.Build.targets
index fe5cadfe..ba23bad2 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -100,6 +100,8 @@
$(DefineConstants);SUPPORTS_CERTIFICATE_LOADER
+ $(DefineConstants);SUPPORTS_JSON_ELEMENT_DEEP_EQUALS
+ $(DefineConstants);SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT
/// The identity.
/// The destinations, returned as a flattened dictionary.
- public static ImmutableDictionary GetDestinations(this ClaimsIdentity identity)
+ public static ImmutableDictionary> GetDestinations(this ClaimsIdentity identity)
{
if (identity is null)
{
throw new ArgumentNullException(nameof(identity));
}
- var builder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal);
+ var builder = ImmutableDictionary.CreateBuilder>(StringComparer.Ordinal);
foreach (var group in identity.Claims.GroupBy(claim => claim.Type))
{
@@ -676,14 +676,14 @@ public static class OpenIddictExtensions
///
/// The principal.
/// The destinations, returned as a flattened dictionary.
- public static ImmutableDictionary GetDestinations(this ClaimsPrincipal principal)
+ public static ImmutableDictionary> GetDestinations(this ClaimsPrincipal principal)
{
if (principal is null)
{
throw new ArgumentNullException(nameof(principal));
}
- var builder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal);
+ var builder = ImmutableDictionary.CreateBuilder>(StringComparer.Ordinal);
foreach (var group in principal.Claims.GroupBy(claim => claim.Type))
{
@@ -714,7 +714,8 @@ public static class OpenIddictExtensions
/// The identity.
/// The destinations, as a flattened dictionary.
/// The identity.
- public static ClaimsIdentity SetDestinations(this ClaimsIdentity identity, ImmutableDictionary destinations)
+ public static ClaimsIdentity SetDestinations(this ClaimsIdentity identity,
+ ImmutableDictionary> destinations)
{
if (identity is null)
{
@@ -743,7 +744,8 @@ public static class OpenIddictExtensions
/// The principal.
/// The destinations, as a flattened dictionary.
/// The principal.
- public static ClaimsPrincipal SetDestinations(this ClaimsPrincipal principal, ImmutableDictionary destinations)
+ public static ClaimsPrincipal SetDestinations(this ClaimsPrincipal principal,
+ ImmutableDictionary> destinations)
{
if (principal is null)
{
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
index f0fa2dfc..4dff1439 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
@@ -4,9 +4,11 @@
* the license and the contributors participating to this project.
*/
+using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
@@ -141,17 +143,15 @@ public class OpenIddictMessage
continue;
}
- var values = parameter.Select(parameter => parameter.Value).ToArray();
-
// Note: the core OAuth 2.0 specification requires that request parameters
// not be present more than once but derived specifications like the
// token exchange specification deliberately allow specifying multiple
// parameters with the same name to represent a multi-valued parameter.
- AddParameter(parameter.Key, values.Length switch
+ AddParameter(parameter.Key, parameter.Select(parameter => parameter.Value).ToArray() switch
{
- 0 => default,
- 1 => values[0],
- _ => values
+ [] => default,
+ [string value] => new OpenIddictParameter(value),
+ [..] values => new(ImmutableCollectionsMarshal.AsImmutableArray(values))
});
}
}
@@ -161,7 +161,7 @@ public class OpenIddictMessage
///
/// The message parameters.
/// Parameters with a null or empty key are always ignored.
- public OpenIddictMessage(IEnumerable> parameters)
+ public OpenIddictMessage(IEnumerable?>> parameters)
{
if (parameters is null)
{
@@ -180,11 +180,11 @@ public class OpenIddictMessage
// not be present more than once but derived specifications like the
// token exchange specification deliberately allow specifying multiple
// parameters with the same name to represent a multi-valued parameter.
- AddParameter(parameter.Key, parameter.Value?.Length switch
+ AddParameter(parameter.Key, parameter.Value switch
{
- null or 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value
+ null or [] => default,
+ [string value] => new OpenIddictParameter(value),
+ [..] values => new OpenIddictParameter(values)
});
}
}
@@ -213,11 +213,11 @@ public class OpenIddictMessage
// not be present more than once but derived specifications like the
// token exchange specification deliberately allow specifying multiple
// parameters with the same name to represent a multi-valued parameter.
- AddParameter(parameter.Key, parameter.Value.Count switch
+ AddParameter(parameter.Key, parameter.Value switch
{
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
+ [] => default,
+ [string value] => new OpenIddictParameter(value),
+ [..] values => new(ImmutableCollectionsMarshal.AsImmutableArray(values.ToArray()))
});
}
}
@@ -243,17 +243,15 @@ public class OpenIddictMessage
continue;
}
- var values = parameters.GetValues(name);
-
// Note: the core OAuth 2.0 specification requires that request parameters
// not be present more than once but derived specifications like the
// token exchange specification deliberately allow specifying multiple
// parameters with the same name to represent a multi-valued parameter.
- AddParameter(name, values?.Length switch
+ AddParameter(name, parameters.GetValues(name) switch
{
- null or 0 => default,
- 1 => values[0],
- _ => values
+ null or [] => default,
+ [string value] => new OpenIddictParameter(value),
+ [..] values => new(ImmutableCollectionsMarshal.AsImmutableArray(values))
});
}
}
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
index 5c27e9d3..7825b108 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
@@ -8,64 +8,88 @@ using System.Collections.Immutable;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Nodes;
+using Microsoft.Extensions.Primitives;
namespace OpenIddict.Abstractions;
///
-/// Represents an OpenIddict parameter value, that can be either a primitive value,
-/// an array of strings or a complex JSON representation containing child nodes.
+/// Represents an OpenIddict parameter value and provides two-way conversion operators that allow
+/// representing it as a primitive value, an immutable array of strings or a JSON element or node.
///
public readonly struct OpenIddictParameter : IEquatable
{
+ private readonly object? _value;
+
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(bool value) => Value = value;
+ public OpenIddictParameter(bool value) => _value = value;
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(bool? value) => Value = value;
+ public OpenIddictParameter(bool? value) => _value = value;
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(JsonElement value) => Value = value;
+ public OpenIddictParameter(JsonElement value) => _value = value;
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(JsonNode? value) => Value = value;
+ public OpenIddictParameter(JsonNode? value) => _value = value switch
+ {
+ // Clone the node to ensure the stored value cannot be mutated.
+ JsonNode node => node.DeepClone(),
+
+ null => null
+ };
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(long value) => Value = value;
+ public OpenIddictParameter(long value) => _value = value;
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(long? value) => Value = value;
+ public OpenIddictParameter(long? value) => _value = value;
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(string? value) => Value = value;
+ public OpenIddictParameter(string? value) => _value = value;
///
/// Initializes a new parameter using the specified value.
///
/// The parameter value.
- public OpenIddictParameter(string?[]? value) => Value = value;
+ public OpenIddictParameter(ImmutableArray value)
+ // Note: to avoid boxing, the underlying array is directly stored as the backing value.
+ => _value = ImmutableCollectionsMarshal.AsArray(value);
+
+ ///
+ /// Initializes a new parameter using the specified value.
+ ///
+ /// The parameter value.
+ public OpenIddictParameter(ImmutableArray? value) => _value = value switch
+ {
+ // Note: to avoid boxing, the underlying array is directly stored as the backing value.
+ ImmutableArray array => ImmutableCollectionsMarshal.AsArray(array),
+
+ null => null
+ };
///
/// Gets the child item corresponding to the specified index.
@@ -89,9 +113,9 @@ public readonly struct OpenIddictParameter : IEquatable
{
get
{
- return Value switch
+ return _value switch
{
- // If the parameter is a primitive array of strings, return its length.
+ // If the parameter is an array of strings, return its length.
string?[] value => value.Length,
// If the parameter is a JSON array or a JSON object, return its length.
@@ -135,6 +159,9 @@ public readonly struct OpenIddictParameter : IEquatable
return element.GetArrayLength();
case JsonValueKind.Object:
+#if SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT
+ return element.GetPropertyCount();
+#else
var count = 0;
using (var enumerator = element.EnumerateObject())
@@ -149,6 +176,7 @@ public readonly struct OpenIddictParameter : IEquatable
}
return count;
+#endif
default: return 0;
}
@@ -157,11 +185,20 @@ public readonly struct OpenIddictParameter : IEquatable
}
///
- /// Gets the associated value, that can be either a primitive CLR type
- /// (e.g bool, string, long), an array of strings or a complex JSON object.
+ /// Gets the associated raw value, that can be either a primitive CLR type
+ /// (e.g bool, string, long), an immutable array of strings or a complex JSON object.
///
- [EditorBrowsable(EditorBrowsableState.Advanced)]
- public object? Value { get; }
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public object? GetRawValue() => _value switch
+ {
+ // If the value is backed by an array of strings or a JSON node, return a copy instead of the
+ // real instance to ensure mutations made on the returned object don't affect the stored array.
+ string?[] array => ImmutableArray.Create(array),
+ JsonNode node => node.DeepClone(),
+
+ object value => value,
+ null => null
+ };
///
/// Determines whether the current
@@ -174,7 +211,7 @@ public readonly struct OpenIddictParameter : IEquatable
///
public bool Equals(OpenIddictParameter other)
{
- return (left: Value, right: other.Value) switch
+ return (_value, other._value) switch
{
// If the two parameters reference the same instance, return true.
//
@@ -207,6 +244,9 @@ public readonly struct OpenIddictParameter : IEquatable
// If the two parameters are JsonElement instances, use the custom comparer.
(JsonElement left, JsonElement right) => DeepEquals(left, right),
+ // If the two parameters are JsonNode instances, use JsonNode.DeepEquals().
+ (JsonNode left, JsonNode right) => JsonNode.DeepEquals(left, right),
+
// When one of the parameters is a JsonElement, compare their underlying values.
(JsonElement { ValueKind: JsonValueKind.True }, bool right) => right,
(bool left, JsonElement { ValueKind: JsonValueKind.True }) => left,
@@ -252,8 +292,9 @@ public readonly struct OpenIddictParameter : IEquatable
static bool DeepEquals(JsonElement left, JsonElement right)
{
+#if !SUPPORTS_JSON_ELEMENT_DEEP_EQUALS
RuntimeHelpers.EnsureSufficientExecutionStack();
-
+#endif
switch ((left.ValueKind, right.ValueKind))
{
case (JsonValueKind.Undefined, JsonValueKind.Undefined):
@@ -267,6 +308,9 @@ public readonly struct OpenIddictParameter : IEquatable
case (JsonValueKind.Null, JsonValueKind.Undefined):
return true;
+#if SUPPORTS_JSON_ELEMENT_DEEP_EQUALS
+ default: return JsonElement.DeepEquals(left, right);
+#else
case (JsonValueKind.Number, JsonValueKind.Number):
return string.Equals(left.GetRawText(), right.GetRawText(), StringComparison.Ordinal);
@@ -312,6 +356,7 @@ public readonly struct OpenIddictParameter : IEquatable
}
default: return false;
+#endif
}
}
}
@@ -333,7 +378,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// The hash code for the current instance.
public override int GetHashCode()
{
- return Value switch
+ return _value switch
{
// When the parameter value is null, return 0.
null => 0,
@@ -460,7 +505,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// A dictionary of all the parameters associated with the current instance.
public IReadOnlyDictionary GetNamedParameters()
{
- return Value switch
+ return _value switch
{
// When the parameter is a JsonElement representing an object, return the requested item.
JsonElement { ValueKind: JsonValueKind.Object } value => GetParametersFromJsonElement(value),
@@ -510,7 +555,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// An enumeration of all the unnamed parameters associated with the current instance.
public IReadOnlyList GetUnnamedParameters()
{
- return Value switch
+ return _value switch
{
// When the parameter is an array of strings, return its items.
string?[] value => GetParametersFromArray(value),
@@ -573,7 +618,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// Returns the representation of the current instance.
///
/// The representation associated with the parameter value.
- public override string? ToString() => Value switch
+ public override string? ToString() => _value switch
{
null => string.Empty,
@@ -633,7 +678,7 @@ public readonly struct OpenIddictParameter : IEquatable
throw new ArgumentException(SR.GetResourceString(SR.ID0192), nameof(name));
}
- var result = Value switch
+ var result = _value switch
{
// When the parameter is a JsonElement representing an array, return the requested item.
JsonElement { ValueKind: JsonValueKind.Object } element =>
@@ -669,7 +714,7 @@ public readonly struct OpenIddictParameter : IEquatable
throw new ArgumentOutOfRangeException(nameof(index), SR.GetResourceString(SR.ID0193));
}
- var result = Value switch
+ var result = _value switch
{
// When the parameter is an array of strings, return the requested item.
string?[] array => index < array.Length ? new(array[index]) : null,
@@ -706,7 +751,7 @@ public readonly struct OpenIddictParameter : IEquatable
throw new ArgumentNullException(nameof(writer));
}
- switch (Value)
+ switch (_value)
{
// Note: undefined JsonElement values are assimilated to null values.
case null:
@@ -778,7 +823,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// The converted value.
public static explicit operator bool?(OpenIddictParameter? parameter)
{
- return parameter?.Value switch
+ return parameter?._value switch
{
// When the parameter is a null value or a JsonElement representing null, return null.
null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
@@ -833,7 +878,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// The converted value.
public static explicit operator JsonElement(OpenIddictParameter? parameter)
{
- return parameter?.Value switch
+ return parameter?._value switch
{
// When the parameter is a null value, return an undefined JsonElement.
null => default,
@@ -876,13 +921,14 @@ public readonly struct OpenIddictParameter : IEquatable
/// The converted value.
public static explicit operator JsonNode?(OpenIddictParameter? parameter)
{
- return parameter?.Value switch
+ return parameter?._value switch
{
// When the parameter is a null value or a JsonElement representing null, return null.
null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
- // When the parameter is already a JsonNode, return it as-is.
- JsonNode value => value,
+ // When the parameter is already a JsonNode, return a clone to ensure mutations
+ // made on the returned object do not affect the instance stored by this structure.
+ JsonNode value => value.DeepClone(),
// When the parameter is a boolean, return a JsonValue.
bool value => JsonValue.Create(value),
@@ -972,7 +1018,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// The converted value.
public static explicit operator long?(OpenIddictParameter? parameter)
{
- return parameter?.Value switch
+ return parameter?._value switch
{
// When the parameter is a null value or a JsonElement representing null, return null.
null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
@@ -1030,7 +1076,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// The converted value.
public static explicit operator string?(OpenIddictParameter? parameter)
{
- return parameter?.Value switch
+ return parameter?._value switch
{
// When the parameter is a null value or a JsonElement representing null, return null.
null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
@@ -1091,19 +1137,145 @@ public readonly struct OpenIddictParameter : IEquatable
}
///
- /// Converts an instance to an array of strings.
+ /// Converts an instance to a instance.
///
/// The parameter to convert.
/// The converted value.
- public static explicit operator string?[]?(OpenIddictParameter? parameter)
+ public static explicit operator StringValues(OpenIddictParameter? parameter)
+ => ((StringValues?) parameter).GetValueOrDefault();
+
+ ///
+ /// Converts an instance to a instance.
+ ///
+ /// The parameter to convert.
+ /// The converted value.
+ public static explicit operator StringValues?(OpenIddictParameter? parameter)
{
- return parameter?.Value switch
+ return parameter?._value switch
+ {
+ // When the parameter is a null value or a JsonElement representing null, return null.
+ null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
+
+ // When the parameter is an array of strings, return a StringValues instance wrapping the cloned array.
+ string?[] value => new StringValues(value.ToArray().ToArray()),
+
+ // When the parameter is a string value, return a StringValues instance with a single entry.
+ string value => new StringValues(value),
+
+ // When the parameter is a boolean value, return a StringValues instance with its string representation.
+ bool value => new StringValues(value ? "true" : "false"),
+
+ // When the parameter is an integer, return a StringValues instance with its string representation.
+ long value => new StringValues(value.ToString(CultureInfo.InvariantCulture)),
+
+ // When the parameter is a JSON boolean value, return a StringValues instance with its string representation.
+ JsonElement { ValueKind: JsonValueKind.True } => new StringValues("true"),
+ JsonElement { ValueKind: JsonValueKind.False } => new StringValues("false"),
+
+ // When the parameter is a JsonElement, try to convert it if it's of a supported type.
+ JsonElement value => ConvertFromJsonElement(value),
+
+ // When the parameter is a JsonValue wrapping a JsonElement,
+ // apply the same logic as with direct JsonElement instances.
+ JsonValue value when value.TryGetValue(out JsonElement element) => ConvertFromJsonElement(element),
+
+ // When the parameter is a JsonValue wrapping a string, return a StringValues instance with a single entry.
+ JsonValue value when value.TryGetValue(out string? result) => new StringValues(result),
+
+ // When the parameter is a JsonValue wrapping a boolean, return a StringValues instance with its string representation.
+ JsonValue value when value.TryGetValue(out bool result)
+ => new StringValues(result ? "true" : "false"),
+
+ // When the parameter is a JsonValue wrapping an integer, return a StringValues instance with its string representation.
+ JsonValue value when value.TryGetValue(out int result)
+ => new StringValues(result.ToString(CultureInfo.InvariantCulture)),
+
+ JsonValue value when value.TryGetValue(out long result)
+ => new StringValues(result.ToString(CultureInfo.InvariantCulture)),
+
+ // When the parameter is a JsonNode (e.g a JsonValue wrapping a non-primitive type),
+ // serialize it to a JsonElement first to determine its actual JSON representation
+ // and apply the same logic as with non-wrapped JsonElement instances.
+ JsonNode value when JsonSerializer.SerializeToElement(value) is JsonElement element
+ => ConvertFromJsonElement(element),
+
+ // If the parameter is of a different type, return null to indicate the conversion failed.
+ _ => null
+ };
+
+ static StringValues? ConvertFromJsonElement(JsonElement element) => element.ValueKind switch
+ {
+ // When the parameter is a JsonElement representing a boolean,
+ // return a StringValues instance with its string representation.
+ JsonValueKind.True => new StringValues("true"),
+ JsonValueKind.False => new StringValues("false"),
+
+ // When the parameter is a JsonElement representing a string or a
+ // number, return a StringValues instance with its string representation.
+ JsonValueKind.String or JsonValueKind.Number => new StringValues(element.ToString()),
+
+ // When the parameter is a JsonElement representing an array, return the elements as strings.
+ JsonValueKind.Array => CreateArrayFromJsonElement(element),
+
+ _ => null
+ };
+
+ static StringValues? CreateArrayFromJsonElement(JsonElement element)
+ {
+ var length = element.GetArrayLength();
+ var array = new string[length];
+
+ for (var index = 0; index < length; index++)
+ {
+ var item = element[index];
+ if (item.ValueKind is JsonValueKind.True)
+ {
+ array[index] = "true";
+ }
+
+ else if (item.ValueKind is JsonValueKind.False)
+ {
+ array[index] = "false";
+ }
+
+ else if (item.ValueKind is JsonValueKind.String or JsonValueKind.Number)
+ {
+ array[index] = item.ToString();
+ }
+
+ // Always return a null array if one of the items is a not string, a number or a boolean.
+ else
+ {
+ return null;
+ }
+ }
+
+ return new StringValues(array);
+ }
+ }
+
+ ///
+ /// Converts an instance to an immutable array of strings.
+ ///
+ /// The parameter to convert.
+ /// The converted value.
+ public static explicit operator ImmutableArray(OpenIddictParameter? parameter)
+ => ((ImmutableArray?) parameter).GetValueOrDefault();
+
+ ///
+ /// Converts an instance to an immutable array of strings.
+ ///
+ /// The parameter to convert.
+ /// The converted value.
+ public static explicit operator ImmutableArray?(OpenIddictParameter? parameter)
+ {
+ return parameter?._value switch
{
// When the parameter is a null value or a JsonElement representing null, return null.
null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
// When the parameter is already an array of strings, return it as-is.
- string?[] value => value,
+ string?[] value => ImmutableCollectionsMarshal.AsImmutableArray(value),
// When the parameter is a string value, return an array with a single entry.
string value => [value],
@@ -1149,7 +1321,7 @@ public readonly struct OpenIddictParameter : IEquatable
_ => null
};
- static string?[]? ConvertFromJsonElement(JsonElement element) => element.ValueKind switch
+ static ImmutableArray? ConvertFromJsonElement(JsonElement element) => element.ValueKind switch
{
// When the parameter is a JsonElement representing a boolean,
// return an 1-item array with its string representation.
@@ -1166,27 +1338,27 @@ public readonly struct OpenIddictParameter : IEquatable
_ => null
};
- static string?[]? CreateArrayFromJsonElement(JsonElement element)
+ static ImmutableArray? CreateArrayFromJsonElement(JsonElement element)
{
var length = element.GetArrayLength();
- var array = new string?[length];
+ var builder = ImmutableArray.CreateBuilder(length);
for (var index = 0; index < length; index++)
{
var item = element[index];
if (item.ValueKind is JsonValueKind.True)
{
- array[index] = "true";
+ builder.Add("true");
}
else if (item.ValueKind is JsonValueKind.False)
{
- array[index] = "false";
+ builder.Add("false");
}
else if (item.ValueKind is JsonValueKind.String or JsonValueKind.Number)
{
- array[index] = item.ToString();
+ builder.Add(item.ToString());
}
// Always return a null array if one of the items is a not string, a number or a boolean.
@@ -1196,65 +1368,96 @@ public readonly struct OpenIddictParameter : IEquatable
}
}
- return array;
+ return builder.ToImmutable();
}
}
///
/// Converts a boolean to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(bool value) => new(value);
///
/// Converts a nullable boolean to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(bool? value) => new(value);
///
/// Converts a to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(JsonElement value) => new(value);
///
/// Converts a to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(JsonNode? value) => new(value);
///
/// Converts a long integer to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(long value) => new(value);
///
/// Converts a nullable long integer to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(long? value) => new(value);
///
/// Converts a string to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
public static implicit operator OpenIddictParameter(string? value) => new(value);
+ ///
+ /// Converts a string to an instance.
+ ///
+ /// The value to convert.
+ /// An instance.
+ public static implicit operator OpenIddictParameter(StringValues? value) => value?.Count switch
+ {
+ null or 0 => default,
+ 1 => new OpenIddictParameter(value.GetValueOrDefault()[0]),
+ _ => new(ImmutableCollectionsMarshal.AsImmutableArray(value.GetValueOrDefault().ToArray()))
+ };
+
+ ///
+ /// Converts a string to an instance.
+ ///
+ /// The value to convert.
+ /// An instance.
+ public static implicit operator OpenIddictParameter(StringValues value) => value.Count switch
+ {
+ 0 => default,
+ 1 => new OpenIddictParameter(value[0]),
+ _ => new(ImmutableCollectionsMarshal.AsImmutableArray(value.ToArray()))
+ };
+
+ ///
+ /// Converts an array of strings to an instance.
+ ///
+ /// The value to convert.
+ /// An instance.
+ public static implicit operator OpenIddictParameter(ImmutableArray value) => new(value);
+
///
/// Converts an array of strings to an instance.
///
- /// The value to convert
+ /// The value to convert.
/// An instance.
- public static implicit operator OpenIddictParameter(string?[]? value) => new(value);
+ public static implicit operator OpenIddictParameter(ImmutableArray? value) => new(value);
///
/// Determines whether a parameter is null or empty.
@@ -1263,7 +1466,7 @@ public readonly struct OpenIddictParameter : IEquatable
/// if the parameter is null or empty, otherwise.
public static bool IsNullOrEmpty(OpenIddictParameter parameter)
{
- return parameter.Value switch
+ return parameter._value switch
{
null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => true,
@@ -1298,11 +1501,14 @@ public readonly struct OpenIddictParameter : IEquatable
return element.GetArrayLength() is 0;
case JsonValueKind.Object:
+#if SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT
+ return element.GetPropertyCount() is 0;
+#else
using (var enumerator = element.EnumerateObject())
{
return !enumerator.MoveNext();
}
-
+#endif
default: return false;
}
}
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs
index dec7c9a7..7b72f057 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs
@@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
+using System.Collections.Immutable;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -79,7 +80,7 @@ public class OpenIddictRequest : OpenIddictMessage
///
/// The request parameters.
/// Parameters with a null or empty key are always ignored.
- public OpenIddictRequest(IEnumerable> parameters)
+ public OpenIddictRequest(IEnumerable?>> parameters)
: base(parameters)
{
}
@@ -134,18 +135,18 @@ public class OpenIddictRequest : OpenIddictMessage
///
/// Gets or sets the "audience" parameters.
///
- public string?[]? Audiences
+ public ImmutableArray? Audiences
{
- get => (string?[]?) GetParameter(OpenIddictConstants.Parameters.Audience);
+ get => (ImmutableArray?) GetParameter(OpenIddictConstants.Parameters.Audience);
set => SetParameter(OpenIddictConstants.Parameters.Audience, value);
}
///
/// Gets or sets the "claims" parameter.
///
- public JsonElement Claims
+ public JsonObject? Claims
{
- get => (JsonElement) GetParameter(OpenIddictConstants.Parameters.Claims);
+ get => (JsonObject?) GetParameter(OpenIddictConstants.Parameters.Claims);
set => SetParameter(OpenIddictConstants.Parameters.Claims, value);
}
@@ -379,9 +380,9 @@ public class OpenIddictRequest : OpenIddictMessage
///
/// Gets or sets the "resource" parameters.
///
- public string?[]? Resources
+ public ImmutableArray? Resources
{
- get => (string?[]?) GetParameter(OpenIddictConstants.Parameters.Resource);
+ get => (ImmutableArray?) GetParameter(OpenIddictConstants.Parameters.Resource);
set => SetParameter(OpenIddictConstants.Parameters.Resource, value);
}
@@ -442,9 +443,9 @@ public class OpenIddictRequest : OpenIddictMessage
///
/// Gets or sets the "registration" parameter.
///
- public JsonElement Registration
+ public JsonObject? Registration
{
- get => (JsonElement) GetParameter(OpenIddictConstants.Parameters.Registration);
+ get => (JsonObject?) GetParameter(OpenIddictConstants.Parameters.Registration);
set => SetParameter(OpenIddictConstants.Parameters.Registration, value);
}
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs
index 6a27bad4..65225514 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs
@@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
+using System.Collections.Immutable;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Text.Json;
@@ -78,7 +79,7 @@ public class OpenIddictResponse : OpenIddictMessage
///
/// The response parameters.
/// Parameters with a null or empty key are always ignored.
- public OpenIddictResponse(IEnumerable> parameters)
+ public OpenIddictResponse(IEnumerable?>> parameters)
: base(parameters)
{
}
diff --git a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Authentication.cs b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Authentication.cs
index 0187420f..ed64fe0a 100644
--- a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Authentication.cs
+++ b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Authentication.cs
@@ -78,9 +78,9 @@ public static partial class OpenIddictClientAspNetCoreHandlers
#if SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
var location = QueryHelpers.AddQueryString(context.AuthorizationEndpoint,
from parameter in context.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select KeyValuePair.Create(parameter.Key, value));
#else
@@ -88,9 +88,9 @@ public static partial class OpenIddictClientAspNetCoreHandlers
foreach (var (key, value) in
from parameter in context.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Session.cs b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Session.cs
index 2e974751..7b9c2064 100644
--- a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Session.cs
+++ b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Session.cs
@@ -78,9 +78,9 @@ public static partial class OpenIddictClientAspNetCoreHandlers
#if SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
var location = QueryHelpers.AddQueryString(context.EndSessionEndpoint,
from parameter in context.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select KeyValuePair.Create(parameter.Key, value));
#else
@@ -88,9 +88,9 @@ public static partial class OpenIddictClientAspNetCoreHandlers
foreach (var (key, value) in
from parameter in context.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
index e8c88f23..c3824696 100644
--- a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.cs
@@ -8,6 +8,7 @@ using System.Buffers.Binary;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
@@ -622,13 +623,17 @@ public static partial class OpenIddictClientAspNetCoreHandlers
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => new OpenIddictParameter(value),
- JsonNode value => new OpenIddictParameter(value),
- bool value => new OpenIddictParameter(value),
- int value => new OpenIddictParameter(value),
- long value => new OpenIddictParameter(value),
- string value => new OpenIddictParameter(value),
- string[] value => new OpenIddictParameter(value),
+
+ JsonElement value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ ImmutableArray value => new OpenIddictParameter(value),
+
+ string?[] value => new(ImmutableCollectionsMarshal.AsImmutableArray(value)),
+ IEnumerable value => new OpenIddictParameter([.. value]),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
@@ -943,13 +948,17 @@ public static partial class OpenIddictClientAspNetCoreHandlers
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => new OpenIddictParameter(value),
- JsonNode value => new OpenIddictParameter(value),
- bool value => new OpenIddictParameter(value),
- int value => new OpenIddictParameter(value),
- long value => new OpenIddictParameter(value),
- string value => new OpenIddictParameter(value),
- string[] value => new OpenIddictParameter(value),
+
+ JsonElement value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ ImmutableArray value => new OpenIddictParameter(value),
+
+ string?[] value => new(ImmutableCollectionsMarshal.AsImmutableArray(value)),
+ IEnumerable value => new OpenIddictParameter([.. value]),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
diff --git a/src/OpenIddict.Client.DataProtection/OpenIddictClientDataProtectionFormatter.cs b/src/OpenIddict.Client.DataProtection/OpenIddictClientDataProtectionFormatter.cs
index c267bbab..8b593bcb 100644
--- a/src/OpenIddict.Client.DataProtection/OpenIddictClientDataProtectionFormatter.cs
+++ b/src/OpenIddict.Client.DataProtection/OpenIddictClientDataProtectionFormatter.cs
@@ -52,7 +52,7 @@ public sealed class OpenIddictClientDataProtectionFormatter : IOpenIddictClientD
{
// Read the version of the format used to serialize the ticket.
var version = reader.ReadInt32();
- if (version != 5)
+ if (version is not 5)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0287));
}
diff --git a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Authentication.cs b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Authentication.cs
index f0fb8953..a369538f 100644
--- a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Authentication.cs
+++ b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Authentication.cs
@@ -78,9 +78,9 @@ public static partial class OpenIddictClientOwinHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Session.cs b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Session.cs
index 4447af9b..873efad4 100644
--- a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Session.cs
+++ b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Session.cs
@@ -76,9 +76,9 @@ public static partial class OpenIddictClientOwinHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
index 19f327e2..184cf080 100644
--- a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
+++ b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.cs
@@ -14,6 +14,7 @@ using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Extensions;
using Owin;
@@ -265,7 +266,10 @@ public static partial class OpenIddictClientOwinHandlers
if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
{
- context.Transaction.Request = new OpenIddictRequest(request.Query);
+ context.Transaction.Request = new OpenIddictRequest(
+ from parameter in request.Query
+ let values = new StringValues(parameter.Value)
+ select new KeyValuePair(parameter.Key, values));
}
else if (string.Equals(request.Method, "POST", StringComparison.OrdinalIgnoreCase))
@@ -296,7 +300,10 @@ public static partial class OpenIddictClientOwinHandlers
return;
}
- context.Transaction.Request = new OpenIddictRequest(await request.ReadFormAsync());
+ context.Transaction.Request = new OpenIddictRequest(
+ from parameter in await request.ReadFormAsync()
+ let values = new StringValues(parameter.Value)
+ select new KeyValuePair(parameter.Key, values));
}
else
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationActivationHandler.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationActivationHandler.cs
index f46a9688..2b69c938 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationActivationHandler.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationActivationHandler.cs
@@ -6,6 +6,7 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
@@ -78,7 +79,9 @@ public sealed class OpenIddictClientSystemIntegrationActivationHandler : IHosted
}
#endif
// Otherwise, try to extract the protocol activation from the command line arguments.
- if (GetProtocolActivationUriFromCommandLineArguments(Environment.GetCommandLineArgs()) is Uri value)
+ var arguments = ImmutableCollectionsMarshal.AsImmutableArray(Environment.GetCommandLineArgs());
+
+ if (GetProtocolActivationUriFromCommandLineArguments(arguments) is Uri value)
{
return new OpenIddictClientSystemIntegrationActivation(value);
}
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
index a194a34a..1ef54bf5 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
@@ -240,8 +240,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
NSUrl CreateUrl() => new(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri);
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value)).AbsoluteUri);
void HandleCallback(NSUrl? url, NSError? error)
{
@@ -253,12 +253,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(url.Query))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -270,12 +265,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(url.Fragment))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -370,8 +360,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
intent.LaunchUrl(Application.Context, NativeUri.Parse(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri)!);
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value)).AbsoluteUri)!);
context.HandleRequest();
#else
@@ -455,8 +445,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
requestUri : OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value))),
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value)),
callbackUri: new Uri(context.RedirectUri, UriKind.Absolute)))
{
case { ResponseStatus: WebAuthenticationStatus.Success } result
@@ -467,12 +457,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -484,12 +469,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -576,8 +556,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
var uri = OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.AuthorizationEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value)));
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
index 052c32d6..05c0d5a1 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
@@ -240,8 +240,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
NSUrl CreateUrl() => new(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri);
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value)).AbsoluteUri);
void HandleCallback(NSUrl? url, NSError? error)
{
@@ -253,12 +253,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(url.Query))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -270,12 +265,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(url.Fragment))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -370,8 +360,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
intent.LaunchUrl(Application.Context, NativeUri.Parse(OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value))).AbsoluteUri)!);
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value)).AbsoluteUri)!);
context.HandleRequest();
#else
@@ -455,8 +445,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
requestUri : OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value))),
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value)),
callbackUri: new Uri(context.PostLogoutRedirectUri, UriKind.Absolute)))
{
case { ResponseStatus: WebAuthenticationStatus.Success } result
@@ -467,12 +457,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(uri.Query))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -484,12 +469,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(uri.Fragment))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -576,8 +556,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
var uri = OpenIddictHelpers.AddQueryStringParameters(
uri: new Uri(context.EndSessionEndpoint, UriKind.Absolute),
parameters: context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value)));
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
index 242b5f72..5821986b 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHelpers.cs
@@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
+using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
@@ -378,7 +379,7 @@ public static class OpenIddictClientSystemIntegrationHelpers
/// The if the application instance was activated
/// via a protocol activation, otherwise.
///
- internal static Uri? GetProtocolActivationUriFromCommandLineArguments(string?[]? arguments) => arguments switch
+ internal static Uri? GetProtocolActivationUriFromCommandLineArguments(ImmutableArray arguments) => arguments switch
{
// In most cases, the first segment present in the command line arguments contains the path of the
// executable, but it's technically possible to start an application in a way that the command line
diff --git a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs
index 606c5b4c..1548d3a4 100644
--- a/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs
+++ b/src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs
@@ -69,12 +69,7 @@ public sealed class OpenIddictClientSystemIntegrationService
{
foreach (var parameter in OpenIddictHelpers.ParseQuery(intent.Data.Query))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
@@ -86,12 +81,7 @@ public sealed class OpenIddictClientSystemIntegrationService
{
foreach (var parameter in OpenIddictHelpers.ParseFragment(intent.Data.Fragment))
{
- parameters[parameter.Key] = parameter.Value.Count switch
- {
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value.ToArray()
- };
+ parameters[parameter.Key] = parameter.Value;
}
}
diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
index da2fec76..aa171c40 100644
--- a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
+++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
@@ -1044,8 +1044,8 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
{
request.RequestUri = OpenIddictHelpers.AddQueryStringParameters(request.RequestUri,
context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value)));
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value));
}
// For POST requests, attach the request parameters to the request form by default.
@@ -1053,9 +1053,9 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
{
request.Content = new FormUrlEncodedContent(
from parameter in context.Transaction.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
select new KeyValuePair(parameter.Key, value));
}
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
index a3e61f78..9fc48bd9 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
@@ -1486,24 +1486,12 @@ public static partial class OpenIddictClientHandlers
// The following parameters MUST be formatted as arrays of objects:
JsonWebKeySetParameterNames.Keys => ((JsonElement) value) is JsonElement element &&
- element.ValueKind is JsonValueKind.Array && ValidateObjectArray(element),
+ element.ValueKind is JsonValueKind.Array &&
+ OpenIddictHelpers.ValidateArrayElements(element, JsonValueKind.Object),
// Parameters that are not in the well-known list can be of any type.
_ => true
};
-
- static bool ValidateObjectArray(JsonElement element)
- {
- foreach (var item in element.EnumerateArray())
- {
- if (item.ValueKind is not JsonValueKind.Object)
- {
- return false;
- }
- }
-
- return true;
- }
}
}
diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Authentication.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Authentication.cs
index 18dc8a18..61e4609b 100644
--- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Authentication.cs
+++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Authentication.cs
@@ -102,9 +102,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
#if SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
var location = QueryHelpers.AddQueryString(context.RequestUri.GetLeftPart(UriPartial.Path),
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select KeyValuePair.Create(parameter.Key, value));
#else
@@ -112,9 +112,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -188,9 +188,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -264,9 +264,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
#if SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
var location = QueryHelpers.AddQueryString(context.RedirectUri,
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select KeyValuePair.Create(parameter.Key, value));
#else
@@ -274,9 +274,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -335,9 +335,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs
index ac2b2d93..0575c971 100644
--- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs
+++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs
@@ -84,9 +84,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
#if SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
var location = QueryHelpers.AddQueryString(context.RequestUri.GetLeftPart(UriPartial.Path),
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select KeyValuePair.Create(parameter.Key, value));
#else
@@ -94,9 +94,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -154,9 +154,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
#if SUPPORTS_MULTIPLE_VALUES_IN_QUERYHELPERS
var location = QueryHelpers.AddQueryString(context.PostLogoutRedirectUri,
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select KeyValuePair.Create(parameter.Key, value));
#else
@@ -164,9 +164,9 @@ public static partial class OpenIddictServerAspNetCoreHandlers
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
index e7405851..8b0ed708 100644
--- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
@@ -7,6 +7,7 @@
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
@@ -257,13 +258,17 @@ public static partial class OpenIddictServerAspNetCoreHandlers
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => new OpenIddictParameter(value),
- JsonNode value => new OpenIddictParameter(value),
- bool value => new OpenIddictParameter(value),
- int value => new OpenIddictParameter(value),
- long value => new OpenIddictParameter(value),
- string value => new OpenIddictParameter(value),
- string[] value => new OpenIddictParameter(value),
+
+ JsonElement value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ ImmutableArray value => new OpenIddictParameter(value),
+
+ string?[] value => new(ImmutableCollectionsMarshal.AsImmutableArray(value)),
+ IEnumerable value => new OpenIddictParameter([.. value]),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
@@ -354,13 +359,17 @@ public static partial class OpenIddictServerAspNetCoreHandlers
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => new OpenIddictParameter(value),
- JsonNode value => new OpenIddictParameter(value),
- bool value => new OpenIddictParameter(value),
- int value => new OpenIddictParameter(value),
- long value => new OpenIddictParameter(value),
- string value => new OpenIddictParameter(value),
- string[] value => new OpenIddictParameter(value),
+
+ JsonElement value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ ImmutableArray value => new OpenIddictParameter(value),
+
+ string?[] value => new(ImmutableCollectionsMarshal.AsImmutableArray(value)),
+ IEnumerable value => new OpenIddictParameter([.. value]),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
@@ -413,13 +422,17 @@ public static partial class OpenIddictServerAspNetCoreHandlers
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => new OpenIddictParameter(value),
- JsonNode value => new OpenIddictParameter(value),
- bool value => new OpenIddictParameter(value),
- int value => new OpenIddictParameter(value),
- long value => new OpenIddictParameter(value),
- string value => new OpenIddictParameter(value),
- string[] value => new OpenIddictParameter(value),
+
+ JsonElement value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ ImmutableArray value => new OpenIddictParameter(value),
+
+ string?[] value => new(ImmutableCollectionsMarshal.AsImmutableArray(value)),
+ IEnumerable value => new OpenIddictParameter([.. value]),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
diff --git a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
index 57eb3a40..50afca1a 100644
--- a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
+++ b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
@@ -61,7 +61,7 @@ public sealed class OpenIddictServerDataProtectionFormatter : IOpenIddictServerD
{
// Read the version of the format used to serialize the ticket.
var version = reader.ReadInt32();
- if (version != 5)
+ if (version is not 5)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0287));
}
diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Authentication.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Authentication.cs
index b43071c4..4a24d218 100644
--- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Authentication.cs
+++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Authentication.cs
@@ -104,9 +104,9 @@ public static partial class OpenIddictServerOwinHandlers
var location = context.RequestUri.GetLeftPart(UriPartial.Path);
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -180,9 +180,9 @@ public static partial class OpenIddictServerOwinHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -256,9 +256,9 @@ public static partial class OpenIddictServerOwinHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -317,9 +317,9 @@ public static partial class OpenIddictServerOwinHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs
index f952fb28..f32bc84f 100644
--- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs
+++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs
@@ -84,9 +84,9 @@ public static partial class OpenIddictServerOwinHandlers
var location = context.RequestUri.GetLeftPart(UriPartial.Path);
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
@@ -143,9 +143,9 @@ public static partial class OpenIddictServerOwinHandlers
// For consistency, multiple parameters with the same name are also supported by this endpoint.
foreach (var (key, value) in
from parameter in context.Response.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
where !string.IsNullOrEmpty(value)
select (parameter.Key, Value: value))
{
diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
index a0ea78cc..28f2790f 100644
--- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
+++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
@@ -13,6 +13,7 @@ using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
using OpenIddict.Extensions;
using Owin;
using static OpenIddict.Server.Owin.OpenIddictServerOwinConstants;
@@ -524,7 +525,10 @@ public static partial class OpenIddictServerOwinHandlers
if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
{
- context.Transaction.Request = new OpenIddictRequest(request.Query);
+ context.Transaction.Request = new OpenIddictRequest(
+ from parameter in request.Query
+ let values = new StringValues(parameter.Value)
+ select new KeyValuePair(parameter.Key, values));
}
else
@@ -575,7 +579,10 @@ public static partial class OpenIddictServerOwinHandlers
if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
{
- context.Transaction.Request = new OpenIddictRequest(request.Query);
+ context.Transaction.Request = new OpenIddictRequest(
+ from parameter in request.Query
+ let values = new StringValues(parameter.Value)
+ select new KeyValuePair(parameter.Key, values));
}
else if (string.Equals(request.Method, "POST", StringComparison.OrdinalIgnoreCase))
@@ -606,7 +613,10 @@ public static partial class OpenIddictServerOwinHandlers
return;
}
- context.Transaction.Request = new OpenIddictRequest(await request.ReadFormAsync());
+ context.Transaction.Request = new OpenIddictRequest(
+ from parameter in await request.ReadFormAsync()
+ let values = new StringValues(parameter.Value)
+ select new KeyValuePair(parameter.Key, values));
}
else
@@ -681,7 +691,10 @@ public static partial class OpenIddictServerOwinHandlers
return;
}
- context.Transaction.Request = new OpenIddictRequest(await request.ReadFormAsync());
+ context.Transaction.Request = new OpenIddictRequest(
+ from parameter in await request.ReadFormAsync()
+ let values = new StringValues(parameter.Value)
+ select new KeyValuePair(parameter.Key, values));
}
else
diff --git a/src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs b/src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs
index beefc946..bdc2c92d 100644
--- a/src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs
+++ b/src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs
@@ -6,6 +6,7 @@
using System.Security.Claims;
using System.Text.Json;
+using System.Text.Json.Nodes;
namespace OpenIddict.Server;
@@ -102,7 +103,7 @@ public static partial class OpenIddictServerEvents
/// Note: this value should only be populated if the "address"
/// scope was requested and accepted by the resource owner.
///
- public JsonElement Address { get; set; }
+ public JsonObject? Address { get; set; }
///
/// Gets or sets the values used for the "aud" claim.
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
index 26beb1a7..4d41e66e 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
@@ -246,20 +246,20 @@ public static partial class OpenIddictServerHandlers
[Metadata.DeviceAuthorizationEndpoint] = notification.DeviceAuthorizationEndpoint?.AbsoluteUri,
[Metadata.PushedAuthorizationRequestEndpoint] = notification.PushedAuthorizationEndpoint?.AbsoluteUri,
[Metadata.JwksUri] = notification.JsonWebKeySetEndpoint?.AbsoluteUri,
- [Metadata.GrantTypesSupported] = notification.GrantTypes.ToArray(),
- [Metadata.ResponseTypesSupported] = notification.ResponseTypes.ToArray(),
- [Metadata.ResponseModesSupported] = notification.ResponseModes.ToArray(),
- [Metadata.ScopesSupported] = notification.Scopes.ToArray(),
- [Metadata.ClaimsSupported] = notification.Claims.ToArray(),
- [Metadata.IdTokenSigningAlgValuesSupported] = notification.IdTokenSigningAlgorithms.ToArray(),
- [Metadata.CodeChallengeMethodsSupported] = notification.CodeChallengeMethods.ToArray(),
- [Metadata.SubjectTypesSupported] = notification.SubjectTypes.ToArray(),
- [Metadata.PromptValuesSupported] = notification.PromptValues.ToArray(),
- [Metadata.TokenEndpointAuthMethodsSupported] = notification.TokenEndpointAuthenticationMethods.ToArray(),
- [Metadata.IntrospectionEndpointAuthMethodsSupported] = notification.IntrospectionEndpointAuthenticationMethods.ToArray(),
- [Metadata.RevocationEndpointAuthMethodsSupported] = notification.RevocationEndpointAuthenticationMethods.ToArray(),
- [Metadata.DeviceAuthorizationEndpointAuthMethodsSupported] = notification.DeviceAuthorizationEndpointAuthenticationMethods.ToArray(),
- [Metadata.PushedAuthorizationRequestEndpointAuthMethodsSupported] = notification.PushedAuthorizationEndpointAuthenticationMethods.ToArray(),
+ [Metadata.GrantTypesSupported] = notification.GrantTypes.ToImmutableArray(),
+ [Metadata.ResponseTypesSupported] = notification.ResponseTypes.ToImmutableArray(),
+ [Metadata.ResponseModesSupported] = notification.ResponseModes.ToImmutableArray(),
+ [Metadata.ScopesSupported] = notification.Scopes.ToImmutableArray(),
+ [Metadata.ClaimsSupported] = notification.Claims.ToImmutableArray(),
+ [Metadata.IdTokenSigningAlgValuesSupported] = notification.IdTokenSigningAlgorithms.ToImmutableArray(),
+ [Metadata.CodeChallengeMethodsSupported] = notification.CodeChallengeMethods.ToImmutableArray(),
+ [Metadata.SubjectTypesSupported] = notification.SubjectTypes.ToImmutableArray(),
+ [Metadata.PromptValuesSupported] = notification.PromptValues.ToImmutableArray(),
+ [Metadata.TokenEndpointAuthMethodsSupported] = notification.TokenEndpointAuthenticationMethods.ToImmutableArray(),
+ [Metadata.IntrospectionEndpointAuthMethodsSupported] = notification.IntrospectionEndpointAuthenticationMethods.ToImmutableArray(),
+ [Metadata.RevocationEndpointAuthMethodsSupported] = notification.RevocationEndpointAuthenticationMethods.ToImmutableArray(),
+ [Metadata.DeviceAuthorizationEndpointAuthMethodsSupported] = notification.DeviceAuthorizationEndpointAuthenticationMethods.ToImmutableArray(),
+ [Metadata.PushedAuthorizationRequestEndpointAuthMethodsSupported] = notification.PushedAuthorizationEndpointAuthenticationMethods.ToImmutableArray(),
[Metadata.RequirePushedAuthorizationRequests] = notification.RequirePushedAuthorizationRequests
};
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
index 0d81a61b..4bf16da7 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
@@ -268,7 +268,7 @@ public static partial class OpenIddictServerHandlers
break;
default:
- response[Claims.Audience] = notification.Audiences.ToArray();
+ response[Claims.Audience] = notification.Audiences.ToImmutableArray();
break;
}
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs
index 27ee1f28..2b348a6f 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs
@@ -556,11 +556,18 @@ public static partial class OpenIddictServerHandlers
// Restore the claim destinations from the special oi_cl_dstn claim (represented as a dictionary/JSON object).
//
// Note: starting in 7.0, Wilson no longer uses JSON.NET and supports a limited set of types for the
- // TryGetPayloadValue() API. Since ImmutableDictionary is not supported, the value
- // is retrieved as a Dictionary, which is supported by both Wilson 6.x and 7.x.
+ // TryGetPayloadValue() API. Since ImmutableDictionary is not supported, the value is
+ // retrieved as a Dictionary and converted to ImmutableDictionary.
if (token.TryGetPayloadValue(Claims.Private.ClaimDestinationsMap, out Dictionary destinations))
{
- context.Principal.SetDestinations(destinations.ToImmutableDictionary());
+ var builder = ImmutableDictionary.CreateBuilder>();
+
+ foreach (var destination in destinations)
+ {
+ builder.Add(destination.Key, [.. destination.Value]);
+ }
+
+ context.Principal.SetDestinations(builder.ToImmutable());
}
context.Logger.LogTrace(SR.GetResourceString(SR.ID6001), context.Token, context.Principal.Claims);
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs
index 430e888f..c32344a6 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs
@@ -243,7 +243,7 @@ public static partial class OpenIddictServerHandlers
break;
default:
- response[Claims.Audience] = notification.Audiences.ToArray();
+ response[Claims.Audience] = notification.Audiences.ToImmutableArray();
break;
}
diff --git a/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs b/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
index ce37c6a6..0131b084 100644
--- a/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
@@ -7,6 +7,7 @@
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
@@ -368,13 +369,17 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
context.Parameters[parameter.Key] = parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => new OpenIddictParameter(value),
- JsonNode value => new OpenIddictParameter(value),
- bool value => new OpenIddictParameter(value),
- int value => new OpenIddictParameter(value),
- long value => new OpenIddictParameter(value),
- string value => new OpenIddictParameter(value),
- string[] value => new OpenIddictParameter(value),
+
+ JsonElement value => new OpenIddictParameter(value),
+ JsonNode value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ ImmutableArray value => new OpenIddictParameter(value),
+
+ string?[] value => new(ImmutableCollectionsMarshal.AsImmutableArray(value)),
+ IEnumerable value => new OpenIddictParameter([.. value]),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
};
diff --git a/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs b/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs
index 2a24d29b..983a982f 100644
--- a/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs
+++ b/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs
@@ -44,7 +44,7 @@ public sealed class OpenIddictValidationDataProtectionFormatter : IOpenIddictVal
{
// Read the version of the format used to serialize the ticket.
var version = reader.ReadInt32();
- if (version != 5)
+ if (version is not 5)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0287));
}
diff --git a/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs b/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
index 8bc6698a..a872cd8e 100644
--- a/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
+++ b/src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
@@ -568,8 +568,8 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
{
request.RequestUri = OpenIddictHelpers.AddQueryStringParameters(request.RequestUri,
context.Transaction.Request.GetParameters().ToDictionary(
- parameter => parameter.Key,
- parameter => new StringValues((string?[]?) parameter.Value)));
+ static parameter => parameter.Key,
+ static parameter => (StringValues) parameter.Value));
}
// For POST requests, attach the request parameters to the request form by default.
@@ -577,9 +577,9 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
{
request.Content = new FormUrlEncodedContent(
from parameter in context.Transaction.Request.GetParameters()
- let values = (string?[]?) parameter.Value
+ let values = (ImmutableArray?) parameter.Value
where values is not null
- from value in values
+ from value in values.GetValueOrDefault()
select new KeyValuePair(parameter.Key, value));
}
diff --git a/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs b/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
index dad16eb0..7bedb22f 100644
--- a/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
+++ b/src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs
@@ -445,24 +445,12 @@ public static partial class OpenIddictValidationHandlers
// The following parameters MUST be formatted as arrays of objects:
JsonWebKeySetParameterNames.Keys => ((JsonElement) value) is JsonElement element &&
- element.ValueKind is JsonValueKind.Array && ValidateObjectArray(element),
+ element.ValueKind is JsonValueKind.Array &&
+ OpenIddictHelpers.ValidateArrayElements(element, JsonValueKind.Object),
// Parameters that are not in the well-known list can be of any type.
_ => true
};
-
- static bool ValidateObjectArray(JsonElement element)
- {
- foreach (var item in element.EnumerateArray())
- {
- if (item.ValueKind is not JsonValueKind.Object)
- {
- return false;
- }
- }
-
- return true;
- }
}
}
diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictConverterTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictConverterTests.cs
index f4b47866..4251d81a 100644
--- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictConverterTests.cs
+++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictConverterTests.cs
@@ -269,7 +269,7 @@ public class OpenIddictConverterTests
var message = new OpenIddictMessage();
message.AddParameter("string", "value");
- message.AddParameter("array", new[] { "value" });
+ message.AddParameter("array", new OpenIddictParameter(["value"]));
// Act
converter.Write(writer, value: message, options: null!);
diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
index 317d3b7a..a3efe139 100644
--- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
+++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
@@ -1125,8 +1125,8 @@ public class OpenIddictExtensionsTests
// Assert
Assert.Equal(2, destinations.Count);
- Assert.Equal([Destinations.AccessToken, Destinations.IdentityToken], destinations[Claims.Name]);
- Assert.Equal([Destinations.IdentityToken], destinations[Claims.Email]);
+ Assert.Equal([Destinations.AccessToken, Destinations.IdentityToken], [.. destinations[Claims.Name]]);
+ Assert.Equal([Destinations.IdentityToken], [.. destinations[Claims.Email]]);
}
[Fact]
@@ -1159,8 +1159,8 @@ public class OpenIddictExtensionsTests
// Assert
Assert.Equal(2, destinations.Count);
- Assert.Equal([Destinations.AccessToken, Destinations.IdentityToken], destinations[Claims.Name]);
- Assert.Equal([Destinations.IdentityToken], destinations[Claims.Email]);
+ Assert.Equal([Destinations.AccessToken, Destinations.IdentityToken], [.. destinations[Claims.Name]]);
+ Assert.Equal([Destinations.IdentityToken], [.. destinations[Claims.Email]]);
}
[Fact]
@@ -1192,7 +1192,7 @@ public class OpenIddictExtensionsTests
{
// Arrange
var identity = new ClaimsIdentity();
- var destinations = (ImmutableDictionary) null!;
+ var destinations = (ImmutableDictionary>) null!;
// Act and assert
var exception = Assert.Throws(() => identity.SetDestinations(destinations));
@@ -1205,7 +1205,7 @@ public class OpenIddictExtensionsTests
{
// Arrange
var principal = new ClaimsPrincipal(new ClaimsIdentity());
- var destinations = (ImmutableDictionary) null!;
+ var destinations = (ImmutableDictionary>) null!;
// Act and assert
var exception = Assert.Throws(() => principal.SetDestinations(destinations));
@@ -1226,7 +1226,7 @@ public class OpenIddictExtensionsTests
var identity = new ClaimsIdentity(claims);
- var destinations = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal);
+ var destinations = ImmutableDictionary.CreateBuilder>(StringComparer.Ordinal);
destinations.Add(Claims.Name, [Destinations.AccessToken, Destinations.IdentityToken]);
destinations.Add(Claims.Email, [Destinations.IdentityToken]);
destinations.Add(Claims.Nonce, []);
@@ -1253,7 +1253,7 @@ public class OpenIddictExtensionsTests
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims));
- var destinations = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal);
+ var destinations = ImmutableDictionary.CreateBuilder>(StringComparer.Ordinal);
destinations.Add(Claims.Name, [Destinations.AccessToken, Destinations.IdentityToken]);
destinations.Add(Claims.Email, [Destinations.IdentityToken]);
destinations.Add(Claims.Nonce, []);
diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs
index 3f9ec073..013ce84e 100644
--- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs
+++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs
@@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
+using System.Collections.Immutable;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
@@ -98,7 +99,8 @@ public class OpenIddictMessageTests
// Assert
Assert.Equal(1, message.Count);
- Assert.Equal(["Fabrikam", "Contoso"], (string?[]?) message.GetParameter("parameter"));
+ Assert.Equal?>(["Fabrikam", "Contoso"],
+ (ImmutableArray?) message.GetParameter("parameter"));
}
[Fact]
@@ -107,12 +109,13 @@ public class OpenIddictMessageTests
// Arrange and act
var message = new OpenIddictMessage(
[
- new KeyValuePair("parameter", ["Fabrikam", "Contoso"])
+ new KeyValuePair?>("parameter", ["Fabrikam", "Contoso"])
]);
// Assert
Assert.Equal(1, message.Count);
- Assert.Equal(["Fabrikam", "Contoso"], (string?[]?) message.GetParameter("parameter"));
+ Assert.Equal?>(["Fabrikam", "Contoso"],
+ (ImmutableArray?) message.GetParameter("parameter"));
}
[Fact]
@@ -121,12 +124,12 @@ public class OpenIddictMessageTests
// Arrange and act
var message = new OpenIddictMessage(
[
- new KeyValuePair("parameter", ["Fabrikam"])
+ new KeyValuePair?>("parameter", ["Fabrikam"])
]);
// Assert
Assert.Equal(1, message.Count);
- Assert.Equal("Fabrikam", message.GetParameter("parameter")?.Value);
+ Assert.Equal("Fabrikam", (string?) message.GetParameter("parameter"));
}
[Theory]
@@ -423,7 +426,7 @@ public class OpenIddictMessageTests
// Act and assert
Assert.True(message.TryGetParameter("parameter", out var parameter));
- Assert.Equal(42, (long?) parameter.Value);
+ Assert.Equal(42, (long?) parameter);
}
[Fact]
@@ -434,7 +437,7 @@ public class OpenIddictMessageTests
// Act and assert
Assert.False(message.TryGetParameter("parameter", out OpenIddictParameter parameter));
- Assert.Null(parameter.Value);
+ Assert.Equal(default, parameter);
}
[Fact]
@@ -507,7 +510,7 @@ public class OpenIddictMessageTests
// Arrange
var message = new OpenIddictMessage
{
- ["redirect_uris"] = new[] { "https://abc.org/callback" },
+ ["redirect_uris"] = new OpenIddictParameter(["https://abc.org/callback"]),
["client_name"] = "My Example Client"
};
diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictParameterTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictParameterTests.cs
index 81c29ed0..b837deb3 100644
--- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictParameterTests.cs
+++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictParameterTests.cs
@@ -4,9 +4,12 @@
* the license and the contributors participating to this project.
*/
+using System.Collections.Immutable;
+using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
+using Microsoft.Extensions.Primitives;
using Xunit;
namespace OpenIddict.Abstractions.Tests.Primitives;
@@ -191,9 +194,9 @@ public class OpenIddictParameterTests
var parameter = new OpenIddictParameter(["Fabrikam", "Contoso"]);
// Act and assert
- Assert.True(parameter.Equals(new string[] { "Fabrikam", "Contoso" }));
- Assert.False(parameter.Equals(new string[] { "Fabrikam" }));
- Assert.False(parameter.Equals(new string[] { "Contoso", "Fabrikam" }));
+ Assert.True(parameter.Equals(new OpenIddictParameter(["Fabrikam", "Contoso"])));
+ Assert.False(parameter.Equals(new OpenIddictParameter(["Fabrikam"])));
+ Assert.False(parameter.Equals(new OpenIddictParameter(["Contoso", "Fabrikam"])));
}
[Fact]
@@ -203,11 +206,11 @@ public class OpenIddictParameterTests
var parameter = new OpenIddictParameter(JsonSerializer.Deserialize("[0,1,2,3]"));
// Act and assert
- Assert.True(parameter.Equals(JsonSerializer.Deserialize("[0,1,2,3]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("[]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("[0,1,2]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("[3,2,1,0]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("{}")));
+ Assert.True(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[0,1,2,3]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[0,1,2]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[3,2,1,0]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("{}"))));
Assert.True(parameter.Equals(new OpenIddictParameter(new JsonArray(0, 1, 2, 3))));
Assert.False(parameter.Equals(new OpenIddictParameter(new JsonArray())));
@@ -223,11 +226,11 @@ public class OpenIddictParameterTests
var parameter = new OpenIddictParameter(new JsonArray(0, 1, 2, 3));
// Act and assert
- Assert.True(parameter.Equals(JsonSerializer.Deserialize("[0,1,2,3]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("[]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("[0,1,2]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("[3,2,1,0]")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize("{}")));
+ Assert.True(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[0,1,2,3]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[0,1,2]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("[3,2,1,0]"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize("{}"))));
Assert.True(parameter.Equals(new OpenIddictParameter(new JsonArray(0, 1, 2, 3))));
Assert.False(parameter.Equals(new OpenIddictParameter(new JsonArray())));
@@ -243,11 +246,11 @@ public class OpenIddictParameterTests
var parameter = new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":[0,1,2,3]}"));
// Act and assert
- Assert.True(parameter.Equals(JsonSerializer.Deserialize(@"{""field"":[0,1,2,3]}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"{}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"{""field"":""value""}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"{""field"":[0,1,2]}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"[]")));
+ Assert.True(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":[0,1,2,3]}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":""value""}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":[0,1,2]}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"[]"))));
Assert.True(parameter.Equals(new OpenIddictParameter(new JsonObject
{
@@ -285,23 +288,23 @@ public class OpenIddictParameterTests
});
// Act and assert
- Assert.True(parameter.Equals(JsonSerializer.Deserialize(@"{""field"":[0,1,2,3]}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"{}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"{""field"":""value""}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"{""field"":[0,1,2]}")));
- Assert.False(parameter.Equals(JsonSerializer.Deserialize(@"[]")));
+ Assert.True(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":[0,1,2,3]}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":""value""}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"{""field"":[0,1,2]}"))));
+ Assert.False(parameter.Equals(new OpenIddictParameter(JsonSerializer.Deserialize(@"[]"))));
- Assert.True(parameter.Equals(new JsonObject
+ Assert.True(parameter.Equals(new OpenIddictParameter(new JsonObject
{
["field"] = new JsonArray(0, 1, 2, 3)
- }));
+ })));
- Assert.False(parameter.Equals(new JsonObject()));
+ Assert.False(parameter.Equals(new OpenIddictParameter(new JsonObject())));
- Assert.False(parameter.Equals(new JsonObject
+ Assert.False(parameter.Equals(new OpenIddictParameter(new JsonObject
{
["field"] = JsonValue.Create("value")
- }));
+ })));
Assert.False(parameter.Equals(new OpenIddictParameter(new JsonObject
{
@@ -309,20 +312,20 @@ public class OpenIddictParameterTests
@"{""field"":""value""}").GetProperty("field"))
})));
- Assert.False(parameter.Equals(new JsonObject
+ Assert.False(parameter.Equals(new OpenIddictParameter(new JsonObject
{
["field"] = new JsonArray(0, 1, 2)
- }));
+ })));
- Assert.True(parameter.Equals(JsonValue.Create(new Dictionary
+ Assert.True(parameter.Equals(new OpenIddictParameter(JsonValue.Create(new Dictionary
{
["field"] = new JsonArray(0, 1, 2, 3)
- })));
+ }))));
- Assert.True(parameter.Equals(JsonValue.Create(new Dictionary
+ Assert.True(parameter.Equals(new OpenIddictParameter(JsonValue.Create(new Dictionary
{
["field"] = new[] { 0, 1, 2, 3 }
- })));
+ }))));
}
[Fact]
@@ -797,11 +800,7 @@ public class OpenIddictParameterTests
public void GetNamedParameters_ReturnsEmptyDictionaryForArrays()
{
// Arrange
- var parameters = new[]
- {
- "Fabrikam",
- "Contoso"
- };
+ ImmutableArray parameters = ["Fabrikam", "Contoso"];
var parameter = new OpenIddictParameter(parameters);
@@ -924,11 +923,7 @@ public class OpenIddictParameterTests
public void GetUnnamedParameters_ReturnsExpectedParametersForArrays()
{
// Arrange
- var parameters = new[]
- {
- "Fabrikam",
- "Contoso"
- };
+ ImmutableArray parameters = ["Fabrikam", "Contoso"];
var parameter = new OpenIddictParameter(parameters);
@@ -1024,7 +1019,7 @@ public class OpenIddictParameterTests
Assert.True(OpenIddictParameter.IsNullOrEmpty(new OpenIddictParameter((bool?) null)));
Assert.True(OpenIddictParameter.IsNullOrEmpty(new OpenIddictParameter((long?) null)));
Assert.True(OpenIddictParameter.IsNullOrEmpty(new OpenIddictParameter((string?) null)));
- Assert.True(OpenIddictParameter.IsNullOrEmpty(new OpenIddictParameter((string?[]?) null)));
+ Assert.True(OpenIddictParameter.IsNullOrEmpty(new OpenIddictParameter((ImmutableArray?) null)));
}
[Fact]
@@ -1502,11 +1497,11 @@ public class OpenIddictParameterTests
public void BoolConverter_CanCreateParameterFromBooleanValue()
{
// Arrange, act and assert
- Assert.True((bool?) new OpenIddictParameter(true).Value);
- Assert.True((bool?) new OpenIddictParameter((bool?) true).Value);
+ Assert.True((bool?) new OpenIddictParameter(true));
+ Assert.True((bool?) new OpenIddictParameter((bool?) true));
- Assert.False((bool?) new OpenIddictParameter(false).Value);
- Assert.False((bool?) new OpenIddictParameter((bool?) false).Value);
+ Assert.False((bool?) new OpenIddictParameter(false));
+ Assert.False((bool?) new OpenIddictParameter((bool?) false));
}
[Fact]
@@ -1898,8 +1893,8 @@ public class OpenIddictParameterTests
public void LongConverter_CanCreateParameterFromLongValue()
{
// Arrange, act and assert
- Assert.Equal(42, (long?) new OpenIddictParameter(42).Value);
- Assert.Equal(42, (long?) new OpenIddictParameter((long?) 42).Value);
+ Assert.Equal(42, (long?) new OpenIddictParameter(42));
+ Assert.Equal(42, (long?) new OpenIddictParameter((long?) 42));
}
[Fact]
@@ -1970,7 +1965,7 @@ public class OpenIddictParameterTests
public void StringConverter_CanCreateParameterFromStringValue()
{
// Arrange, act and assert
- Assert.Equal("Fabrikam", (string?) new OpenIddictParameter("Fabrikam").Value);
+ Assert.Equal("Fabrikam", (string?) new OpenIddictParameter("Fabrikam"));
}
[Fact]
@@ -2041,77 +2036,155 @@ public class OpenIddictParameterTests
public void StringArrayConverter_CanCreateParameterFromArray()
{
// Arrange
- var array = new[] { "Fabrikam", "Contoso" };
+ string?[] array = ["Fabrikam", "Contoso"];
// Act
- var parameter = new OpenIddictParameter(array);
+ var parameter = new OpenIddictParameter([.. array]);
// Assert
- Assert.Same(array, parameter.Value);
+ Assert.Equal?>(array, (ImmutableArray?) parameter);
}
[Fact]
public void StringArrayConverter_CanCreateParameterFromPrimitiveValues()
{
// Arrange, act and assert
- Assert.Equal(["Fabrikam"], (string?[]?) new OpenIddictParameter("Fabrikam"));
- Assert.Equal(["false"], (string?[]?) new OpenIddictParameter(false));
- Assert.Equal(["42"], (string?[]?) new OpenIddictParameter(42));
+ Assert.Equal?>(["Fabrikam"], (ImmutableArray?) new OpenIddictParameter("Fabrikam"));
+ Assert.Equal?>(["false"], (ImmutableArray?) new OpenIddictParameter(false));
+ Assert.Equal?>(["42"], (ImmutableArray?) new OpenIddictParameter(42));
}
[Fact]
public void StringArrayConverter_ReturnsDefaultValueForNullValues()
{
// Arrange, act and assert
- Assert.Null((string?[]?) new OpenIddictParameter());
+ Assert.Null((ImmutableArray?) new OpenIddictParameter());
}
[Fact]
public void StringArrayConverter_ReturnsSingleElementArrayForStringValue()
{
// Arrange, act and assert
- Assert.Equal(["Fabrikam"], (string?[]?) new OpenIddictParameter("Fabrikam"));
+ Assert.Equal?>(["Fabrikam"], (ImmutableArray?) new OpenIddictParameter("Fabrikam"));
}
[Fact]
public void StringArrayConverter_ReturnsDefaultValueForUnsupportedJsonValues()
{
// Arrange, act and assert
- Assert.Null((string?[]?) new OpenIddictParameter(new JsonElement()));
- Assert.Null((string?[]?) new OpenIddictParameter(
+ Assert.Null((ImmutableArray?) new OpenIddictParameter(new JsonElement()));
+ Assert.Null((ImmutableArray?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"[""value"",[]]")));
- Assert.Null((string?[]?) new OpenIddictParameter(
+ Assert.Null((ImmutableArray?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"[""value"",{}]")));
- Assert.Null((string?[]?) new OpenIddictParameter((JsonNode?) null));
- Assert.Null((string?[]?) new OpenIddictParameter(new JsonArray("value", new JsonArray())));
- Assert.Null((string?[]?) new OpenIddictParameter(new JsonArray("value", new JsonObject())));
+ Assert.Null((ImmutableArray?) new OpenIddictParameter((JsonNode?) null));
+ Assert.Null((ImmutableArray?) new OpenIddictParameter(new JsonArray("value", new JsonArray())));
+ Assert.Null((ImmutableArray?) new OpenIddictParameter(new JsonArray("value", new JsonObject())));
}
[Fact]
public void StringArrayConverter_CanConvertFromJsonValues()
{
// Arrange, act and assert
- Assert.Equal(["Fabrikam"], (string?[]?) new OpenIddictParameter(
+ Assert.Equal?>(["Fabrikam"], (ImmutableArray?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"{""field"":""Fabrikam""}").GetProperty("field")));
+ Assert.Equal?>(["false"], (ImmutableArray?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"{""field"":false}").GetProperty("field")));
+ Assert.Equal?>(["42"], (ImmutableArray?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"{""field"":42}").GetProperty("field")));
+ Assert.Equal?>(["Fabrikam"], (ImmutableArray?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"[""Fabrikam""]")));
+ Assert.Equal?>(["Contoso", "Fabrikam"], (ImmutableArray?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"[""Contoso"",""Fabrikam""]")));
+ Assert.Equal?>(["value", "42", "true"], (ImmutableArray?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"[""value"",42,true]")));
+
+ Assert.Equal?>(["Fabrikam"], (ImmutableArray?) new OpenIddictParameter(JsonValue.Create("Fabrikam")));
+ Assert.Equal?>(["false"], (ImmutableArray?) new OpenIddictParameter(JsonValue.Create(false)));
+ Assert.Equal?>(["42"], (ImmutableArray?) new OpenIddictParameter(JsonValue.Create(42)));
+ Assert.Equal?>(["42"], (ImmutableArray?) new OpenIddictParameter(JsonValue.Create(42L)));
+ Assert.Equal?>(["Fabrikam"], (ImmutableArray?) new OpenIddictParameter(new JsonArray("Fabrikam")));
+ Assert.Equal?>(["Contoso", "Fabrikam"], (ImmutableArray?) new OpenIddictParameter(new JsonArray("Contoso", "Fabrikam")));
+ Assert.Equal?>(["value", "42", "true"], (ImmutableArray?) new OpenIddictParameter(new JsonArray("value", 42, true)));
+ }
+
+ [Fact]
+ public void StringValuesConverter_CanCreateParameterFromArray()
+ {
+ // Arrange
+ string?[] array = ["Fabrikam", "Contoso"];
+
+ // Act
+ var parameter = new OpenIddictParameter([.. array]);
+
+ // Assert
+ Assert.Equal?>(array, (StringValues?) parameter);
+ }
+
+ [Fact]
+ public void StringValuesConverter_CanCreateParameterFromPrimitiveValues()
+ {
+ // Arrange, act and assert
+ Assert.Equal?>(["Fabrikam"], (StringValues?) new OpenIddictParameter("Fabrikam"));
+ Assert.Equal?>(["false"], (StringValues?) new OpenIddictParameter(false));
+ Assert.Equal?>(["42"], (StringValues?) new OpenIddictParameter(42));
+ }
+
+ [Fact]
+ public void StringValuesConverter_ReturnsDefaultValueForNullValues()
+ {
+ // Arrange, act and assert
+ Assert.Null((StringValues?) new OpenIddictParameter());
+ }
+
+ [Fact]
+ public void StringValuesConverter_ReturnsSingleElementArrayForStringValue()
+ {
+ // Arrange, act and assert
+ Assert.Equal?>(["Fabrikam"], (StringValues?) new OpenIddictParameter("Fabrikam"));
+ }
+
+ [Fact]
+ public void StringValuesConverter_ReturnsDefaultValueForUnsupportedJsonValues()
+ {
+ // Arrange, act and assert
+ Assert.Null((StringValues?) new OpenIddictParameter(new JsonElement()));
+ Assert.Null((StringValues?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"[""value"",[]]")));
+
+ Assert.Null((StringValues?) new OpenIddictParameter(
+ JsonSerializer.Deserialize(@"[""value"",{}]")));
+
+ Assert.Null((StringValues?) new OpenIddictParameter((JsonNode?) null));
+ Assert.Null((StringValues?) new OpenIddictParameter(new JsonArray("value", new JsonArray())));
+ Assert.Null((StringValues?) new OpenIddictParameter(new JsonArray("value", new JsonObject())));
+ }
+
+ [Fact]
+ public void StringValuesConverter_CanConvertFromJsonValues()
+ {
+ // Arrange, act and assert
+ Assert.Equal?>(["Fabrikam"], (StringValues?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"{""field"":""Fabrikam""}").GetProperty("field")));
- Assert.Equal(["false"], (string?[]?) new OpenIddictParameter(
+ Assert.Equal?>(["false"], (StringValues?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"{""field"":false}").GetProperty("field")));
- Assert.Equal(["42"], (string?[]?) new OpenIddictParameter(
+ Assert.Equal?>(["42"], (StringValues?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"{""field"":42}").GetProperty("field")));
- Assert.Equal(["Fabrikam"], (string?[]?) new OpenIddictParameter(
+ Assert.Equal?>(["Fabrikam"], (StringValues?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"[""Fabrikam""]")));
- Assert.Equal(["Contoso", "Fabrikam"], (string?[]?) new OpenIddictParameter(
+ Assert.Equal?>(["Contoso", "Fabrikam"], (StringValues?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"[""Contoso"",""Fabrikam""]")));
- Assert.Equal(["value", "42", "true"], (string?[]?) new OpenIddictParameter(
+ Assert.Equal?>(["value", "42", "true"], (StringValues?) new OpenIddictParameter(
JsonSerializer.Deserialize(@"[""value"",42,true]")));
- Assert.Equal(["Fabrikam"], (string?[]?) new OpenIddictParameter(JsonValue.Create("Fabrikam")));
- Assert.Equal(["false"], (string?[]?) new OpenIddictParameter(JsonValue.Create(false)));
- Assert.Equal(["42"], (string?[]?) new OpenIddictParameter(JsonValue.Create(42)));
- Assert.Equal(["42"], (string?[]?) new OpenIddictParameter(JsonValue.Create(42L)));
- Assert.Equal(["Fabrikam"], (string?[]?) new OpenIddictParameter(new JsonArray("Fabrikam")));
- Assert.Equal(["Contoso", "Fabrikam"], (string?[]?) new OpenIddictParameter(new JsonArray("Contoso", "Fabrikam")));
- Assert.Equal