diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index adf8ba214..f998851e2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -85,6 +85,14 @@ jobs:
run: |
dotnet-coverage collect 'dotnet test ./test/System.Linq.Dynamic.Core.Tests.Net8/System.Linq.Dynamic.Core.Tests.Net8.csproj --configuration Debug --framework net8.0 -p:buildType=azure-pipelines-ci' -f xml -o dynamic-coverage-efcore.xml
+ - name: Run Tests Newtonsoft.Json .NET 8 (with Coverage)
+ run: |
+ dotnet-coverage collect 'dotnet test ./test/System.Linq.Dynamic.Core.NewtonsoftJson.Tests/System.Linq.Dynamic.Core.NewtonsoftJson.Tests.csproj --configuration Debug --framework net8.0 -p:buildType=azure-pipelines-ci' -f xml -o dynamic-coverage-newtonsoftjson.xml
+
+ - name: Run Tests System.Text.Json .NET 8 (with Coverage)
+ run: |
+ dotnet-coverage collect 'dotnet test ./test/System.Linq.Dynamic.Core.SystemTextJson.Tests/System.Linq.Dynamic.Core.SystemTextJson.Tests.csproj --configuration Debug --framework net8.0 -p:buildType=azure-pipelines-ci' -f xml -o dynamic-coverage-systemtextjson.xml
+
- name: End analysis on SonarCloud
if: ${{ steps.secret-check.outputs.run_analysis == 'true' }}
run: |
diff --git a/System.Linq.Dynamic.Core.sln b/System.Linq.Dynamic.Core.sln
index 38874017f..c331aac5e 100644
--- a/System.Linq.Dynamic.Core.sln
+++ b/System.Linq.Dynamic.Core.sln
@@ -143,6 +143,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.Plugin", "src-console\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.Tests.NetCoreApp31", "test\System.Linq.Dynamic.Core.Tests.NetCoreApp31\System.Linq.Dynamic.Core.Tests.NetCoreApp31.csproj", "{7AFC2836-0F6E-4B0D-8BB3-13317A3B6616}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.NewtonsoftJson", "src\System.Linq.Dynamic.Core.NewtonsoftJson\System.Linq.Dynamic.Core.NewtonsoftJson.csproj", "{8C5851B8-5C47-4229-AB55-D4252703598E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.NewtonsoftJson.Tests", "test\System.Linq.Dynamic.Core.NewtonsoftJson.Tests\System.Linq.Dynamic.Core.NewtonsoftJson.Tests.csproj", "{912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.SystemTextJson", "src\System.Linq.Dynamic.Core.SystemTextJson\System.Linq.Dynamic.Core.SystemTextJson.csproj", "{FA01CE15-315A-499E-AFC2-955CA7EB45FF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Linq.Dynamic.Core.SystemTextJson.Tests", "test\System.Linq.Dynamic.Core.SystemTextJson.Tests\System.Linq.Dynamic.Core.SystemTextJson.Tests.csproj", "{D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasmDynamicLinq", "src-blazor\WasmDynamicLinq\WasmDynamicLinq.csproj", "{2DE2052F-0A50-40C7-B6FF-52B52386BF9A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SldcTrimmer", "src-examples\SldcTrimmer\SldcTrimmer.csproj", "{7A31366C-DD98-41A3-A0C1-A97068BD9658}"
@@ -903,6 +911,70 @@ Global
{7AFC2836-0F6E-4B0D-8BB3-13317A3B6616}.Release|x64.Build.0 = Release|Any CPU
{7AFC2836-0F6E-4B0D-8BB3-13317A3B6616}.Release|x86.ActiveCfg = Release|Any CPU
{7AFC2836-0F6E-4B0D-8BB3-13317A3B6616}.Release|x86.Build.0 = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|ARM.Build.0 = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|x64.Build.0 = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Debug|x86.Build.0 = Debug|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|ARM.ActiveCfg = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|ARM.Build.0 = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|x64.ActiveCfg = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|x64.Build.0 = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|x86.ActiveCfg = Release|Any CPU
+ {8C5851B8-5C47-4229-AB55-D4252703598E}.Release|x86.Build.0 = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|ARM.Build.0 = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|x64.Build.0 = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Debug|x86.Build.0 = Debug|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|Any CPU.Build.0 = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|ARM.ActiveCfg = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|ARM.Build.0 = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|x64.ActiveCfg = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|x64.Build.0 = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|x86.ActiveCfg = Release|Any CPU
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90}.Release|x86.Build.0 = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|ARM.Build.0 = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|x64.Build.0 = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Debug|x86.Build.0 = Debug|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|ARM.ActiveCfg = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|ARM.Build.0 = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|x64.ActiveCfg = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|x64.Build.0 = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|x86.ActiveCfg = Release|Any CPU
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF}.Release|x86.Build.0 = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|ARM.Build.0 = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|x64.Build.0 = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Debug|x86.Build.0 = Debug|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|ARM.ActiveCfg = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|ARM.Build.0 = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|x64.ActiveCfg = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|x64.Build.0 = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|x86.ActiveCfg = Release|Any CPU
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E}.Release|x86.Build.0 = Release|Any CPU
{2DE2052F-0A50-40C7-B6FF-52B52386BF9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DE2052F-0A50-40C7-B6FF-52B52386BF9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DE2052F-0A50-40C7-B6FF-52B52386BF9A}.Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -1018,6 +1090,10 @@ Global
{D8368319-F370-4071-9411-A3DADB234330} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
{B01B327C-FC68-49B6-BDE3-A13D0C66DF5C} = {7971CAEB-B9F2-416B-966D-2D697C4C1E62}
{7AFC2836-0F6E-4B0D-8BB3-13317A3B6616} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38}
+ {8C5851B8-5C47-4229-AB55-D4252703598E} = {DBD7D9B6-FCC7-4650-91AF-E6457573A68F}
+ {912FBF24-3CAE-4A50-B5EA-E525B9FAEC90} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38}
+ {FA01CE15-315A-499E-AFC2-955CA7EB45FF} = {DBD7D9B6-FCC7-4650-91AF-E6457573A68F}
+ {D5844AE4-53FA-4C8A-9D52-AD213FD0CA1E} = {8463ED7E-69FB-49AE-85CF-0791AFD98E38}
{2DE2052F-0A50-40C7-B6FF-52B52386BF9A} = {122BC4FA-7563-4E35-9D17-077F16F1629F}
{7A31366C-DD98-41A3-A0C1-A97068BD9658} = {BCA2A024-9032-4E56-A6C4-17A15D921728}
{C774DAE7-54A0-4FCD-A3B7-3CB63D7E112D} = {DBD7D9B6-FCC7-4650-91AF-E6457573A68F}
diff --git a/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj b/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj
index 84ca9532f..46108c0bc 100644
--- a/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj
+++ b/src-console/ConsoleApp_net6.0/ConsoleApp_net6.0.csproj
@@ -8,7 +8,8 @@
-
+
+
diff --git a/src-console/ConsoleApp_net6.0/Program.cs b/src-console/ConsoleApp_net6.0/Program.cs
index baf2c16f9..8c5af2f6c 100644
--- a/src-console/ConsoleApp_net6.0/Program.cs
+++ b/src-console/ConsoleApp_net6.0/Program.cs
@@ -2,116 +2,185 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
-using System.Linq.Dynamic.Core.Parser;
+using System.Linq.Dynamic.Core.NewtonsoftJson;
+using System.Linq.Dynamic.Core.SystemTextJson;
using System.Linq.Expressions;
+using System.Text.Json;
+using Newtonsoft.Json.Linq;
-namespace ConsoleApp_net6._0
+namespace ConsoleApp_net6._0;
+
+public class X
{
- public class X
- {
- public string Key { get; set; } = null!;
+ public string Key { get; set; } = null!;
- public List? Contestants { get; set; }
- }
+ public List? Contestants { get; set; }
+}
- public class Y
+public class Y
+{
+}
+
+class Program
+{
+ static void Main(string[] args)
{
+ Json();
+ NewtonsoftJson();
+
+ return;
+
+ Issue389DoesNotWork();
+ return;
+ Issue389_Works();
+ return;
+
+ var q = new[]
+ {
+ new X { Key = "x" },
+ new X { Key = "a" },
+ new X { Key = "a", Contestants = new List { new Y() } }
+ }.AsQueryable();
+ var groupByKey = q.GroupBy("Key");
+ var selectQry = groupByKey.Select("new (Key, Sum(np(Contestants.Count, 0)) As TotalCount)").ToDynamicList();
+
+ Normal();
+ Dynamic();
}
- class Program
+ private static void NewtonsoftJson()
{
- static void Main(string[] args)
+ var array = JArray.Parse(@"[
{
- var parser = new ExpressionParser(new[] { Expression.Parameter(typeof(int), "VarA") }, "\"foo\" & VarA", new object[0], new ParsingConfig { ConvertObjectToSupportComparison = true});
-
- var expression = parser.Parse(typeof(string));
-
- Issue389DoesNotWork();
- return;
- Issue389_Works();
- return;
-
- var q = new[]
- {
- new X { Key = "x" },
- new X { Key = "a" },
- new X { Key = "a", Contestants = new List { new Y() } }
- }.AsQueryable();
- var groupByKey = q.GroupBy("Key");
- var selectQry = groupByKey.Select("new (Key, Sum(np(Contestants.Count, 0)) As TotalCount)").ToDynamicList();
-
- Normal();
- Dynamic();
- }
-
- private static void Issue389_Works()
+ ""first"": 1,
+ ""City"": ""Paris"",
+ ""third"": ""test""
+ },
{
- var strArray = new[] { "1", "2", "3", "4" };
- var x = new List();
- x.Add(Expression.Parameter(strArray.GetType(), "strArray"));
+ ""first"": 2,
+ ""City"": ""New York"",
+ ""third"": ""abc""
+ }]");
- string query = "string.Join(\",\", strArray)";
+ var where = array.Where("City == @0", "Paris");
+ foreach (var result in where)
+ {
+ Console.WriteLine(result["first"]);
+ }
- var e = DynamicExpressionParser.ParseLambda(x.ToArray(), null, query);
- Delegate del = e.Compile();
- var result1 = del.DynamicInvoke(new object?[] { strArray });
- Console.WriteLine(result1);
+ var select = array.Select("City");
+ foreach (var result in select)
+ {
+ Console.WriteLine(result);
}
- private static void Issue389WorksWithInts()
+ var whereWithSelect = array.Where("City == @0", "Paris").Select("first");
+ foreach (var result in whereWithSelect)
{
- var intArray = new object[] { 1, 2, 3, 4 };
- var x = new List();
- x.Add(Expression.Parameter(intArray.GetType(), "intArray"));
+ Console.WriteLine(result);
+ }
+ }
- string query = "string.Join(\",\", intArray)";
+ private static void Json()
+ {
+ var doc = JsonDocument.Parse(@"[
+ {
+ ""first"": 1,
+ ""City"": ""Paris"",
+ ""third"": ""test""
+ },
+ {
+ ""first"": 2,
+ ""City"": ""New York"",
+ ""third"": ""abc""
+ }]");
- var e = DynamicExpressionParser.ParseLambda(x.ToArray(), null, query);
- Delegate del = e.Compile();
- var result = del.DynamicInvoke(new object?[] { intArray });
+ var where = doc.Where("City == @0", "Paris");
+ foreach (var result in where.RootElement.EnumerateArray())
+ {
+ Console.WriteLine(result.GetProperty("first"));
+ }
+ var select = doc.Select("City");
+ foreach (var result in select.RootElement.EnumerateArray())
+ {
Console.WriteLine(result);
}
- private static void Issue389DoesNotWork()
+ var whereWithSelect = doc.Where("City == @0", "Paris").Select("first");
+ foreach (var result in whereWithSelect.RootElement.EnumerateArray())
{
- var intArray = new [] { 1, 2, 3, 4 };
- var x = new List();
- x.Add(Expression.Parameter(intArray.GetType(), "intArray"));
+ Console.WriteLine(result);
+ }
+ }
- string query = "string.Join(\",\", intArray)";
+ private static void Issue389_Works()
+ {
+ var strArray = new[] { "1", "2", "3", "4" };
+ var x = new List();
+ x.Add(Expression.Parameter(strArray.GetType(), "strArray"));
- var e = DynamicExpressionParser.ParseLambda(x.ToArray(), null, query);
- Delegate del = e.Compile();
- var result = del.DynamicInvoke(new object?[] { intArray });
+ string query = "string.Join(\",\", strArray)";
- Console.WriteLine(result);
- }
+ var e = DynamicExpressionParser.ParseLambda(x.ToArray(), null, query);
+ Delegate del = e.Compile();
+ var result1 = del.DynamicInvoke(new object?[] { strArray });
+ Console.WriteLine(result1);
+ }
- private static void Normal()
- {
- var e = new int[0].AsQueryable();
- var q = new[] { 1 }.AsQueryable();
+ private static void Issue389WorksWithInts()
+ {
+ var intArray = new object[] { 1, 2, 3, 4 };
+ var x = new List();
+ x.Add(Expression.Parameter(intArray.GetType(), "intArray"));
- var a = q.FirstOrDefault();
- var b = e.FirstOrDefault(44);
+ string query = "string.Join(\",\", intArray)";
- var c = q.FirstOrDefault(i => i == 0);
- var d = q.FirstOrDefault(i => i == 0, 42);
+ var e = DynamicExpressionParser.ParseLambda(x.ToArray(), null, query);
+ Delegate del = e.Compile();
+ var result = del.DynamicInvoke(new object?[] { intArray });
- var t = q.Take(1);
- }
+ Console.WriteLine(result);
+ }
- private static void Dynamic()
- {
- var e = new int[0].AsQueryable() as IQueryable;
- var q = new[] { 1 }.AsQueryable() as IQueryable;
+ private static void Issue389DoesNotWork()
+ {
+ var intArray = new[] { 1, 2, 3, 4 };
+ var x = new List();
+ x.Add(Expression.Parameter(intArray.GetType(), "intArray"));
- var a = q.FirstOrDefault();
- //var b = e.FirstOrDefault(44);
+ string query = "string.Join(\",\", intArray)";
- var c = q.FirstOrDefault("it == 0");
- //var d = q.FirstOrDefault(i => i == 0, 42);
- }
+ var e = DynamicExpressionParser.ParseLambda(x.ToArray(), null, query);
+ Delegate del = e.Compile();
+ var result = del.DynamicInvoke(new object?[] { intArray });
+
+ Console.WriteLine(result);
+ }
+
+ private static void Normal()
+ {
+ var e = new int[0].AsQueryable();
+ var q = new[] { 1 }.AsQueryable();
+
+ var a = q.FirstOrDefault();
+ var b = e.FirstOrDefault(44);
+
+ var c = q.FirstOrDefault(i => i == 0);
+ var d = q.FirstOrDefault(i => i == 0, 42);
+
+ var t = q.Take(1);
+ }
+
+ private static void Dynamic()
+ {
+ var e = new int[0].AsQueryable() as IQueryable;
+ var q = new[] { 1 }.AsQueryable() as IQueryable;
+
+ var a = q.FirstOrDefault();
+ //var b = e.FirstOrDefault(44);
+
+ var c = q.FirstOrDefault("it == 0");
+ //var d = q.FirstOrDefault(i => i == 0, 42);
}
}
\ No newline at end of file
diff --git a/src/System.Linq.Dynamic.Core.NewtonsoftJson/Config/NewtonsoftJsonParsingConfig.cs b/src/System.Linq.Dynamic.Core.NewtonsoftJson/Config/NewtonsoftJsonParsingConfig.cs
new file mode 100644
index 000000000..fad7f9f12
--- /dev/null
+++ b/src/System.Linq.Dynamic.Core.NewtonsoftJson/Config/NewtonsoftJsonParsingConfig.cs
@@ -0,0 +1,19 @@
+using JsonConverter.Abstractions.Models;
+
+namespace System.Linq.Dynamic.Core.NewtonsoftJson.Config;
+
+///
+/// Configuration class for System.Linq.Dynamic.Core.NewtonsoftJson which implements the .
+///
+public class NewtonsoftJsonParsingConfig : ParsingConfig
+{
+ ///
+ /// The default ParsingConfig for .
+ ///
+ public new static NewtonsoftJsonParsingConfig Default { get; } = new();
+
+ ///
+ /// The default to use.
+ ///
+ public DynamicJsonClassOptions? DynamicJsonClassOptions { get; set; }
+}
\ No newline at end of file
diff --git a/src/System.Linq.Dynamic.Core.NewtonsoftJson/Extensions/JObjectExtensions.cs b/src/System.Linq.Dynamic.Core.NewtonsoftJson/Extensions/JObjectExtensions.cs
new file mode 100644
index 000000000..1a7be2f44
--- /dev/null
+++ b/src/System.Linq.Dynamic.Core.NewtonsoftJson/Extensions/JObjectExtensions.cs
@@ -0,0 +1,187 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using JsonConverter.Abstractions.Models;
+using Newtonsoft.Json.Linq;
+
+namespace System.Linq.Dynamic.Core.NewtonsoftJson.Extensions;
+
+///
+/// Based on https://github.com/StefH/JsonConverter/blob/main/src/JsonConverter.Newtonsoft.Json/Extensions/JObjectExtensions.cs
+///
+internal static class JObjectExtensions
+{
+ private class JTokenResolvers : Dictionary>;
+
+ private static readonly JTokenResolvers Resolvers = new()
+ {
+ { JTokenType.Array, ConvertJTokenArray },
+ { JTokenType.Boolean, (jToken, _) => jToken.Value() },
+ { JTokenType.Bytes, (jToken, _) => jToken.Value() },
+ { JTokenType.Date, (jToken, _) => jToken.Value() },
+ { JTokenType.Float, ConvertJTokenFloat },
+ { JTokenType.Guid, (jToken, _) => jToken.Value() },
+ { JTokenType.Integer, ConvertJTokenInteger },
+ { JTokenType.None, (_, _) => null },
+ { JTokenType.Null, (_, _) => null },
+ { JTokenType.Object, ConvertJObject },
+ { JTokenType.Property, ConvertJTokenProperty },
+ { JTokenType.String, (jToken, _) => jToken.Value() },
+ { JTokenType.TimeSpan, (jToken, _) => jToken.Value() },
+ { JTokenType.Undefined, (_, _) => null },
+ { JTokenType.Uri, (o, _) => o.Value() },
+ };
+
+ internal static DynamicClass? ToDynamicClass(this JObject? src, DynamicJsonClassOptions? options = null)
+ {
+ if (src == null)
+ {
+ return null;
+ }
+
+ var dynamicPropertiesWithValue = new List();
+
+ foreach (var prop in src.Properties())
+ {
+ var value = Resolvers[prop.Type](prop.Value, options);
+ if (value != null)
+ {
+ dynamicPropertiesWithValue.Add(new DynamicPropertyWithValue(prop.Name, value));
+ }
+ }
+
+ return DynamicClassFactory.CreateInstance(dynamicPropertiesWithValue);
+ }
+
+ internal static object? ToDynamicClass(this JToken? src, DynamicJsonClassOptions? options = null)
+ {
+ return src == null ? null : GetResolverFor(src)(src, options);
+ }
+
+ internal static IEnumerable ToDynamicJsonClassArray(this JArray? src, DynamicJsonClassOptions? options = null)
+ {
+ return src == null ? new object?[0] : ConvertJTokenArray(src, options);
+ }
+
+ private static object? ConvertJObject(JToken arg, DynamicJsonClassOptions? options = null)
+ {
+ if (arg is JObject asJObject)
+ {
+ return asJObject.ToDynamicClass(options);
+ }
+
+ return GetResolverFor(arg)(arg, options);
+ }
+
+ private static object PassThrough(JToken arg, DynamicJsonClassOptions? options)
+ {
+ return arg;
+ }
+
+ private static Func GetResolverFor(JToken arg)
+ {
+ return Resolvers.TryGetValue(arg.Type, out var result) ? result : PassThrough;
+ }
+
+ private static object ConvertJTokenFloat(JToken arg, DynamicJsonClassOptions? options = null)
+ {
+ if (arg.Type != JTokenType.Float)
+ {
+ throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to double or float.");
+ }
+
+ if (options?.FloatConvertBehavior == FloatBehavior.UseFloat)
+ {
+ try
+ {
+ return arg.Value();
+ }
+ catch
+ {
+ return arg.Value();
+ }
+ }
+
+ if (options?.FloatConvertBehavior == FloatBehavior.UseDecimal)
+ {
+ try
+ {
+ return arg.Value();
+ }
+ catch
+ {
+ return arg.Value();
+ }
+ }
+
+
+ return arg.Value();
+ }
+
+ private static object ConvertJTokenInteger(JToken arg, DynamicJsonClassOptions? options = null)
+ {
+ if (arg.Type != JTokenType.Integer)
+ {
+ throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to long or int.");
+ }
+
+ var longValue = arg.Value();
+
+ if (options is null || options.IntegerConvertBehavior == IntegerBehavior.UseInt)
+ {
+ if (longValue is >= int.MinValue and <= int.MaxValue)
+ {
+ return Convert.ToInt32(longValue);
+ }
+ }
+
+ return longValue;
+ }
+
+ private static object? ConvertJTokenProperty(JToken arg, DynamicJsonClassOptions? options = null)
+ {
+ var resolver = GetResolverFor(arg);
+ if (resolver is null)
+ {
+ throw new InvalidOperationException($"Unable to handle {nameof(JToken)} of type: {arg.Type}.");
+ }
+
+ return resolver(arg, options);
+ }
+
+ private static IEnumerable ConvertJTokenArray(JToken arg, DynamicJsonClassOptions? options = null)
+ {
+ if (arg is not JArray array)
+ {
+ throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to {nameof(JArray)}.");
+ }
+
+ var result = new List