From ce33829be304c78a21db1266dd4d93bb0411cf59 Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Mon, 15 Apr 2024 11:34:12 +0200 Subject: [PATCH 01/13] Implements dynamic conversions from a JsonDynamicValue instance to commonly used runtime types. --- .../Json/Dynamic/JsonDynamicArray.cs | 41 +-- .../Json/Dynamic/JsonDynamicObject.cs | 32 +- .../Json/Dynamic/JsonDynamicValue.cs | 148 +++++++- .../ContentElement.cs | 11 +- .../Data/ContentItemTests.cs | 78 +++- .../Data/JsonDynamicTests.cs | 341 ++++++++++++++++++ 6 files changed, 574 insertions(+), 77 deletions(-) create mode 100644 test/OrchardCore.Tests/Data/JsonDynamicTests.cs diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicArray.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicArray.cs index cee0d2fd1f9..7c9032302c6 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicArray.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicArray.cs @@ -25,20 +25,8 @@ public class JsonDynamicArray : DynamicObject, IEnumerable public object? this[int index] { - get - { - var value = GetValue(index); - if (value is JsonDynamicValue jsonDynamicValue) - { - return jsonDynamicValue.JsonValue; - } - - return value; - } - set - { - SetValue(index, value); - } + get => GetValue(index); + set => SetValue(index, value); } public bool Remove(JsonNode? item) @@ -57,14 +45,7 @@ public void RemoveAt(int index) public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object? result) { - var value = GetValue((int)indexes[0]); - if (value is JsonDynamicValue jsonDynamicValue) - { - result = jsonDynamicValue.Value; - return true; - } - - result = value; + result = GetValue((int)indexes[0]); return true; } @@ -116,7 +97,7 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object?[]? args, return null; } - public void SetValue(int index, object? value, object? nodeValue = null) + public void SetValue(int index, object? value) { if (value is null) { @@ -127,8 +108,7 @@ public void SetValue(int index, object? value, object? nodeValue = null) if (value is not JsonNode) { - var jsonNode = JNode.FromObject(value); - SetValue(index, jsonNode, value); + value = JNode.FromObject(value); } if (value is JsonObject jsonObject) @@ -148,7 +128,7 @@ public void SetValue(int index, object? value, object? nodeValue = null) if (value is JsonValue jsonValue) { _jsonArray[index] = jsonValue; - _dictionary[index] = new JsonDynamicValue(jsonValue, nodeValue); + _dictionary[index] = new JsonDynamicValue(jsonValue); return; } } @@ -183,14 +163,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object? result) return false; } - var value = GetValue(index); - if (value is JsonDynamicValue jsonDynamicValue) - { - result = jsonDynamicValue.Value; - return true; - } - - result = value; + result = GetValue(index); return true; } diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs index 9e4ea95cfc5..e905d780aed 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs @@ -27,20 +27,8 @@ public void Merge(JsonNode? content, JsonMergeSettings? settings = null) => public object? this[string key] { - get - { - var value = GetValue(key); - if (value is JsonDynamicValue jsonDynamicValue) - { - return jsonDynamicValue.JsonValue; - } - - return value; - } - set - { - SetValue(key, value); - } + get => GetValue(key); + set => SetValue(key, value); } public override bool TryGetMember(GetMemberBinder binder, out object? result) @@ -57,14 +45,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object? result) return true; } - var value = GetValue(binder.Name); - if (value is JsonDynamicValue jsonDynamicValue) - { - result = jsonDynamicValue.Value; - return true; - } - - result = value; + result = GetValue(binder.Name); return true; } @@ -127,7 +108,7 @@ public bool Remove(string key) return null; } - public void SetValue(string key, object? value, object? nodeValue = null) + public void SetValue(string key, object? value) { if (value is null) { @@ -138,8 +119,7 @@ public void SetValue(string key, object? value, object? nodeValue = null) if (value is not JsonNode) { - var jsonNode = JNode.FromObject(value); - SetValue(key, jsonNode, value); + value = JNode.FromObject(value); } if (value is JsonObject jsonObject) @@ -159,7 +139,7 @@ public void SetValue(string key, object? value, object? nodeValue = null) if (value is JsonValue jsonValue) { _jsonObject[key] = jsonValue; - _dictionary[key] = new JsonDynamicValue(jsonValue, nodeValue); + _dictionary[key] = new JsonDynamicValue(jsonValue); return; } } diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index fe665c0ca12..1d4d49c0d19 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -1,35 +1,155 @@ +using System.Dynamic; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; using System.Text.Json.Nodes; namespace System.Text.Json.Dynamic; #nullable enable -public class JsonDynamicValue +public class JsonDynamicValue : DynamicObject, IConvertible { - private object? _value; - private bool _hasValue; - public JsonDynamicValue(JsonValue? jsonValue) => JsonValue = jsonValue; - public JsonDynamicValue(JsonValue? jsonValue, object? value) + public JsonValue? JsonValue { get; } + + public override DynamicMetaObject GetMetaObject(Expression parameter) { - JsonValue = jsonValue; - _value = value; + return new JsonDynamicMetaObject(parameter, this); } - public JsonValue? JsonValue { get; } + public override string ToString() => JsonValue?.ToString() ?? string.Empty; - public object? Value + TypeCode IConvertible.GetTypeCode() { - get + if (JsonValue == null) { - if (!_hasValue) + return TypeCode.Empty; + } + return TypeCode.Object; + } + + bool IConvertible.ToBoolean(IFormatProvider? provider) => (bool)this; + byte IConvertible.ToByte(IFormatProvider? provider) => (byte)this; + char IConvertible.ToChar(IFormatProvider? provider) => (char)this; + DateTime IConvertible.ToDateTime(IFormatProvider? provider) => (DateTime)this; + decimal IConvertible.ToDecimal(IFormatProvider? provider) => (decimal)this; + double IConvertible.ToDouble(IFormatProvider? provider) => (double)this; + short IConvertible.ToInt16(IFormatProvider? provider) => (short)this; + int IConvertible.ToInt32(IFormatProvider? provider) => (int)this; + long IConvertible.ToInt64(IFormatProvider? provider) => (long)this; + sbyte IConvertible.ToSByte(IFormatProvider? provider) => (sbyte)this; + float IConvertible.ToSingle(IFormatProvider? provider) => (float)this; + string IConvertible.ToString(IFormatProvider? provider) => (string?)this ?? string.Empty; + object IConvertible.ToType(Type conversionType, IFormatProvider? provider) => JsonValue?.ToObject(conversionType) ?? throw new InvalidOperationException($"Can not convert {this} to {conversionType}"); + ushort IConvertible.ToUInt16(IFormatProvider? provider) => (ushort)this; + uint IConvertible.ToUInt32(IFormatProvider? provider) => (uint)this; + ulong IConvertible.ToUInt64(IFormatProvider? provider) => (ulong)this; + + public static explicit operator bool(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Boolean"); + public static explicit operator bool?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator byte(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Byte"); + public static explicit operator byte?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator char(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Char"); + public static explicit operator char?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator DateTime(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to DateTime"); + public static explicit operator DateTime?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator DateTimeOffset(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to DateTimeOffset"); + public static explicit operator DateTimeOffset?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator decimal(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Decimal"); + public static explicit operator decimal?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator double(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Double"); + public static explicit operator double?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator Guid(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Guid"); + public static explicit operator Guid?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator short(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Int16"); + public static explicit operator short?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator int(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Int32"); + public static explicit operator int?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator long(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Int64"); + public static explicit operator long?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator sbyte(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to SByte"); + public static explicit operator sbyte?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator float(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Single"); + public static explicit operator float?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator string?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator ushort(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to UInt32"); + public static explicit operator ushort?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator uint(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to UInt32"); + public static explicit operator uint?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator ulong(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to UInt64"); + public static explicit operator ulong?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + + public static explicit operator byte[]?(JsonDynamicValue value) + { + if (value?.JsonValue.GetObjectValue() is string str) + { + return Convert.FromBase64String(str); + } + + throw new InvalidCastException($"Can not convert {value} to Byte array"); + } + + public static explicit operator TimeSpan(JsonDynamicValue value) + { + if(value?.JsonValue?.GetObjectValue() is string str) + { + return TimeSpan.Parse(str, CultureInfo.InvariantCulture); + } + + throw new InvalidCastException($"Can not convert {value} to TimeSpan"); + } + + public static explicit operator TimeSpan?(JsonDynamicValue value) + { + var str = value?.JsonValue?.GetObjectValue() as string; + + return str is null ? null : TimeSpan.Parse(str, CultureInfo.InvariantCulture); + } + + public static explicit operator Uri?(JsonDynamicValue value) => new Uri(value?.JsonValue?.GetValue() ?? string.Empty); + + private sealed class JsonDynamicMetaObject : DynamicMetaObject + { + public JsonDynamicMetaObject(Expression expression, JsonDynamicValue value) + : base(expression, BindingRestrictions.Empty, value) + { + } + + public override DynamicMetaObject BindConvert(ConvertBinder binder) + { + var targetType = binder.Type; + + var castMethod = typeof(JsonDynamicValue).GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(m => m.Name == "op_Explicit" && m.ReturnType == targetType) + .FirstOrDefault(); + + if (castMethod != null) { - _value = JsonValue?.GetObjectValue(); - _hasValue = true; + var convertExpression = Expression.Convert(Expression.Convert(Expression, typeof(JsonDynamicValue)), targetType, castMethod); + return new DynamicMetaObject(convertExpression, BindingRestrictions.GetTypeRestriction(Expression, typeof(JsonDynamicValue))); } - return _value; + // Fallback to default behavior + return base.BindConvert(binder); } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.Abstractions/ContentElement.cs b/src/OrchardCore/OrchardCore.ContentManagement.Abstractions/ContentElement.cs index f648d15b8ea..7a499911f65 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.Abstractions/ContentElement.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.Abstractions/ContentElement.cs @@ -13,6 +13,7 @@ public class ContentElement : IContent { private Dictionary _elements; private JsonDynamicObject _dynamicObject; + private JsonObject _data; protected ContentElement() : this([]) { @@ -27,7 +28,15 @@ protected ContentElement() : this([]) public dynamic Content => _dynamicObject ??= Data; [JsonIgnore] - internal JsonObject Data { get; set; } + internal JsonObject Data + { + get => _data; + set + { + _dynamicObject = null; + _data = value; + } + } [JsonIgnore] public ContentItem ContentItem { get; set; } diff --git a/test/OrchardCore.Tests/Data/ContentItemTests.cs b/test/OrchardCore.Tests/Data/ContentItemTests.cs index 860b260e025..2955aa31ce6 100644 --- a/test/OrchardCore.Tests/Data/ContentItemTests.cs +++ b/test/OrchardCore.Tests/Data/ContentItemTests.cs @@ -143,7 +143,7 @@ public void ContentShouldCanCallRemoveMethod() } [Fact] - public void ShouldDeserializeListContentPart() + public void ShouldDeserializeContentField() { var contentItem = CreateContentItemWithMyPart(); contentItem.Alter(x => x.Text = "test"); @@ -155,7 +155,71 @@ public void ShouldDeserializeListContentPart() var json = JConvert.SerializeObject(contentItem); - Assert.Contains(@"""MyPart"":{""Text"":""test"",""myField"":{""Value"":123}}", json); + var contentItem2 = JConvert.DeserializeObject(json); + + Assert.NotNull(contentItem2.Content.MyPart); + Assert.NotNull(contentItem2.Content.MyPart.myField); + Assert.Equal(123, (int)contentItem2.Content.MyPart.myField.Value); + } + + [Fact] + public void ContentShouldStoreDateTimeFields() + { + var contentItem = new ContentItem(); + contentItem.GetOrCreate(); + contentItem.Alter(x => x.Text = "test"); + contentItem.Alter(x => + { + x.GetOrCreate("myField"); + x.Alter("myField", f => f.Value = new DateTime(2024, 1, 1, 10, 42, 0)); + }); + + var json = JConvert.SerializeObject(contentItem); + + Assert.Contains(@"""MyPart"":{""Text"":""test"",""myField"":{""Value"":""2024-01-01T10:42:00""}}", json); + } + + [Fact] + public void ShouldDeserializeDateTimeFields() + { + var contentItem = new ContentItem(); + contentItem.GetOrCreate(); + contentItem.Alter(x => x.Text = "test"); + contentItem.Alter(x => + { + x.GetOrCreate("myField"); + x.Alter("myField", f => f.Value = new DateTime(2024, 1, 1, 10, 42, 0)); + }); + + var json = JConvert.SerializeObject(contentItem); + + var contentItem2 = JConvert.DeserializeObject(json); + + Assert.NotNull(contentItem2.Content.MyPart); + Assert.NotNull(contentItem2.Content.MyPart.myField); + Assert.Equal(new DateTime(2024, 1, 1, 10, 42, 0), (DateTime?)contentItem2.Content.MyPart.myField.Value); + } + + [Fact] + public void ShouldDeserializeTextFields() + { + var contentItem = new ContentItem(); + contentItem.GetOrCreate(); + contentItem.Alter(x => x.Text = "test"); + contentItem.Alter(x => + { + x.GetOrCreate("myField"); + x.Alter("myField", f => f.Text = "This is a test field entry"); + }); + + + var json = JConvert.SerializeObject(contentItem); + + var contentItem2 = JConvert.DeserializeObject(json); + + Assert.NotNull(contentItem2.Content.MyPart); + Assert.NotNull(contentItem2.Content.MyPart.myField); + Assert.Equal("This is a test field entry", (string)contentItem2.Content.MyPart.myField.Text); } private static ContentItem CreateContentItemWithMyPart(string text = "test") @@ -185,6 +249,16 @@ public class MyField : ContentField public int Value { get; set; } } + public class MyDateTimeField : ContentField + { + public DateTime? Value { get; set; } + } + + public class MyTextField : ContentField + { + public string Text { get; set; } + } + public class GetOnlyListPart : ContentPart { public IList Texts { get; } = new List(); diff --git a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs new file mode 100644 index 00000000000..225559aee94 --- /dev/null +++ b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs @@ -0,0 +1,341 @@ +using System.Text.Json.Dynamic; +using System.Text.Json.Nodes; + +namespace OrchardCore.Tests.Data +{ + public class JsonDynamicTests + { + [Fact] + public void JsonDynamicValueMustConvertToBool() + { + const bool expectedValue = true; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (bool)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableBool() + { + bool? expectedValue = true; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (bool?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToByte() + { + const byte expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (byte)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableBye() + { + byte? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (byte?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToChar() + { + const char expectedValue = 'A'; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (char)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableChar() + { + char? expectedValue = 'B'; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (char?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDateTime() + { + var expectedValue = DateTime.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTime)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableDateTime() + { + DateTime? expectedValue = DateTime.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTime?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDateTimeOffset() + { + DateTimeOffset expectedValue = DateTimeOffset.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTimeOffset)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullablDateTimeOffset() + { + DateTimeOffset? expectedValue = DateTimeOffset.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTimeOffset?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDecimal() + { + decimal expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (decimal)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableDecimal() + { + decimal? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (decimal?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDouble() + { + double expectedValue = 42.42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (double)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableDouble() + { + double? expectedValue = 42.42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (double?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToGuid() + { + Guid expectedValue = Guid.NewGuid(); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (Guid)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableGuid() + { + Guid? expectedValue = Guid.NewGuid(); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (Guid?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToInt16() + { + short expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (short)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableInt16() + { + short? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (short?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToInt32() + { + int expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (int)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableInt32() + { + int? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (int?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToInt64() + { + long expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (long)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableInt64() + { + long? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (long?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToSByte() + { + sbyte expectedValue = -42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (sbyte)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableSByte() + { + sbyte? expectedValue = -42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (sbyte?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToSingle() + { + float expectedValue = 42.42F; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (float)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableSingle() + { + float? expectedValue = 42.42F; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (float?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToString() + { + string expectedValue = "A test string value"; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (string)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUInt16() + { + ushort expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ushort)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableUInt16() + { + ushort? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ushort?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUInt32() + { + uint expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (uint)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableUInt32() + { + uint? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (uint?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUInt64() + { + ulong expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ulong)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableUInt64() + { + ulong? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ulong?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToByteArray() + { + var expectedValue = Encoding.UTF8.GetBytes("A string in a byte array"); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (byte[])myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToTimeSpan() + { + TimeSpan expectedValue = TimeSpan.FromSeconds(42); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); + + Assert.Equal(expectedValue, (TimeSpan)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableTimeSpan() + { + TimeSpan expectedValue = TimeSpan.FromSeconds(42); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); + + Assert.Equal(expectedValue, (TimeSpan?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUri() + { + Uri expectedValue = new Uri("https://www.example.com"); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); + + Assert.Equal(expectedValue, (Uri)myDynamic); + } + } +} From aef368fd5610bff9b3846cd89bf229b364c0656c Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 24 Apr 2024 07:43:14 -0700 Subject: [PATCH 02/13] Formatting cleanup --- .../Json/Dynamic/JsonDynamicValue.cs | 220 ++++-- .../Data/JsonDynamicTests.cs | 669 +++++++++--------- 2 files changed, 494 insertions(+), 395 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 1d4d49c0d19..4b7108c9c95 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -16,11 +16,10 @@ public class JsonDynamicValue : DynamicObject, IConvertible public JsonValue? JsonValue { get; } public override DynamicMetaObject GetMetaObject(Expression parameter) - { - return new JsonDynamicMetaObject(parameter, this); - } - - public override string ToString() => JsonValue?.ToString() ?? string.Empty; + => new JsonDynamicMetaObject(parameter, this); + + public override string ToString() + => JsonValue?.ToString() ?? string.Empty; TypeCode IConvertible.GetTypeCode() { @@ -28,75 +27,173 @@ TypeCode IConvertible.GetTypeCode() { return TypeCode.Empty; } + return TypeCode.Object; } - bool IConvertible.ToBoolean(IFormatProvider? provider) => (bool)this; - byte IConvertible.ToByte(IFormatProvider? provider) => (byte)this; - char IConvertible.ToChar(IFormatProvider? provider) => (char)this; - DateTime IConvertible.ToDateTime(IFormatProvider? provider) => (DateTime)this; - decimal IConvertible.ToDecimal(IFormatProvider? provider) => (decimal)this; - double IConvertible.ToDouble(IFormatProvider? provider) => (double)this; - short IConvertible.ToInt16(IFormatProvider? provider) => (short)this; - int IConvertible.ToInt32(IFormatProvider? provider) => (int)this; - long IConvertible.ToInt64(IFormatProvider? provider) => (long)this; - sbyte IConvertible.ToSByte(IFormatProvider? provider) => (sbyte)this; - float IConvertible.ToSingle(IFormatProvider? provider) => (float)this; - string IConvertible.ToString(IFormatProvider? provider) => (string?)this ?? string.Empty; - object IConvertible.ToType(Type conversionType, IFormatProvider? provider) => JsonValue?.ToObject(conversionType) ?? throw new InvalidOperationException($"Can not convert {this} to {conversionType}"); - ushort IConvertible.ToUInt16(IFormatProvider? provider) => (ushort)this; - uint IConvertible.ToUInt32(IFormatProvider? provider) => (uint)this; - ulong IConvertible.ToUInt64(IFormatProvider? provider) => (ulong)this; + bool IConvertible.ToBoolean(IFormatProvider? provider) + => (bool)this; + + byte IConvertible.ToByte(IFormatProvider? provider) + => (byte)this; + + char IConvertible.ToChar(IFormatProvider? provider) + => (char)this; + + DateTime IConvertible.ToDateTime(IFormatProvider? provider) + => (DateTime)this; + + decimal IConvertible.ToDecimal(IFormatProvider? provider) + => (decimal)this; + + double IConvertible.ToDouble(IFormatProvider? provider) + => (double)this; + + short IConvertible.ToInt16(IFormatProvider? provider) + => (short)this; + + int IConvertible.ToInt32(IFormatProvider? provider) + => (int)this; + + long IConvertible.ToInt64(IFormatProvider? provider) + => (long)this; + + sbyte IConvertible.ToSByte(IFormatProvider? provider) + => (sbyte)this; + + float IConvertible.ToSingle(IFormatProvider? provider) + => (float)this; + + string IConvertible.ToString(IFormatProvider? provider) + => (string?)this ?? string.Empty; + + object IConvertible.ToType(Type conversionType, IFormatProvider? provider) + => JsonValue?.ToObject(conversionType) + ?? throw new InvalidOperationException($"Cannot convert {this} to {conversionType}"); + + ushort IConvertible.ToUInt16(IFormatProvider? provider) + => (ushort)this; + + uint IConvertible.ToUInt32(IFormatProvider? provider) + => (uint)this; + + ulong IConvertible.ToUInt64(IFormatProvider? provider) + => (ulong)this; + + public static explicit operator bool(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Boolean"); + + public static explicit operator bool?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator byte(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Byte"); + + public static explicit operator byte?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator char(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Char"); + + public static explicit operator char?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator DateTime(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to DateTime"); + + public static explicit operator DateTime?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator DateTimeOffset(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to DateTimeOffset"); + + public static explicit operator DateTimeOffset?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator decimal(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Decimal"); + + public static explicit operator decimal?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator double(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Double"); + + public static explicit operator double?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); + + public static explicit operator Guid(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Guid"); + + public static explicit operator Guid?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator bool(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Boolean"); - public static explicit operator bool?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator short(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Int16"); - public static explicit operator byte(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Byte"); - public static explicit operator byte?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator short?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator char(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Char"); - public static explicit operator char?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator int(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Int32"); - public static explicit operator DateTime(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to DateTime"); - public static explicit operator DateTime?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator int?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator DateTimeOffset(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to DateTimeOffset"); - public static explicit operator DateTimeOffset?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator long(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Int64"); - public static explicit operator decimal(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Decimal"); - public static explicit operator decimal?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator long?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator double(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Double"); - public static explicit operator double?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator sbyte(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to SByte"); - public static explicit operator Guid(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Guid"); - public static explicit operator Guid?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator sbyte?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator short(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Int16"); - public static explicit operator short?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator float(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Float"); - public static explicit operator int(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Int32"); - public static explicit operator int?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator float?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator long(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Int64"); - public static explicit operator long?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator string?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator sbyte(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to SByte"); - public static explicit operator sbyte?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator ushort(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); - public static explicit operator float(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to Single"); - public static explicit operator float?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator ushort?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator string?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator uint(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); - public static explicit operator ushort(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to UInt32"); - public static explicit operator ushort?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator uint?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); - public static explicit operator uint(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to UInt32"); - public static explicit operator uint?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator ulong(JsonDynamicValue value) + => value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to UInt64"); - public static explicit operator ulong(JsonDynamicValue value) => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Can not convert {value} to UInt64"); - public static explicit operator ulong?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); + public static explicit operator ulong?(JsonDynamicValue value) + => value?.JsonValue?.GetValue(); public static explicit operator byte[]?(JsonDynamicValue value) { @@ -105,27 +202,30 @@ TypeCode IConvertible.GetTypeCode() return Convert.FromBase64String(str); } - throw new InvalidCastException($"Can not convert {value} to Byte array"); + throw new InvalidCastException($"Cannot convert {value} to Byte array"); } public static explicit operator TimeSpan(JsonDynamicValue value) { - if(value?.JsonValue?.GetObjectValue() is string str) + if (value?.JsonValue?.GetObjectValue() is string str) { return TimeSpan.Parse(str, CultureInfo.InvariantCulture); } - throw new InvalidCastException($"Can not convert {value} to TimeSpan"); + throw new InvalidCastException($"Cannot convert {value} to TimeSpan"); } public static explicit operator TimeSpan?(JsonDynamicValue value) { var str = value?.JsonValue?.GetObjectValue() as string; - return str is null ? null : TimeSpan.Parse(str, CultureInfo.InvariantCulture); + return str is not null + ? TimeSpan.Parse(str, CultureInfo.InvariantCulture) + : null; } - public static explicit operator Uri?(JsonDynamicValue value) => new Uri(value?.JsonValue?.GetValue() ?? string.Empty); + public static explicit operator Uri?(JsonDynamicValue value) + => new Uri(value?.JsonValue?.GetValue() ?? string.Empty); private sealed class JsonDynamicMetaObject : DynamicMetaObject { @@ -148,7 +248,7 @@ public override DynamicMetaObject BindConvert(ConvertBinder binder) return new DynamicMetaObject(convertExpression, BindingRestrictions.GetTypeRestriction(Expression, typeof(JsonDynamicValue))); } - // Fallback to default behavior + // Fallback to default behavior. return base.BindConvert(binder); } } diff --git a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs index 225559aee94..90fafd03ca9 100644 --- a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs +++ b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs @@ -1,341 +1,340 @@ using System.Text.Json.Dynamic; using System.Text.Json.Nodes; -namespace OrchardCore.Tests.Data +namespace OrchardCore.Tests.Data; + +public class JsonDynamicTests { - public class JsonDynamicTests - { - [Fact] - public void JsonDynamicValueMustConvertToBool() - { - const bool expectedValue = true; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (bool)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableBool() - { - bool? expectedValue = true; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (bool?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToByte() - { - const byte expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (byte)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableBye() - { - byte? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (byte?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToChar() - { - const char expectedValue = 'A'; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (char)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableChar() - { - char? expectedValue = 'B'; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (char?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToDateTime() - { - var expectedValue = DateTime.UtcNow; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (DateTime)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableDateTime() - { - DateTime? expectedValue = DateTime.UtcNow; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (DateTime?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToDateTimeOffset() - { - DateTimeOffset expectedValue = DateTimeOffset.UtcNow; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (DateTimeOffset)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullablDateTimeOffset() - { - DateTimeOffset? expectedValue = DateTimeOffset.UtcNow; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (DateTimeOffset?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToDecimal() - { - decimal expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (decimal)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableDecimal() - { - decimal? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (decimal?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToDouble() - { - double expectedValue = 42.42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (double)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableDouble() - { - double? expectedValue = 42.42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (double?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToGuid() - { - Guid expectedValue = Guid.NewGuid(); - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (Guid)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableGuid() - { - Guid? expectedValue = Guid.NewGuid(); - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (Guid?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToInt16() - { - short expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (short)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableInt16() - { - short? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (short?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToInt32() - { - int expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (int)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableInt32() - { - int? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (int?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToInt64() - { - long expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (long)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableInt64() - { - long? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (long?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToSByte() - { - sbyte expectedValue = -42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (sbyte)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableSByte() - { - sbyte? expectedValue = -42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (sbyte?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToSingle() - { - float expectedValue = 42.42F; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (float)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableSingle() - { - float? expectedValue = 42.42F; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (float?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToString() - { - string expectedValue = "A test string value"; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (string)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToUInt16() - { - ushort expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (ushort)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableUInt16() - { - ushort? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (ushort?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToUInt32() - { - uint expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (uint)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableUInt32() - { - uint? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (uint?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToUInt64() - { - ulong expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (ulong)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableUInt64() - { - ulong? expectedValue = 42; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (ulong?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToByteArray() - { - var expectedValue = Encoding.UTF8.GetBytes("A string in a byte array"); - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.Equal(expectedValue, (byte[])myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToTimeSpan() - { - TimeSpan expectedValue = TimeSpan.FromSeconds(42); - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); - - Assert.Equal(expectedValue, (TimeSpan)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToNullableTimeSpan() - { - TimeSpan expectedValue = TimeSpan.FromSeconds(42); - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); - - Assert.Equal(expectedValue, (TimeSpan?)myDynamic); - } - - [Fact] - public void JsonDynamicValueMustConvertToUri() - { - Uri expectedValue = new Uri("https://www.example.com"); - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); - - Assert.Equal(expectedValue, (Uri)myDynamic); - } + [Fact] + public void JsonDynamicValueMustConvertToBool() + { + var bool expectedValue = true; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (bool)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableBool() + { + bool? expectedValue = true; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (bool?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToByte() + { + byte expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (byte)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableBye() + { + byte? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (byte?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToChar() + { + var expectedValue = 'A'; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (char)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableChar() + { + char? expectedValue = 'B'; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (char?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDateTime() + { + var expectedValue = DateTime.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTime)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableDateTime() + { + DateTime? expectedValue = DateTime.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTime?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDateTimeOffset() + { + DateTimeOffset expectedValue = DateTimeOffset.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTimeOffset)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullablDateTimeOffset() + { + DateTimeOffset? expectedValue = DateTimeOffset.UtcNow; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (DateTimeOffset?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDecimal() + { + decimal expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (decimal)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableDecimal() + { + decimal? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (decimal?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToDouble() + { + double expectedValue = 42.42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (double)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableDouble() + { + double? expectedValue = 42.42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (double?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToGuid() + { + Guid expectedValue = Guid.NewGuid(); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (Guid)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableGuid() + { + Guid? expectedValue = Guid.NewGuid(); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (Guid?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToInt16() + { + short expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (short)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableInt16() + { + short? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (short?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToInt32() + { + int expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (int)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableInt32() + { + int? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (int?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToInt64() + { + long expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (long)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableInt64() + { + long? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (long?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToSByte() + { + sbyte expectedValue = -42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (sbyte)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableSByte() + { + sbyte? expectedValue = -42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (sbyte?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToSingle() + { + float expectedValue = 42.42F; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (float)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableSingle() + { + float? expectedValue = 42.42F; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (float?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToString() + { + var expectedValue = "A test string value"; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (string)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUInt16() + { + ushort expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ushort)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableUInt16() + { + ushort? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ushort?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUInt32() + { + uint expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (uint)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableUInt32() + { + uint? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (uint?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUInt64() + { + ulong expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ulong)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableUInt64() + { + ulong? expectedValue = 42; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (ulong?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToByteArray() + { + var expectedValue = Encoding.UTF8.GetBytes("A string in a byte array"); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.Equal(expectedValue, (byte[])myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToTimeSpan() + { + var expectedValue = TimeSpan.FromSeconds(42); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); + + Assert.Equal(expectedValue, (TimeSpan)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToNullableTimeSpan() + { + var expectedValue = TimeSpan.FromSeconds(42); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); + + Assert.Equal(expectedValue, (TimeSpan?)myDynamic); + } + + [Fact] + public void JsonDynamicValueMustConvertToUri() + { + var expectedValue = new Uri("https://www.orchardcore.net"); + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue.ToString())); + + Assert.Equal(expectedValue, (Uri)myDynamic); } } From 008cd5de61e1798b8c1e71937f760c166e3bc2eb Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 24 Apr 2024 08:13:22 -0700 Subject: [PATCH 03/13] fix build --- test/OrchardCore.Tests/Data/ContentItemTests.cs | 1 - test/OrchardCore.Tests/Data/JsonDynamicTests.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/OrchardCore.Tests/Data/ContentItemTests.cs b/test/OrchardCore.Tests/Data/ContentItemTests.cs index 2955aa31ce6..d1a77fc1cbf 100644 --- a/test/OrchardCore.Tests/Data/ContentItemTests.cs +++ b/test/OrchardCore.Tests/Data/ContentItemTests.cs @@ -212,7 +212,6 @@ public void ShouldDeserializeTextFields() x.Alter("myField", f => f.Text = "This is a test field entry"); }); - var json = JConvert.SerializeObject(contentItem); var contentItem2 = JConvert.DeserializeObject(json); diff --git a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs index 90fafd03ca9..5060531a1d8 100644 --- a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs +++ b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs @@ -8,7 +8,7 @@ public class JsonDynamicTests [Fact] public void JsonDynamicValueMustConvertToBool() { - var bool expectedValue = true; + var expectedValue = true; dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); Assert.Equal(expectedValue, (bool)myDynamic); From 3ea7384005a5994766f2b9bde6380c7dc955a29b Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Thu, 25 Apr 2024 14:11:30 +0200 Subject: [PATCH 04/13] Added missing ToString() overloads. --- .../Json/Dynamic/JsonDynamicValue.cs | 170 ++++++++++-------- 1 file changed, 97 insertions(+), 73 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 4b7108c9c95..ffc8a0be74e 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -17,10 +17,34 @@ public class JsonDynamicValue : DynamicObject, IConvertible public override DynamicMetaObject GetMetaObject(Expression parameter) => new JsonDynamicMetaObject(parameter, this); - - public override string ToString() + + public override string ToString() => JsonValue?.ToString() ?? string.Empty; + public string ToString(string format) + => ToString(format, CultureInfo.CurrentCulture); + + public string ToString(IFormatProvider? formatProvider) + => ToString(null, formatProvider); + + public string ToString(string? format, IFormatProvider? formatProvider) + { + if (JsonValue == null) + { + return string.Empty; + } + + var value = JsonValue.GetObjectValue(); + if (value is IFormattable formattable) + { + return formattable.ToString(format, formatProvider); + } + else + { + return value?.ToString() ?? string.Empty; + } + } + TypeCode IConvertible.GetTypeCode() { if (JsonValue == null) @@ -31,168 +55,168 @@ TypeCode IConvertible.GetTypeCode() return TypeCode.Object; } - bool IConvertible.ToBoolean(IFormatProvider? provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) => (bool)this; - byte IConvertible.ToByte(IFormatProvider? provider) + byte IConvertible.ToByte(IFormatProvider? provider) => (byte)this; - char IConvertible.ToChar(IFormatProvider? provider) + char IConvertible.ToChar(IFormatProvider? provider) => (char)this; - DateTime IConvertible.ToDateTime(IFormatProvider? provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) => (DateTime)this; - decimal IConvertible.ToDecimal(IFormatProvider? provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) => (decimal)this; - double IConvertible.ToDouble(IFormatProvider? provider) + double IConvertible.ToDouble(IFormatProvider? provider) => (double)this; - short IConvertible.ToInt16(IFormatProvider? provider) + short IConvertible.ToInt16(IFormatProvider? provider) => (short)this; - int IConvertible.ToInt32(IFormatProvider? provider) + int IConvertible.ToInt32(IFormatProvider? provider) => (int)this; - long IConvertible.ToInt64(IFormatProvider? provider) + long IConvertible.ToInt64(IFormatProvider? provider) => (long)this; - sbyte IConvertible.ToSByte(IFormatProvider? provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) => (sbyte)this; - float IConvertible.ToSingle(IFormatProvider? provider) + float IConvertible.ToSingle(IFormatProvider? provider) => (float)this; - string IConvertible.ToString(IFormatProvider? provider) + string IConvertible.ToString(IFormatProvider? provider) => (string?)this ?? string.Empty; - object IConvertible.ToType(Type conversionType, IFormatProvider? provider) - => JsonValue?.ToObject(conversionType) + object IConvertible.ToType(Type conversionType, IFormatProvider? provider) + => JsonValue?.ToObject(conversionType) ?? throw new InvalidOperationException($"Cannot convert {this} to {conversionType}"); - ushort IConvertible.ToUInt16(IFormatProvider? provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) => (ushort)this; - uint IConvertible.ToUInt32(IFormatProvider? provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) => (uint)this; - ulong IConvertible.ToUInt64(IFormatProvider? provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) => (ulong)this; - public static explicit operator bool(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator bool(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Boolean"); - public static explicit operator bool?(JsonDynamicValue value) + public static explicit operator bool?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator byte(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator byte(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Byte"); - - public static explicit operator byte?(JsonDynamicValue value) + + public static explicit operator byte?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator char(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator char(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Char"); - public static explicit operator char?(JsonDynamicValue value) + public static explicit operator char?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator DateTime(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator DateTime(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to DateTime"); - - public static explicit operator DateTime?(JsonDynamicValue value) + + public static explicit operator DateTime?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator DateTimeOffset(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator DateTimeOffset(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to DateTimeOffset"); - public static explicit operator DateTimeOffset?(JsonDynamicValue value) + public static explicit operator DateTimeOffset?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator decimal(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator decimal(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Decimal"); - public static explicit operator decimal?(JsonDynamicValue value) + public static explicit operator decimal?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator double(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator double(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Double"); - public static explicit operator double?(JsonDynamicValue value) + public static explicit operator double?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator Guid(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator Guid(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Guid"); - - public static explicit operator Guid?(JsonDynamicValue value) + + public static explicit operator Guid?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator short(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator short(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Int16"); - public static explicit operator short?(JsonDynamicValue value) + public static explicit operator short?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator int(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator int(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Int32"); - public static explicit operator int?(JsonDynamicValue value) + public static explicit operator int?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator long(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator long(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Int64"); public static explicit operator long?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator sbyte(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator sbyte(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to SByte"); - public static explicit operator sbyte?(JsonDynamicValue value) + public static explicit operator sbyte?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator float(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator float(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to Float"); - public static explicit operator float?(JsonDynamicValue value) + public static explicit operator float?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator string?(JsonDynamicValue value) + public static explicit operator string?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator ushort(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator ushort(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); - public static explicit operator ushort?(JsonDynamicValue value) + public static explicit operator ushort?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator uint(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator uint(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); - public static explicit operator uint?(JsonDynamicValue value) + public static explicit operator uint?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); - public static explicit operator ulong(JsonDynamicValue value) - => value?.JsonValue?.GetValue() + public static explicit operator ulong(JsonDynamicValue value) + => value?.JsonValue?.GetValue() ?? throw new InvalidCastException($"Cannot convert {value} to UInt64"); - public static explicit operator ulong?(JsonDynamicValue value) + public static explicit operator ulong?(JsonDynamicValue value) => value?.JsonValue?.GetValue(); public static explicit operator byte[]?(JsonDynamicValue value) @@ -219,12 +243,12 @@ public static explicit operator TimeSpan(JsonDynamicValue value) { var str = value?.JsonValue?.GetObjectValue() as string; - return str is not null - ? TimeSpan.Parse(str, CultureInfo.InvariantCulture) + return str is not null + ? TimeSpan.Parse(str, CultureInfo.InvariantCulture) : null; } - public static explicit operator Uri?(JsonDynamicValue value) + public static explicit operator Uri?(JsonDynamicValue value) => new Uri(value?.JsonValue?.GetValue() ?? string.Empty); private sealed class JsonDynamicMetaObject : DynamicMetaObject From 81cb5f6c83bba81e6e68d42bddfc09edc4211e72 Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Thu, 25 Apr 2024 14:37:13 +0200 Subject: [PATCH 05/13] Adds the Value property back to JsonDynamicValue. --- .../Json/Dynamic/JsonDynamicValue.cs | 3 +++ test/OrchardCore.Tests/Data/JsonDynamicTests.cs | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index ffc8a0be74e..305e6484792 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -18,6 +18,9 @@ public class JsonDynamicValue : DynamicObject, IConvertible public override DynamicMetaObject GetMetaObject(Expression parameter) => new JsonDynamicMetaObject(parameter, this); + public object? Value + => JsonValue?.GetObjectValue(); + public override string ToString() => JsonValue?.ToString() ?? string.Empty; diff --git a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs index 5060531a1d8..4b8513b5d8f 100644 --- a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs +++ b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs @@ -337,4 +337,14 @@ public void JsonDynamicValueMustConvertToUri() Assert.Equal(expectedValue, (Uri)myDynamic); } + + [Fact] + public void JsonDynamicValueHasValue() + { + var expectedValue = "A test string value"; + dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); + + Assert.NotNull(myDynamic.Value); + Assert.Equal(expectedValue, myDynamic.Value); + } } From 75bc4d6319b99ef0c59e9aa20dc9407d5ab44c25 Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Thu, 25 Apr 2024 14:46:06 +0200 Subject: [PATCH 06/13] Formatting. --- .../Json/Dynamic/JsonDynamicValue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 305e6484792..16818a0fb2d 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -15,12 +15,12 @@ public class JsonDynamicValue : DynamicObject, IConvertible public JsonValue? JsonValue { get; } - public override DynamicMetaObject GetMetaObject(Expression parameter) - => new JsonDynamicMetaObject(parameter, this); - public object? Value => JsonValue?.GetObjectValue(); + public override DynamicMetaObject GetMetaObject(Expression parameter) + => new JsonDynamicMetaObject(parameter, this); + public override string ToString() => JsonValue?.ToString() ?? string.Empty; From ee258498bab56a279d09d7901b634343237d0cfa Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Mon, 6 May 2024 12:53:51 +0200 Subject: [PATCH 07/13] Added unit test for serializing/deserializing UTC date time values in content fields. --- .../Data/ContentItemTests.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/OrchardCore.Tests/Data/ContentItemTests.cs b/test/OrchardCore.Tests/Data/ContentItemTests.cs index d1a77fc1cbf..325cd2783fb 100644 --- a/test/OrchardCore.Tests/Data/ContentItemTests.cs +++ b/test/OrchardCore.Tests/Data/ContentItemTests.cs @@ -200,6 +200,44 @@ public void ShouldDeserializeDateTimeFields() Assert.Equal(new DateTime(2024, 1, 1, 10, 42, 0), (DateTime?)contentItem2.Content.MyPart.myField.Value); } + [Fact] + public void ContentShouldStoreUtcDateTimeFields() + { + var contentItem = new ContentItem(); + contentItem.GetOrCreate(); + contentItem.Alter(x => x.Text = "test"); + contentItem.Alter(x => + { + x.GetOrCreate("myField"); + x.Alter("myField", f => f.Value = new DateTime(2024, 1, 1, 10, 42, 0, DateTimeKind.Utc)); + }); + + var json = JConvert.SerializeObject(contentItem); + + Assert.Contains(@"""MyPart"":{""Text"":""test"",""myField"":{""Value"":""2024-01-01T10:42:00Z""}}", json); + } + + [Fact] + public void ShouldDeserializeUtcDateTimeFields() + { + var contentItem = new ContentItem(); + contentItem.GetOrCreate(); + contentItem.Alter(x => x.Text = "test"); + contentItem.Alter(x => + { + x.GetOrCreate("myField"); + x.Alter("myField", f => f.Value = new DateTime(2024, 1, 1, 10, 42, 0, DateTimeKind.Utc)); + }); + + var json = JConvert.SerializeObject(contentItem); + + var contentItem2 = JConvert.DeserializeObject(json); + + Assert.NotNull(contentItem2.Content.MyPart); + Assert.NotNull(contentItem2.Content.MyPart.myField); + Assert.Equal(new DateTime(2024, 1, 1, 10, 42, 0, DateTimeKind.Utc), (DateTime?)contentItem2.Content.MyPart.myField.Value); + } + [Fact] public void ShouldDeserializeTextFields() { From d4d2251e5a8e44bfd5f416db488e09e84f96d84f Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Mon, 6 May 2024 13:44:14 +0200 Subject: [PATCH 08/13] Caches reflection information. --- .../Json/Dynamic/JsonDynamicValue.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 16818a0fb2d..3a031d37cb4 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Dynamic; using System.Globalization; using System.Linq; @@ -256,20 +257,29 @@ public static explicit operator TimeSpan(JsonDynamicValue value) private sealed class JsonDynamicMetaObject : DynamicMetaObject { + private static readonly Dictionary _cachedReflectionInfo = typeof(JsonDynamicValue) + .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(method => method.Name == "op_Explicit") + .ToDictionary(method => method.ReturnType); + public JsonDynamicMetaObject(Expression expression, JsonDynamicValue value) : base(expression, BindingRestrictions.Empty, value) { } + // BindConvert() is automatically invoked to handle type conversion when casting dynamic types + // to static types in C#. For example, when extracting a DateTime value from a dynamically typed + // content item's field: + // + // dynamic contentItem = [...]; // Assume contentItem is initialized properly + // + // // BindConvert() is called implicitly to convert contentItem.Content.MyPart.MyField.Value to DateTime + // var dateTimeValue = (DateTime)contentItem.Content.MyPart.MyField.Value; public override DynamicMetaObject BindConvert(ConvertBinder binder) { var targetType = binder.Type; - var castMethod = typeof(JsonDynamicValue).GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(m => m.Name == "op_Explicit" && m.ReturnType == targetType) - .FirstOrDefault(); - - if (castMethod != null) + if (_cachedReflectionInfo.TryGetValue(targetType, out var castMethod)) { var convertExpression = Expression.Convert(Expression.Convert(Expression, typeof(JsonDynamicValue)), targetType, castMethod); return new DynamicMetaObject(convertExpression, BindingRestrictions.GetTypeRestriction(Expression, typeof(JsonDynamicValue))); From 0d7b4a5e56a54c28894478a535bf1b0a0b610210 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 6 May 2024 08:20:22 -0700 Subject: [PATCH 09/13] cleanup --- .../Json/Dynamic/JsonDynamicValue.cs | 11 ++++++++--- test/OrchardCore.Tests/Data/ContentItemTests.cs | 12 ++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 3a031d37cb4..c4aee784c5c 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -267,13 +267,17 @@ public JsonDynamicMetaObject(Expression expression, JsonDynamicValue value) { } - // BindConvert() is automatically invoked to handle type conversion when casting dynamic types - // to static types in C#. For example, when extracting a DateTime value from a dynamically typed + + // The 'BindConvert()' method is automatically invoked to handle type conversion when casting + // dynamic types to static types in C#. + // + // For example, when extracting a 'DateTime' value from a dynamically typed // content item's field: // // dynamic contentItem = [...]; // Assume contentItem is initialized properly // - // // BindConvert() is called implicitly to convert contentItem.Content.MyPart.MyField.Value to DateTime + // 'BindConvert()' is called implicitly to convert contentItem.Content.MyPart.MyField.Value + // to 'DateTime' with similar behavior to the following: // var dateTimeValue = (DateTime)contentItem.Content.MyPart.MyField.Value; public override DynamicMetaObject BindConvert(ConvertBinder binder) { @@ -282,6 +286,7 @@ public override DynamicMetaObject BindConvert(ConvertBinder binder) if (_cachedReflectionInfo.TryGetValue(targetType, out var castMethod)) { var convertExpression = Expression.Convert(Expression.Convert(Expression, typeof(JsonDynamicValue)), targetType, castMethod); + return new DynamicMetaObject(convertExpression, BindingRestrictions.GetTypeRestriction(Expression, typeof(JsonDynamicValue))); } diff --git a/test/OrchardCore.Tests/Data/ContentItemTests.cs b/test/OrchardCore.Tests/Data/ContentItemTests.cs index 325cd2783fb..f7dd3f35cd5 100644 --- a/test/OrchardCore.Tests/Data/ContentItemTests.cs +++ b/test/OrchardCore.Tests/Data/ContentItemTests.cs @@ -276,28 +276,28 @@ private static void AssertJsonEqual(JsonNode expected, JsonNode actual) } } - public class MyPart : ContentPart + public sealed class MyPart : ContentPart { public string Text { get; set; } } - public class MyField : ContentField + public sealed class MyField : ContentField { public int Value { get; set; } } - public class MyDateTimeField : ContentField + public sealed class MyDateTimeField : ContentField { public DateTime? Value { get; set; } } - public class MyTextField : ContentField + public sealed class MyTextField : ContentField { public string Text { get; set; } } - public class GetOnlyListPart : ContentPart + public sealed class GetOnlyListPart : ContentPart { - public IList Texts { get; } = new List(); + public IList Texts { get; } = []; } } From 447fd3d0c0cdebd8352f231c85400ba614b5f252 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 9 May 2024 12:36:13 -0700 Subject: [PATCH 10/13] use frozen dictionary --- .../Json/Dynamic/JsonDynamicValue.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index c4aee784c5c..37351c875ff 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Frozen; using System.Dynamic; using System.Globalization; using System.Linq; @@ -253,14 +253,14 @@ public static explicit operator TimeSpan(JsonDynamicValue value) } public static explicit operator Uri?(JsonDynamicValue value) - => new Uri(value?.JsonValue?.GetValue() ?? string.Empty); + => new(value?.JsonValue?.GetValue() ?? string.Empty); private sealed class JsonDynamicMetaObject : DynamicMetaObject { - private static readonly Dictionary _cachedReflectionInfo = typeof(JsonDynamicValue) + private static readonly FrozenDictionary _cachedReflectionInfo = typeof(JsonDynamicValue) .GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(method => method.Name == "op_Explicit") - .ToDictionary(method => method.ReturnType); + .ToFrozenDictionary(method => method.ReturnType); public JsonDynamicMetaObject(Expression expression, JsonDynamicValue value) : base(expression, BindingRestrictions.Empty, value) From d3bddb9f7f03cb4c3f98bcc47d341c7f99ed72d5 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 10 May 2024 15:56:23 -0700 Subject: [PATCH 11/13] Fix methodinfo cache initialization --- .../Json/Dynamic/JsonDynamicObject.cs | 14 +- .../Json/Dynamic/JsonDynamicValue.cs | 262 +++++++++++++----- 2 files changed, 196 insertions(+), 80 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs index df1b4ed1709..432285a9b97 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicObject.cs @@ -16,14 +16,22 @@ public class JsonDynamicObject : DynamicObject private readonly Dictionary _dictionary = []; - public JsonDynamicObject() => _jsonObject = []; + public JsonDynamicObject() + { + _jsonObject = []; + } - public JsonDynamicObject(JsonObject jsonObject) => _jsonObject = jsonObject; + public JsonDynamicObject(JsonObject jsonObject) + { + _jsonObject = jsonObject; + } public int Count => _jsonObject.Count; - public void Merge(JsonNode? content, JsonMergeSettings? settings = null) => + public void Merge(JsonNode? content, JsonMergeSettings? settings = null) + { _jsonObject.Merge(content, settings); + } public object? this[string key] { diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 37351c875ff..45be0fae42b 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -12,24 +12,32 @@ namespace System.Text.Json.Dynamic; public class JsonDynamicValue : DynamicObject, IConvertible { - public JsonDynamicValue(JsonValue? jsonValue) => JsonValue = jsonValue; + public JsonDynamicValue(JsonValue? jsonValue) + { + JsonValue = jsonValue; + } public JsonValue? JsonValue { get; } - public object? Value - => JsonValue?.GetObjectValue(); - public override DynamicMetaObject GetMetaObject(Expression parameter) - => new JsonDynamicMetaObject(parameter, this); + { + return new JsonDynamicMetaObject(parameter, this); + } public override string ToString() - => JsonValue?.ToString() ?? string.Empty; + { + return JsonValue?.ToString() ?? string.Empty; + } public string ToString(string format) - => ToString(format, CultureInfo.CurrentCulture); + { + return ToString(format, CultureInfo.CurrentCulture); + } public string ToString(IFormatProvider? formatProvider) - => ToString(null, formatProvider); + { + return ToString(null, formatProvider); + } public string ToString(string? format, IFormatProvider? formatProvider) { @@ -60,168 +68,266 @@ TypeCode IConvertible.GetTypeCode() } bool IConvertible.ToBoolean(IFormatProvider? provider) - => (bool)this; + { + return (bool)this; + } byte IConvertible.ToByte(IFormatProvider? provider) - => (byte)this; + { + return (byte)this; + } char IConvertible.ToChar(IFormatProvider? provider) - => (char)this; + { + return (char)this; + } DateTime IConvertible.ToDateTime(IFormatProvider? provider) - => (DateTime)this; + { + return (DateTime)this; + } decimal IConvertible.ToDecimal(IFormatProvider? provider) - => (decimal)this; + { + return (decimal)this; + } double IConvertible.ToDouble(IFormatProvider? provider) - => (double)this; + { + return (double)this; + } short IConvertible.ToInt16(IFormatProvider? provider) - => (short)this; + { + return (short)this; + } int IConvertible.ToInt32(IFormatProvider? provider) - => (int)this; + { + return (int)this; + } long IConvertible.ToInt64(IFormatProvider? provider) - => (long)this; + { + return (long)this; + } sbyte IConvertible.ToSByte(IFormatProvider? provider) - => (sbyte)this; + { + return (sbyte)this; + } float IConvertible.ToSingle(IFormatProvider? provider) - => (float)this; + { + return (float)this; + } string IConvertible.ToString(IFormatProvider? provider) - => (string?)this ?? string.Empty; + { + return (string?)this ?? string.Empty; + } object IConvertible.ToType(Type conversionType, IFormatProvider? provider) - => JsonValue?.ToObject(conversionType) - ?? throw new InvalidOperationException($"Cannot convert {this} to {conversionType}"); + { + return JsonValue?.ToObject(conversionType) + ?? throw new InvalidOperationException($"Cannot convert {this} to {conversionType}"); + } ushort IConvertible.ToUInt16(IFormatProvider? provider) - => (ushort)this; + { + return (ushort)this; + } uint IConvertible.ToUInt32(IFormatProvider? provider) - => (uint)this; + { + return (uint)this; + } ulong IConvertible.ToUInt64(IFormatProvider? provider) - => (ulong)this; + { + return (ulong)this; + } public static explicit operator bool(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Boolean"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Boolean"); + } public static explicit operator bool?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator byte(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Byte"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Byte"); + } public static explicit operator byte?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator char(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Char"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Char"); + } public static explicit operator char?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator DateTime(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to DateTime"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to DateTime"); + } public static explicit operator DateTime?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator DateTimeOffset(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to DateTimeOffset"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to DateTimeOffset"); + } public static explicit operator DateTimeOffset?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator decimal(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Decimal"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Decimal"); + } public static explicit operator decimal?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator double(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Double"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Double"); + } public static explicit operator double?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator Guid(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Guid"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Guid"); + } public static explicit operator Guid?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator short(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Int16"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Int16"); + } public static explicit operator short?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator int(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Int32"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Int32"); + } public static explicit operator int?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator long(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Int64"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Int64"); + } public static explicit operator long?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator sbyte(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to SByte"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to SByte"); + } public static explicit operator sbyte?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator float(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to Float"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to Float"); + } public static explicit operator float?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator string?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator ushort(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); + } public static explicit operator ushort?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator uint(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to UInt32"); + } public static explicit operator uint?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator ulong(JsonDynamicValue value) - => value?.JsonValue?.GetValue() - ?? throw new InvalidCastException($"Cannot convert {value} to UInt64"); + { + return value?.JsonValue?.GetValue() + ?? throw new InvalidCastException($"Cannot convert {value} to UInt64"); + } public static explicit operator ulong?(JsonDynamicValue value) - => value?.JsonValue?.GetValue(); + { + return value?.JsonValue?.GetValue(); + } public static explicit operator byte[]?(JsonDynamicValue value) { @@ -253,12 +359,14 @@ public static explicit operator TimeSpan(JsonDynamicValue value) } public static explicit operator Uri?(JsonDynamicValue value) - => new(value?.JsonValue?.GetValue() ?? string.Empty); + { + return new(value?.JsonValue?.GetValue() ?? string.Empty); + } private sealed class JsonDynamicMetaObject : DynamicMetaObject { private static readonly FrozenDictionary _cachedReflectionInfo = typeof(JsonDynamicValue) - .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(method => method.Name == "op_Explicit") .ToFrozenDictionary(method => method.ReturnType); @@ -286,7 +394,7 @@ public override DynamicMetaObject BindConvert(ConvertBinder binder) if (_cachedReflectionInfo.TryGetValue(targetType, out var castMethod)) { var convertExpression = Expression.Convert(Expression.Convert(Expression, typeof(JsonDynamicValue)), targetType, castMethod); - + return new DynamicMetaObject(convertExpression, BindingRestrictions.GetTypeRestriction(Expression, typeof(JsonDynamicValue))); } From 8cfa4a4c6675fa6cc1824c399d971d002c4697e3 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 10 May 2024 16:36:00 -0700 Subject: [PATCH 12/13] Remove test --- test/OrchardCore.Tests/Data/JsonDynamicTests.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs index 4b8513b5d8f..5060531a1d8 100644 --- a/test/OrchardCore.Tests/Data/JsonDynamicTests.cs +++ b/test/OrchardCore.Tests/Data/JsonDynamicTests.cs @@ -337,14 +337,4 @@ public void JsonDynamicValueMustConvertToUri() Assert.Equal(expectedValue, (Uri)myDynamic); } - - [Fact] - public void JsonDynamicValueHasValue() - { - var expectedValue = "A test string value"; - dynamic myDynamic = new JsonDynamicValue(JsonValue.Create(expectedValue)); - - Assert.NotNull(myDynamic.Value); - Assert.Equal(expectedValue, myDynamic.Value); - } } From 234ee2f1fd28eeaebd7dba602de31c02df581e05 Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Tue, 14 May 2024 12:51:57 +0200 Subject: [PATCH 13/13] Made conversions to string a little bit more consistent. --- .../Json/Dynamic/JsonDynamicValue.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs index 45be0fae42b..3257e3bd7a9 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Json/Dynamic/JsonDynamicValue.cs @@ -26,7 +26,7 @@ public override DynamicMetaObject GetMetaObject(Expression parameter) public override string ToString() { - return JsonValue?.ToString() ?? string.Empty; + return ToString(null, null); } public string ToString(string format) @@ -124,7 +124,7 @@ float IConvertible.ToSingle(IFormatProvider? provider) string IConvertible.ToString(IFormatProvider? provider) { - return (string?)this ?? string.Empty; + return ToString(provider); } object IConvertible.ToType(Type conversionType, IFormatProvider? provider) @@ -293,7 +293,7 @@ public static explicit operator float(JsonDynamicValue value) public static explicit operator string?(JsonDynamicValue value) { - return value?.JsonValue?.GetValue(); + return value?.ToString(); } public static explicit operator ushort(JsonDynamicValue value) @@ -354,8 +354,8 @@ public static explicit operator TimeSpan(JsonDynamicValue value) var str = value?.JsonValue?.GetObjectValue() as string; return str is not null - ? TimeSpan.Parse(str, CultureInfo.InvariantCulture) - : null; + ? TimeSpan.Parse(str, CultureInfo.InvariantCulture) + : null; } public static explicit operator Uri?(JsonDynamicValue value)