Skip to content

Commit 0a1c85d

Browse files
authored
Merge pull request #2014 from riganti/copilot/fix-binding-translation-bug
Fix ObjectIsFrozenException when using string.IsNullOrEmpty/IsNullOrWhiteSpace in Where lambda bindings
2 parents 188d1b6 + a7c241e commit 0a1c85d

2 files changed

Lines changed: 26 additions & 9 deletions

File tree

src/Framework/Framework/Compilation/Binding/GeneralBindingPropertyResolvers.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ public SimplePathExpressionBindingProperty FormatSimplePath(IBinding binding)
142142
// if contains api parameter, can't use this as a path
143143
if (js.Expression.DescendantNodes().Any(n => n.TryGetAnnotation(out ViewModelInfoAnnotation? vmInfo) && vmInfo.ExtensionParameter is RestApiRegistrationHelpers.ApiExtensionParameter apiParameter))
144144
throw new Exception($"Can't get a path expression for command binding from binding that is using rest api.");
145-
return new(js.Expression.FormatParametrizedScript());
145+
var expr = js.Expression.Clone(); // need to Clone, because js.Expression is frozen and not parethesized
146+
return new(expr.FormatParametrizedScript());
146147
}
147148
else if (binding.GetProperty<KnockoutExpressionBindingProperty>(ErrorHandlingMode.ReturnNull) is { } expr)
148149
{

src/Tests/Binding/JavascriptCompilationTests.cs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
1-
using DotVVM.Framework.Binding;
2-
using DotVVM.Framework.Controls;
3-
using DotVVM.Framework.Runtime;
4-
using Microsoft.VisualStudio.TestTools.UnitTesting;
51
using System;
62
using System.Collections.Generic;
73
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Text.Json.Serialization;
86
using System.Threading.Tasks;
7+
using DotVVM.Framework.Binding;
8+
using DotVVM.Framework.Binding.Expressions;
9+
using DotVVM.Framework.Binding.Properties;
910
using DotVVM.Framework.Compilation;
1011
using DotVVM.Framework.Compilation.Binding;
1112
using DotVVM.Framework.Compilation.ControlTree;
1213
using DotVVM.Framework.Compilation.Javascript;
1314
using DotVVM.Framework.Compilation.Javascript.Ast;
14-
using DotVVM.Framework.Testing;
1515
using DotVVM.Framework.Configuration;
16-
using System.Linq.Expressions;
17-
using Microsoft.Extensions.DependencyInjection;
16+
using DotVVM.Framework.Controls;
17+
using DotVVM.Framework.Runtime;
18+
using DotVVM.Framework.Testing;
1819
using DotVVM.Framework.Utils;
1920
using DotVVM.Framework.ViewModel;
20-
using System.Text.Json.Serialization;
21+
using Microsoft.Extensions.DependencyInjection;
22+
using Microsoft.VisualStudio.TestTools.UnitTesting;
23+
using static DotVVM.Framework.Configuration.FreezableUtils;
2124

2225
namespace DotVVM.Framework.Tests.Binding
2326
{
@@ -1511,6 +1514,19 @@ public void JavascriptCompilation_StringFunctions(string input, string expected)
15111514
Assert.AreEqual(expected, result);
15121515
}
15131516

1517+
[TestMethod]
1518+
[DataRow("VmArray.Where(v => string.IsNullOrEmpty(v.SomeString)).ToList()")]
1519+
[DataRow("VmArray.Where(v => string.IsNullOrWhiteSpace(v.SomeString)).ToList()")]
1520+
// Regression test: FormatParametrizedScript was called on a frozen JsBinaryExpression (from string.IsNullOrEmpty/IsNullOrWhiteSpace
1521+
// translation) causing ObjectIsFrozenException when computing SimplePathExpressionBindingProperty.
1522+
public void JavascriptCompilation_IsNullOrEmpty_InWhereLambda_DoesNotThrowOnSimplePathExpression(string expression)
1523+
{
1524+
var binding = bindingHelper.ValueBinding<IEnumerable<TestViewModel2>>(
1525+
expression,
1526+
new[] { typeof(TestViewModel) });
1527+
var simplePath = binding.GetProperty(typeof(SimplePathExpressionBindingProperty), ErrorHandlingMode.ThrowException);
1528+
}
1529+
15141530
[TestMethod]
15151531
public void JavascriptCompilation_CustomPrimitiveToString()
15161532
{

0 commit comments

Comments
 (0)