Skip to content

Commit

Permalink
Improve error handling of CommandResolver: missing markup control
Browse files Browse the repository at this point in the history
  • Loading branch information
exyi committed Sep 14, 2022
1 parent c44b606 commit 14a7721
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Runtime.CompilerServices;
using DotVVM.Framework.Compilation.ControlTree.Resolved;
using DotVVM.Framework.Utils;
using FastExpressionCompiler;

namespace DotVVM.Framework.Compilation.ControlTree
{
Expand Down Expand Up @@ -167,12 +168,12 @@ int ComputeHashCode()
public override string ToString()
{
string?[] features = new [] {
$"type={this.DataContextType.FullName}",
$"type={this.DataContextType.ToCode()}",
this.ServerSideOnly ? "server-side-only" : null,
this.NamespaceImports.Any() ? "imports=[" + string.Join(", ", this.NamespaceImports) + "]" : null,
this.ExtensionParameters.Any() ? "ext=[" + string.Join(", ", this.ExtensionParameters.Select(e => e.Identifier + ": " + e.ParameterType.Name)) + "]" : null,
this.BindingPropertyResolvers.Any() ? "resolvers=[" + string.Join(", ", this.BindingPropertyResolvers.Select(s => s.Method)) + "]" : null,
this.Parent != null ? "par=[" + string.Join(", ", this.Parents().Select(p => p.Name)) + "]" : null
this.Parent != null ? "par=[" + string.Join(", ", this.Parents().Select(p => p.ToCode(stripNamespace: true))) + "]" : null
};
return "(" + features.Where(a => a != null).StringJoin(", ") + ")";
}
Expand Down
73 changes: 71 additions & 2 deletions src/Framework/Framework/Controls/DotvvmControlProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,11 @@ public DotvvmPropertyDictionary(DotvvmBindableObject control)

public object? this[DotvvmProperty key] { get => control.properties.GetOrThrow(key); set => control.properties.Set(key, value); }

public ICollection<DotvvmProperty> Keys => throw new NotImplementedException();
public KeysCollection Keys => new KeysCollection(control);
ICollection<DotvvmProperty> IDictionary<DotvvmProperty, object?>.Keys => Keys;

public ICollection<object?> Values => throw new NotImplementedException();
public ValuesCollection Values => new ValuesCollection(control);
ICollection<object?> IDictionary<DotvvmProperty, object?>.Values => Values;

public int Count => control.properties.Count();
public bool IsReadOnly => false;
Expand Down Expand Up @@ -442,5 +444,72 @@ public bool TryGetValue(DotvvmProperty key, out object? value) =>
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();

IEnumerator<KeyValuePair<DotvvmProperty, object?>> IEnumerable<KeyValuePair<DotvvmProperty, object?>>.GetEnumerator() => this.GetEnumerator();


public readonly struct KeysCollection : ICollection<DotvvmProperty>, IReadOnlyCollection<DotvvmProperty>
{
private readonly DotvvmBindableObject control;

public KeysCollection(DotvvmBindableObject control) { this.control = control; }
public int Count => control.properties.Count();

public bool IsReadOnly => true;
public void Add(DotvvmProperty item) => throw new NotSupportedException("Adding a property without value doesn't make sense");
public void Clear() => throw new NotSupportedException("Explicitly use control.Properties.Clear() instead.");
public bool Contains(DotvvmProperty item) => control.properties.Contains(item);
public void CopyTo(DotvvmProperty[] array, int arrayIndex)
{
foreach (var x in control.properties)
{
array[arrayIndex++] = x.Key;
}
}
public IEnumerator<DotvvmProperty> GetEnumerator()
{
foreach (var x in control.properties)
{
yield return x.Key;
}
}
public bool Remove(DotvvmProperty item) => throw new NotSupportedException("Explicitly use control.Properties.Remove() instead.");
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

public struct ValuesCollection : ICollection<object?>
{
private readonly DotvvmBindableObject control;

public ValuesCollection(DotvvmBindableObject control) { this.control = control; }
public int Count => control.properties.Count();

public bool IsReadOnly => true;
public void Add(object? item) => throw new NotSupportedException("Adding a value without property doesn't make sense");
public void Clear() => throw new NotSupportedException("Explicitly use control.Properties.Clear() instead.");
public bool Contains(object? item)
{
foreach (var x in control.properties)
{
if (Object.Equals(x.Value, item))
return true;
}
return false;
}
public void CopyTo(object?[] array, int arrayIndex)
{
foreach (var x in control.properties)
{
array[arrayIndex++] = x.Value;
}
}
public IEnumerator<object?> GetEnumerator()
{
foreach (var x in control.properties)
{
yield return x.Value;
}
}
public bool Remove(object? item) => throw new NotSupportedException("Explicitly use control.Properties.Remove() instead.");
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,13 @@ public void PopulateViewModel(IDotvvmRequestContext context, string serializedPo
var target = view.FindControlByUniqueId(controlUniqueId);
if (target == null)
{
throw new Exception(string.Format("The control with ID '{0}' was not found!", controlUniqueId));
var markupControls =
view.GetAllDescendants()
.OfType<DotvvmMarkupControl>()
.Where(c => c.GetAllDescendants(cc => cc is not DotvvmMarkupControl)
.Any(cc => cc.Properties.Values
.Any(value => value is Binding.Expressions.CommandBindingExpression cb && cb.BindingId == command)));
throw new Exception($"The control with ID '{controlUniqueId}' was not found! Existing markup controls with this command are: {string.Join(", ", markupControls.Select(c => c.GetDotvvmUniqueId().ToString()).OrderBy(s => s, StringComparer.Ordinal))}");
}
return commandResolver.GetFunction(target, view, context, path, command, args);
}
Expand Down

0 comments on commit 14a7721

Please sign in to comment.