Browse Source

Fix Ignitor bug (#25933)

The implementation of the Ignitor has a few differences compared to BrowserRenderer
which results in exceptions. This change addresses these issue. In addition, this
adds a minimal sample that makes it easier to test Ignitor without having to
package it.
Pranav K 5 years ago
parent
commit
741d98f53a

+ 29 - 14
AspNetCore.sln

@@ -1507,7 +1507,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.App.Un
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Localization", "Localization", "{3D34C81F-2CB5-459E-87E9-0CC04757A2A0}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GlobalizationWasmApp", "src\Components\test\testassets\GlobalizationWasmApp\GlobalizationWasmApp.csproj", "{04CFE286-6D32-41EF-8887-4B5F8086A365}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GlobalizationWasmApp", "src\Components\test\testassets\GlobalizationWasmApp\GlobalizationWasmApp.csproj", "{04CFE286-6D32-41EF-8887-4B5F8086A365}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Localization.Abstractions", "src\Localization\Abstractions\src\Microsoft.Extensions.Localization.Abstractions.csproj", "{FEF97646-9BC9-4D1B-A939-784D915C18A4}"
 EndProject
@@ -1551,6 +1551,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{E83B0BCC-A8E
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostingStartup", "src\SiteExtensions\Sdk\HostingStartup\HostingStartup.csproj", "{5D6F99C5-D292-4459-B8BD-8E4AD42E1B21}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IgnitorSample", "src\Components\Samples\IgnitorSample\IgnitorSample.csproj", "{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -7223,18 +7225,6 @@ Global
 		{BAD47859-95DF-4C8F-9AF7-C48B68F478A1}.Release|x64.Build.0 = Release|Any CPU
 		{BAD47859-95DF-4C8F-9AF7-C48B68F478A1}.Release|x86.ActiveCfg = Release|Any CPU
 		{BAD47859-95DF-4C8F-9AF7-C48B68F478A1}.Release|x86.Build.0 = Release|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x64.Build.0 = Debug|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x86.Build.0 = Debug|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|Any CPU.Build.0 = Release|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x64.ActiveCfg = Release|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x64.Build.0 = Release|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x86.ActiveCfg = Release|Any CPU
-		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x86.Build.0 = Release|Any CPU
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -7247,6 +7237,18 @@ Global
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0}.Release|x64.Build.0 = Release|Any CPU
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0}.Release|x86.ActiveCfg = Release|Any CPU
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0}.Release|x86.Build.0 = Release|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x64.Build.0 = Debug|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Debug|x86.Build.0 = Debug|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|Any CPU.Build.0 = Release|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x64.ActiveCfg = Release|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x64.Build.0 = Release|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x86.ActiveCfg = Release|Any CPU
+		{04CFE286-6D32-41EF-8887-4B5F8086A365}.Release|x86.Build.0 = Release|Any CPU
 		{FEF97646-9BC9-4D1B-A939-784D915C18A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{FEF97646-9BC9-4D1B-A939-784D915C18A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{FEF97646-9BC9-4D1B-A939-784D915C18A4}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -7427,6 +7429,18 @@ Global
 		{5D6F99C5-D292-4459-B8BD-8E4AD42E1B21}.Release|x64.Build.0 = Release|Any CPU
 		{5D6F99C5-D292-4459-B8BD-8E4AD42E1B21}.Release|x86.ActiveCfg = Release|Any CPU
 		{5D6F99C5-D292-4459-B8BD-8E4AD42E1B21}.Release|x86.Build.0 = Release|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Debug|x64.Build.0 = Debug|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Debug|x86.Build.0 = Debug|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Release|x64.ActiveCfg = Release|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Release|x64.Build.0 = Release|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Release|x86.ActiveCfg = Release|Any CPU
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -8179,10 +8193,10 @@ Global
 		{37329855-01B8-4B03-9765-1A941B06E43C} = {8C15FD04-7F90-43FC-B488-023432FE3CE1}
 		{D3246226-BC1A-47F1-8E3E-C3380A8F13FB} = {8C15FD04-7F90-43FC-B488-023432FE3CE1}
 		{B06ADD57-E855-4D8C-85DC-B323509AE540} = {898F7E0B-1671-42CB-9DFB-689AFF212ED3}
-		{04CFE286-6D32-41EF-8887-4B5F8086A365} = {6126DCE4-9692-4EE2-B240-C65743572995}
 		{BAD47859-95DF-4C8F-9AF7-C48B68F478A1} = {A4C26078-B6D8-4FD8-87A6-7C15A3482038}
 		{010A9638-F20E-4FE6-A186-85732BFC9CB0} = {A4C26078-B6D8-4FD8-87A6-7C15A3482038}
 		{3D34C81F-2CB5-459E-87E9-0CC04757A2A0} = {017429CC-C5FB-48B4-9C46-034E29EE2F06}
+		{04CFE286-6D32-41EF-8887-4B5F8086A365} = {6126DCE4-9692-4EE2-B240-C65743572995}
 		{FEF97646-9BC9-4D1B-A939-784D915C18A4} = {3D34C81F-2CB5-459E-87E9-0CC04757A2A0}
 		{839CE175-E0D9-43B9-9FA8-F32C47E7F56B} = {3D34C81F-2CB5-459E-87E9-0CC04757A2A0}
 		{50BF2926-7435-4F4B-88A9-3D0EDEB67FC8} = {3D34C81F-2CB5-459E-87E9-0CC04757A2A0}
@@ -8204,6 +8218,7 @@ Global
 		{545751D5-71FC-4889-A3A0-BBD731DBA18A} = {56B45580-B089-424E-A847-A6115D591950}
 		{E83B0BCC-A8E0-4FBD-BE51-9A533C9CB972} = {DFC4F588-B4B4-484B-AB93-B36721374AD3}
 		{5D6F99C5-D292-4459-B8BD-8E4AD42E1B21} = {E83B0BCC-A8E0-4FBD-BE51-9A533C9CB972}
+		{CAFD1885-B87B-4A7A-8BE6-86B0C238C2B1} = {5FE1FBC1-8CE3-4355-9866-44FE1307C5F1}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

+ 2 - 1
src/Components/ComponentsNoDeps.slnf

@@ -14,6 +14,7 @@
       "src\\Components\\Ignitor\\src\\Ignitor.csproj",
       "src\\Components\\Ignitor\\test\\Ignitor.Test.csproj",
       "src\\Components\\Samples\\BlazorServerApp\\BlazorServerApp.csproj",
+      "src\\Components\\Samples\\IgnitorSample\\IgnitorSample.csproj",
       "src\\Components\\Server\\src\\Microsoft.AspNetCore.Components.Server.csproj",
       "src\\Components\\Server\\test\\Microsoft.AspNetCore.Components.Server.Tests.csproj",
       "src\\Components\\Web.Extensions\\src\\Microsoft.AspNetCore.Components.Web.Extensions.csproj",
@@ -49,4 +50,4 @@
       "src\\Components\\test\\testassets\\TestServer\\Components.TestServer.csproj"
     ]
   }
-}
+}

+ 5 - 2
src/Components/Ignitor/src/BlazorClient.cs

@@ -2,6 +2,7 @@
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 using System;
+using System.Diagnostics;
 using System.Linq;
 using System.Net.Http;
 using System.Text.Json;
@@ -35,8 +36,10 @@ namespace Ignitor
             });
         }
 
-        public TimeSpan? DefaultConnectionTimeout { get; set; } = TimeSpan.FromSeconds(20);
-        public TimeSpan? DefaultOperationTimeout { get; set; } = TimeSpan.FromMilliseconds(500);
+        public TimeSpan? DefaultConnectionTimeout { get; set; } = Debugger.IsAttached ?
+            Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(20);
+        public TimeSpan? DefaultOperationTimeout { get; set; } = Debugger.IsAttached ?
+            Timeout.InfiniteTimeSpan : TimeSpan.FromMilliseconds(500);
 
         /// <summary>
         /// Gets or sets a value that determines whether the client will capture data such

+ 12 - 2
src/Components/Ignitor/src/ElementHive.cs

@@ -259,7 +259,7 @@ namespace Ignitor
 
                 case RenderTreeFrameType.Region:
                     {
-                        return InsertFrameRange(batch, parent, childIndex, frames, frameIndex + 1, frameIndex + CountDescendantFrames(frame));
+                        return InsertFrameRange(batch, parent, childIndex, frames, frameIndex + 1, frameIndex + frame.RegionSubtreeLength);
                     }
 
                 case RenderTreeFrameType.ElementReferenceCapture:
@@ -322,7 +322,8 @@ namespace Ignitor
         {
             // Note: we don't handle SVG here
             var newElement = new ElementNode(frame.ElementName);
-            parent.InsertLogicalChild(newElement, childIndex);
+
+            var inserted = false;
 
             // Apply attributes
             for (var i = frameIndex + 1; i < frameIndex + frame.ElementSubtreeLength; i++)
@@ -334,12 +335,21 @@ namespace Ignitor
                 }
                 else
                 {
+                    parent.InsertLogicalChild(newElement, childIndex);
+                    inserted = true;
+
                     // As soon as we see a non-attribute child, all the subsequent child frames are
                     // not attributes, so bail out and insert the remnants recursively
                     InsertFrameRange(batch, newElement, 0, frames, i, frameIndex + frame.ElementSubtreeLength);
                     break;
                 }
             }
+
+            // this element did not have any children, so it's not inserted yet.
+            if (!inserted)
+            {
+                parent.InsertLogicalChild(newElement, childIndex);
+            }
         }
 
         private void ApplyAttribute(RenderBatch batch, ElementNode elementNode, RenderTreeFrame attributeFrame)

+ 1 - 1
src/Components/Samples/BlazorServerApp/Pages/Counter.razor

@@ -2,7 +2,7 @@
 
 <h1>Counter</h1>
 
-<p>Current count: @currentCount</p>
+<p id="counter">Current count: @currentCount</p>
 
 <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
 

+ 14 - 0
src/Components/Samples/IgnitorSample/IgnitorSample.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+    <IsShippingPackage>false</IsShippingPackage>
+    <Nullable>enable</Nullable>
+    <OutputType>Exe</OutputType>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Reference Include="Ignitor" />
+  </ItemGroup>
+
+</Project>

+ 45 - 0
src/Components/Samples/IgnitorSample/Program.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Diagnostics;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Ignitor;
+using Microsoft.AspNetCore.SignalR.Client;
+
+namespace IgnitorSample
+{
+    /// <summary>
+    /// This is a minimal sample that lets you try out Ignitor against a Blazor Server app.
+    /// To use this, first launch the server app. Update the code below to point to the host url and run the test.
+    /// </summary>
+    class Program
+    {
+        private static readonly string ServerUrl = "https://localhost:5001";
+        private static readonly JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);
+
+        static async Task Main(string[] args)
+        {
+            var client = new BlazorClient();
+            await client.ConnectAsync(new Uri(ServerUrl));
+
+            await VerifyNavigationAsync(client);
+
+            Console.WriteLine("Done");
+        }
+
+        static async ValueTask VerifyNavigationAsync(BlazorClient client)
+        {
+            await client.ExpectRenderBatch(() => client.NavigateAsync($"{ServerUrl}/counter"));
+            client.Hive.TryFindElementById("counter", out var counter);
+            Debug.Assert(counter != null, "We must have navigated to counter.");
+        }
+    }
+
+    static class BlazorClientExtensions
+    {
+        public static Task NavigateAsync(this BlazorClient client, string url, CancellationToken cancellationToken = default)
+        {
+            return client.HubConnection.InvokeAsync("OnLocationChanged", url, false, cancellationToken);
+        }
+    }
+}