diff --git a/README.md b/README.md index c54e1ec2..abe2b88d 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,29 @@ int c = 10; db.Customers.WhereInterpolated($"City == {cityName} and Orders.Count >= {c}"); ``` +## :exclamation: Breaking changes + +### v1.3.0 +A breaking change is introduced in version 1.3.0 which is related to calling methods on classes. +Due to security reasons, it's now only allowed to call methods on the standard predefined classes like (`bool`, `int`, `string` ...). +If you want to call a method on an own custom class, annotate that class with the [DynamicLinqType](https://dynamic-linq.net/advanced-extending#dynamiclinqtype-attribute). +Example: +``` c# +[DynamicLinqType] +public class MyCustomClass +{ + public int GetAge(int x) => x; +} +``` + +If it's not possible to add that attribute, you need to implement a custom [CustomTypeProvider](https://dynamic-linq.net/advanced-configuration#customtypeprovider) and set this to the `ParsingConfig` and provide that config to the dynamic call. + ## Useful links -- [Website](https://dynamic-linq.net/) +- [Website](https://dynamic-linq.net) - [Documentation](https://dynamic-linq.net/overview) - [Online examples](https://dynamic-linq.net/online-examples) -- [nuget](https://www.nuget.org/packages/System.Linq.Dynamic.Core/) +- [NuGet](https://www.nuget.org/packages/System.Linq.Dynamic.Core) ## Info | | | diff --git a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs index 818037e1..0a93e8c5 100644 --- a/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs @@ -77,6 +77,23 @@ public class CustomClassWithStaticMethod public static int GetAge(int x) => x; } + public class CustomClassWithMethod + { + public int GetAge(int x) => x; + } + + [DynamicLinqType] + public class CustomClassWithMethodWithDynamicLinqTypeAttribute + { + public int GetAge(int x) => x; + } + + [DynamicLinqType] + public class CustomClassWithStaticMethodWithDynamicLinqTypeAttribute + { + public static int GetAge(int x) => x; + } + public class CustomTextClass { public CustomTextClass(string origin) @@ -1010,7 +1027,7 @@ public void DynamicExpressionParser_ParseLambda_TupleToStringMethodCall_ReturnsS } [Fact] - public void DynamicExpressionParser_ParseLambda_CustomMethod() + public void DynamicExpressionParser_ParseLambda_CustomStaticMethod_WhenClassIsReturnedByCustomTypeProvider_ShouldWorkCorrect() { // Assign var config = new ParsingConfig @@ -1030,6 +1047,51 @@ public void DynamicExpressionParser_ParseLambda_CustomMethod() Check.That(result).IsEqualTo(10); } + [Fact] + public void DynamicExpressionParser_ParseLambda_CustomStaticMethod_WhenClassHasDynamicLinqTypeAttribute_ShouldWorkCorrect() + { + // Assign + var context = new CustomClassWithStaticMethodWithDynamicLinqTypeAttribute(); + var expression = $"{nameof(CustomClassWithStaticMethodWithDynamicLinqTypeAttribute)}.{nameof(CustomClassWithStaticMethodWithDynamicLinqTypeAttribute.GetAge)}(10)"; + + // Act + var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(CustomClassWithStaticMethodWithDynamicLinqTypeAttribute), null, expression); + var del = lambdaExpression.Compile(); + var result = (int)del.DynamicInvoke(context); + + // Assert + Check.That(result).IsEqualTo(10); + } + + [Fact] + public void DynamicExpressionParser_ParseLambda_CustomMethod_WhenClassHasDynamicLinqTypeAttribute_ShouldWorkCorrect() + { + // Assign + var context = new CustomClassWithMethodWithDynamicLinqTypeAttribute(); + var expression = $"{nameof(CustomClassWithMethodWithDynamicLinqTypeAttribute.GetAge)}(10)"; + + // Act + var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(CustomClassWithMethodWithDynamicLinqTypeAttribute), null, expression); + var del = lambdaExpression.Compile(); + var result = (int)del.DynamicInvoke(context); + + // Assert + Check.That(result).IsEqualTo(10); + } + + [Fact] + public void DynamicExpressionParser_ParseLambda_CustomMethod_WhenClassDoesNotHaveDynamicLinqTypeAttribute_ShouldThrowException() + { + // Assign + var expression = $"{nameof(CustomClassWithMethod.GetAge)}(10)"; + + // Act + Action action = () => DynamicExpressionParser.ParseLambda(typeof(CustomClassWithMethod), null, expression); + + // Assert + action.Should().Throw().WithMessage("Methods on type 'CustomClassWithMethod' are not accessible"); + } + // [Fact] public void DynamicExpressionParser_ParseLambda_With_InnerStringLiteral() {