From 9f7dab309684cc84a0f7ca1f5804fef5cd19f87e Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Fri, 26 Jan 2018 10:10:06 -0800 Subject: [PATCH] Better error handling when setting properties on child components --- .../Rendering/Renderer.cs | 20 +++++++++- .../RenderTreeDiffComputerTest.cs | 39 ++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Blazor/Rendering/Renderer.cs b/src/Microsoft.AspNetCore.Blazor/Rendering/Renderer.cs index 98372bcf48..7dfdc43153 100644 --- a/src/Microsoft.AspNetCore.Blazor/Rendering/Renderer.cs +++ b/src/Microsoft.AspNetCore.Blazor/Rendering/Renderer.cs @@ -104,9 +104,25 @@ namespace Microsoft.AspNetCore.Blazor.Rendering private void SetPropertyOnComponent(IComponent component, in RenderTreeNode attributeNode) { - // TODO: Cache the reflection + // TODO: Is it beneficial to cache the reflection? var property = component.GetType().GetProperty(attributeNode.AttributeName); - property.SetValue(component, attributeNode.AttributeValue); + if (property == null) + { + throw new InvalidOperationException( + $"Component of type '{component.GetType().FullName}' does not have a property " + + $"matching the name '{attributeNode.AttributeName}'."); + } + + try + { + property.SetValue(component, attributeNode.AttributeValue); + } + catch (Exception ex) + { + throw new InvalidOperationException( + $"Unable to set property '{attributeNode.AttributeName}' on component of " + + $"type '{component.GetType().FullName}'. The error was: {ex.Message}", ex); + } } } } diff --git a/test/Microsoft.AspNetCore.Blazor.Test/RenderTreeDiffComputerTest.cs b/test/Microsoft.AspNetCore.Blazor.Test/RenderTreeDiffComputerTest.cs index f341aa7e07..5f791a9127 100644 --- a/test/Microsoft.AspNetCore.Blazor.Test/RenderTreeDiffComputerTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.Test/RenderTreeDiffComputerTest.cs @@ -702,9 +702,46 @@ namespace Microsoft.AspNetCore.Blazor.Test } [Fact] - public void RejectsUnknownPropertiesOnChildComponents() + public void ThrowsIfAssigningUnknownPropertiesToChildComponents() { + // Arrange + var renderer = new FakeRenderer(); + var oldTree = new RenderTreeBuilder(renderer); + var newTree = new RenderTreeBuilder(renderer); + var diff = new RenderTreeDiffComputer(renderer); + var testObject = new object(); + newTree.OpenComponentElement(0); + newTree.AddAttribute(1, "SomeUnknownProperty", 123); + newTree.CloseElement(); + // Act/Assert + var ex = Assert.Throws(() => + { + diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes()); + }); + Assert.Equal($"Component of type '{typeof(FakeComponent).FullName}' does not have a property matching the name 'SomeUnknownProperty'.", ex.Message); + } + + [Fact] + public void ThrowsIfAssigningReadOnlyPropertiesToChildComponents() + { + // Arrange + var renderer = new FakeRenderer(); + var oldTree = new RenderTreeBuilder(renderer); + var newTree = new RenderTreeBuilder(renderer); + var diff = new RenderTreeDiffComputer(renderer); + var testObject = new object(); + newTree.OpenComponentElement(0); + newTree.AddAttribute(1, nameof(FakeComponent.ReadonlyProperty), 123); + newTree.CloseElement(); + + // Act/Assert + var ex = Assert.Throws(() => + { + diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes()); + }); + Assert.StartsWith($"Unable to set property '{nameof(FakeComponent.ReadonlyProperty)}' on " + + $"component of type '{typeof(FakeComponent).FullName}'.", ex.Message); } [Fact]