From 2d4b110b94ff406d1bc458992070f27d8f73b048 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Tue, 29 Oct 2019 17:16:58 +0000 Subject: [PATCH] Correctly handle AddMultipleAttributes terminated by OpenRegion. Fixes #16570 --- .../src/Rendering/RenderTreeBuilder.cs | 8 +++++ .../test/Rendering/RenderTreeBuilderTest.cs | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs index 6876c97f0d..f8a28273e4 100644 --- a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs +++ b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs @@ -581,6 +581,14 @@ namespace Microsoft.AspNetCore.Components.Rendering /// An integer that represents the position of the instruction in the source code. public void OpenRegion(int sequence) { + // We are entering a new scope, since we track the "duplicate attributes" per + // element/component we might need to clean them up now. + if (_hasSeenAddMultipleAttributes) + { + var indexOfLastElementOrComponent = _openElementIndices.Peek(); + ProcessDuplicateAttributes(first: indexOfLastElementOrComponent + 1); + } + _openElementIndices.Push(_entries.Count); Append(RenderTreeFrame.Region(sequence)); } diff --git a/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs b/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs index 7dfce8a79c..31364dca00 100644 --- a/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs +++ b/src/Components/Components/test/Rendering/RenderTreeBuilderTest.cs @@ -298,6 +298,39 @@ namespace Microsoft.AspNetCore.Components.Rendering frame => AssertFrame.Attribute(frame, "attribute7", "the end")); } + [Fact] + public void CanAddMultipleAttributes_WithChildRegion() + { + // This represents bug https://github.com/aspnet/AspNetCore/issues/16570 + // If a sequence of attributes is terminated by a call to builder.OpenRegion, + // then the attribute deduplication logic wasn't working correctly + + // Arrange + var builder = new RenderTreeBuilder(); + + // Act + builder.OpenElement(0, "myelement"); + builder.AddAttribute(0, "attribute1", "value1"); + builder.AddMultipleAttributes(1, new Dictionary() + { + { "attribute1", "value2" }, + }); + builder.OpenRegion(2); + builder.OpenElement(3, "child"); + builder.CloseElement(); + builder.CloseRegion(); + builder.CloseElement(); + + // Assert + var frames = builder.GetFrames().AsEnumerable().ToArray(); + Assert.Collection( + frames, + frame => AssertFrame.Element(frame, "myelement", 4), + frame => AssertFrame.Attribute(frame, "attribute1", "value2"), + frame => AssertFrame.Region(frame, 2, 2), + frame => AssertFrame.Element(frame, "child", 1, 3)); + } + [Fact] public void CanAddMultipleAttributes_DictionaryObject() {