Skip to content

Commit

Permalink
Improve error message when binding a command with arguments into norm…
Browse files Browse the repository at this point in the history
…al button
  • Loading branch information
exyi authored and tomasherceg committed Feb 8, 2024
1 parent 4d43044 commit 8121e7a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 14 deletions.
14 changes: 12 additions & 2 deletions src/Framework/Framework/Compilation/Javascript/ParametrizedCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,14 @@ public ParametrizedCode(string code, OperatorPrecedence precedence = default)

// TODO(exyi): add WriteTo(StringBuilder)
/// <summary>
/// Converts this to string and assigns all parameters using `parameterAssignment`. If there is any missing, exception is thrown.
/// Converts this to string and assigns all parameters using `parameterAssignment`.
/// </summary>
/// <exception cref="MissingAssignmentException">Thrown when some parameter is not assigned and has no default value.</exception>
public string ToString(Func<CodeSymbolicParameter, CodeParameterAssignment> parameterAssignment) => ToString(parameterAssignment, out var _);
/// <summary>
/// Converts this to string and assigns all parameters using `parameterAssignment`.
/// </summary>
/// <exception cref="MissingAssignmentException">Thrown when some parameter is not assigned and has no default value.</exception>
public string ToString(Func<CodeSymbolicParameter, CodeParameterAssignment> parameterAssignment, out bool allIsDefault)
{
allIsDefault = true;
Expand Down Expand Up @@ -205,7 +210,7 @@ private CodeParameterAssignment[] FindAssignment(Func<CodeSymbolicParameter, Cod
{
pp[i] = parameters[i].DefaultAssignment;
if (pp[i].Code == null)
throw new InvalidOperationException($"Assignment of parameter '{parameters[i].Parameter}' was not found.");
throw new MissingAssignmentException(parameters[i], this);
}
}
else
Expand All @@ -229,6 +234,11 @@ public IEnumerable<CodeSymbolicParameter> EnumerateAllParameters()
}
}

public record MissingAssignmentException(CodeParameterInfo Parameter, ParametrizedCode FullCode): RecordExceptions.RecordException
{
public override string Message => $"Assignment of parameter '{Parameter.Parameter}' was not found.";
}

/// <summary>
/// Builder class with reasonably fast Add operation. Use Build method to convert it to immutable ParametrizedCode
/// </summary>
Expand Down
33 changes: 21 additions & 12 deletions src/Framework/Framework/Controls/KnockoutHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using DotVVM.Framework.Compilation.Javascript.Ast;
using DotVVM.Framework.Configuration;
using DotVVM.Framework.Utils;
using FastExpressionCompiler;
using Newtonsoft.Json;

namespace DotVVM.Framework.Controls
Expand Down Expand Up @@ -263,18 +264,26 @@ options.KoContext is object ?

string SubstituteArguments(ParametrizedCode parametrizedCode)
{
return parametrizedCode.ToString(p =>
p == JavascriptTranslator.CurrentElementParameter ? options.ElementAccessor :
p == CommandBindingExpression.CurrentPathParameter ? CodeParameterAssignment.FromIdentifier(getContextPath(control)) :
p == CommandBindingExpression.ControlUniqueIdParameter ? uniqueControlId?.GetParametrizedJsExpression(control) ?? CodeParameterAssignment.FromLiteral("") :
p == JavascriptTranslator.KnockoutContextParameter ? knockoutContext :
p == JavascriptTranslator.KnockoutViewModelParameter ? viewModel :
p == CommandBindingExpression.OptionalKnockoutContextParameter ? optionalKnockoutContext :
p == CommandBindingExpression.CommandArgumentsParameter ? options.CommandArgs ?? default :
p == CommandBindingExpression.PostbackHandlersParameter ? CodeParameterAssignment.FromIdentifier(getHandlerScript()) :
p == CommandBindingExpression.AbortSignalParameter ? abortSignal :
default
);
try
{
return parametrizedCode.ToString(p =>
p == JavascriptTranslator.CurrentElementParameter ? options.ElementAccessor :
p == CommandBindingExpression.CurrentPathParameter ? CodeParameterAssignment.FromIdentifier(getContextPath(control)) :
p == CommandBindingExpression.ControlUniqueIdParameter ? uniqueControlId?.GetParametrizedJsExpression(control) ?? CodeParameterAssignment.FromLiteral("") :
p == JavascriptTranslator.KnockoutContextParameter ? knockoutContext :
p == JavascriptTranslator.KnockoutViewModelParameter ? viewModel :
p == CommandBindingExpression.OptionalKnockoutContextParameter ? optionalKnockoutContext :
p == CommandBindingExpression.CommandArgumentsParameter ? options.CommandArgs ?? default :
p == CommandBindingExpression.PostbackHandlersParameter ? CodeParameterAssignment.FromIdentifier(getHandlerScript()) :
p == CommandBindingExpression.AbortSignalParameter ? abortSignal :
default
);
}
catch (ParametrizedCode.MissingAssignmentException e) when (e.Parameter.Parameter == CommandBindingExpression.CommandArgumentsParameter)
{
var returnType = expression.GetProperty<ResultTypeBindingProperty>(ErrorHandlingMode.ReturnNull)?.Type;
throw new DotvvmControlException(control, $"The binding {expression} of type {returnType?.ToCode(stripNamespace: true) ?? "?"} requires arguments, but none were provided to the KnockoutHelper.GenerateClientPostback method.", innerException: e) { RelatedBinding = expression };
}
}
}

Expand Down

0 comments on commit 8121e7a

Please sign in to comment.