diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props index d1d79ea73f..ce14f22333 100644 --- a/eng/ProjectReferences.props +++ b/eng/ProjectReferences.props @@ -15,6 +15,7 @@ + diff --git a/src/Components/Components.sln b/src/Components/Components.sln index f00b28bd36..e6aa7ab8d1 100644 --- a/src/Components/Components.sln +++ b/src/Components/Components.sln @@ -214,9 +214,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Signal EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Connections.Client", "..\SignalR\clients\csharp\Http.Connections.Client\src\Microsoft.AspNetCore.Http.Connections.Client.csproj", "{F88118E1-6F4A-4F89-B047-5FFD2889B9F0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor", "test\testassets\Ignitor\Ignitor.csproj", "{A78CE874-76B7-46FE-8009-1ED5258BA0AA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor", "Ignitor\src\Ignitor.csproj", "{A78CE874-76B7-46FE-8009-1ED5258BA0AA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor.Test", "test\Ignitor.Test\Ignitor.Test.csproj", "{FC2A1EB0-A116-4689-92B7-239B1DCCF4CA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ignitor.Test", "Ignitor\test\Ignitor.Test.csproj", "{FC2A1EB0-A116-4689-92B7-239B1DCCF4CA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.HttpClient", "Blazor\Http\src\Microsoft.AspNetCore.Blazor.HttpClient.csproj", "{74D21785-2FAB-4266-B7C4-E311EC8EE0DF}" EndProject @@ -236,6 +236,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Compon EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Forms.Tests", "Forms\test\Microsoft.AspNetCore.Components.Forms.Tests.csproj", "{173D84A3-0F37-480F-AC0F-7E2DBBE32B28}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ignitor", "Ignitor", "{D6712550-0DA2-49C8-88E1-F04CAB982BF4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1583,8 +1585,8 @@ Global {DA137BD4-F7F1-4D53-855F-5EC40CEA36B0} = {2FC10057-7A0A-4E34-8302-879925BC0102} {0CDAB70B-71DC-43BE-ACB7-AD2EE3541FFB} = {2FC10057-7A0A-4E34-8302-879925BC0102} {F88118E1-6F4A-4F89-B047-5FFD2889B9F0} = {2FC10057-7A0A-4E34-8302-879925BC0102} - {A78CE874-76B7-46FE-8009-1ED5258BA0AA} = {44E0D4F3-4430-4175-B482-0D1AEE4BB699} - {FC2A1EB0-A116-4689-92B7-239B1DCCF4CA} = {E9E9CF3C-CE9B-4282-B2BB-97EFC3872798} + {A78CE874-76B7-46FE-8009-1ED5258BA0AA} = {D6712550-0DA2-49C8-88E1-F04CAB982BF4} + {FC2A1EB0-A116-4689-92B7-239B1DCCF4CA} = {D6712550-0DA2-49C8-88E1-F04CAB982BF4} {74D21785-2FAB-4266-B7C4-E311EC8EE0DF} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} {E4C01A3F-D3C1-4639-A6A9-930E918843DD} = {7260DED9-22A9-4E9D-92F4-5E8A4404DEAF} {DE297C91-B3E9-4C6F-B74D-0AF9EFEBF684} = {A27FF193-195B-4474-8E6C-840B2E339373} diff --git a/src/Components/Components/src/Properties/AssemblyInfo.cs b/src/Components/Components/src/Properties/AssemblyInfo.cs index ef782190ea..d5aa38e01d 100644 --- a/src/Components/Components/src/Properties/AssemblyInfo.cs +++ b/src/Components/Components/src/Properties/AssemblyInfo.cs @@ -7,5 +7,3 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Server.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Web.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Ignitor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Ignitor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs b/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs index 3fb698d3ee..2252000716 100644 --- a/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs +++ b/src/Components/Components/src/RenderTree/ArrayBuilderExtensions.cs @@ -3,7 +3,11 @@ using System; +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { internal static class ArrayBuilderExtensions { diff --git a/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs b/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs index 3377e18163..4820e2f5fd 100644 --- a/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs +++ b/src/Components/Components/src/RenderTree/ArrayBuilderSegment.cs @@ -5,7 +5,11 @@ using System; using System.Collections; using System.Collections.Generic; +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/ArrayRange.cs b/src/Components/Components/src/RenderTree/ArrayRange.cs index b27a8d5310..a980a92246 100644 --- a/src/Components/Components/src/RenderTree/ArrayRange.cs +++ b/src/Components/Components/src/RenderTree/ArrayRange.cs @@ -1,7 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/RenderBatch.cs b/src/Components/Components/src/RenderTree/RenderBatch.cs index 092c6ec378..55f3c02629 100644 --- a/src/Components/Components/src/RenderTree/RenderBatch.cs +++ b/src/Components/Components/src/RenderTree/RenderBatch.cs @@ -1,7 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiff.cs b/src/Components/Components/src/RenderTree/RenderTreeDiff.cs index da5b3ed3f7..4947029ab2 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeDiff.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeDiff.cs @@ -1,7 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/RenderTreeEdit.cs b/src/Components/Components/src/RenderTree/RenderTreeEdit.cs index 68437a7471..93b1dd9da6 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeEdit.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeEdit.cs @@ -3,7 +3,11 @@ using System.Runtime.InteropServices; +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/RenderTreeEditType.cs b/src/Components/Components/src/RenderTree/RenderTreeEditType.cs index f508760135..f3d48172fb 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeEditType.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeEditType.cs @@ -1,7 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/RenderTreeFrame.cs b/src/Components/Components/src/RenderTree/RenderTreeFrame.cs index 39dd7de74a..c9a358c698 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeFrame.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeFrame.cs @@ -3,9 +3,15 @@ using System; using System.Runtime.InteropServices; +#if !IGNITOR using Microsoft.AspNetCore.Components.Rendering; +#endif +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs b/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs index 339a7b6795..e73119e038 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeFrameType.cs @@ -1,7 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.RenderTree +#endif { /// /// Types in the Microsoft.AspNetCore.Components.RenderTree are not recommended for use outside diff --git a/src/Components/ComponentsNoDeps.slnf b/src/Components/ComponentsNoDeps.slnf index f41ac99b30..7502dc1eaf 100644 --- a/src/Components/ComponentsNoDeps.slnf +++ b/src/Components/ComponentsNoDeps.slnf @@ -36,8 +36,8 @@ "test\\testassets\\ComponentsApp.Server\\ComponentsApp.Server.csproj", "test\\testassets\\TestContentPackage\\TestContentPackage.csproj", "test\\testassets\\TestServer\\Components.TestServer.csproj", - "test\\testassets\\Ignitor\\Ignitor.csproj", - "test\\Ignitor.Test\\Ignitor.Test.csproj" + "Ignitor\\src\\Ignitor.csproj", + "Ignitor\\test\\Ignitor.Test.csproj" ] } } \ No newline at end of file diff --git a/src/Components/test/testassets/Ignitor/BlazorClient.cs b/src/Components/Ignitor/src/BlazorClient.cs similarity index 94% rename from src/Components/test/testassets/Ignitor/BlazorClient.cs rename to src/Components/Ignitor/src/BlazorClient.cs index 3f96604574..861e2ad0f2 100644 --- a/src/Components/test/testassets/Ignitor/BlazorClient.cs +++ b/src/Components/Ignitor/src/BlazorClient.cs @@ -16,7 +16,7 @@ using Microsoft.Extensions.Logging; namespace Ignitor { - public class BlazorClient + public class BlazorClient : IAsyncDisposable { private const string MarkerPattern = ".*?.*?"; @@ -54,6 +54,8 @@ namespace Ignitor private TaskCompletionSource TaskCompletionSource { get; } + private CancellableOperation NextAttachComponentReceived { get; set; } + private CancellableOperation NextBatchReceived { get; set; } private CancellableOperation NextErrorReceived { get; set; } @@ -82,7 +84,7 @@ namespace Ignitor public bool ImplicitWait => DefaultOperationTimeout != null; - public HubConnection HubConnection { get; set; } + public HubConnection HubConnection { get; private set; } public Task PrepareForNextBatch(TimeSpan? timeout) { @@ -345,6 +347,7 @@ namespace Ignitor HubConnection = builder.Build(); await HubConnection.StartAsync(CancellationToken); + HubConnection.On("JS.AttachComponent", OnAttachComponent); HubConnection.On("JS.BeginInvokeJS", OnBeginInvokeJS); HubConnection.On("JS.EndInvokeDotNet", OnEndInvokeDotNet); HubConnection.On("JS.RenderBatch", OnRenderBatch); @@ -376,6 +379,14 @@ namespace Ignitor NextDotNetInteropCompletionReceived?.Completion?.TrySetResult(null); } + private void OnAttachComponent(int componentId, string domSelector) + { + var call = new CapturedAttachComponentCall(componentId, domSelector); + Operations?.AttachComponent.Enqueue(call); + + NextAttachComponentReceived?.Completion?.TrySetResult(call); + } + private void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson) { var call = new CapturedJSInteropCall(asyncHandle, identifier, argsJson); @@ -421,6 +432,7 @@ namespace Ignitor NextBatchReceived?.Completion?.TrySetException(exception); NextDotNetInteropCompletionReceived?.Completion.TrySetException(exception); NextJSInteropReceived?.Completion.TrySetException(exception); + NextAttachComponentReceived?.Completion?.TrySetException(exception); NextErrorReceived?.Completion?.TrySetResult(null); } @@ -481,7 +493,7 @@ namespace Ignitor { if (!Hive.TryFindElementById(id, out var element)) { - throw new InvalidOperationException("Element not found."); + throw new InvalidOperationException($"Element with id '{id}' was not found."); } return element; @@ -544,8 +556,9 @@ namespace Ignitor var markers = matches.Select(s => (value: s.Groups[1].Value, parsed: JsonDocument.Parse(s.Groups[1].Value))) .Where(s => { - var markerType = s.parsed.RootElement.GetProperty("type"); - return markerType.ValueKind != JsonValueKind.Undefined && markerType.GetString() == "server"; + return s.parsed.RootElement.TryGetProperty("type", out var markerType) && + markerType.ValueKind != JsonValueKind.Undefined && + markerType.GetString() == "server"; }) .OrderBy(p => p.parsed.RootElement.GetProperty("sequence").GetInt32()) .Select(p => p.value) @@ -553,5 +566,13 @@ namespace Ignitor return markers; } + + public async ValueTask DisposeAsync() + { + if (HubConnection != null) + { + await HubConnection.DisposeAsync(); + } + } } } diff --git a/src/Components/Ignitor/src/CapturedAttachComponentCall.cs b/src/Components/Ignitor/src/CapturedAttachComponentCall.cs new file mode 100644 index 0000000000..b3897c9579 --- /dev/null +++ b/src/Components/Ignitor/src/CapturedAttachComponentCall.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Ignitor +{ + public readonly struct CapturedAttachComponentCall + { + public CapturedAttachComponentCall(int componentId, string selector) + { + ComponentId = componentId; + Selector = selector; + } + + public int ComponentId { get; } + public string Selector { get; } + } +} diff --git a/src/Components/test/testassets/Ignitor/CapturedJSInteropCall.cs b/src/Components/Ignitor/src/CapturedJSInteropCall.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/CapturedJSInteropCall.cs rename to src/Components/Ignitor/src/CapturedJSInteropCall.cs diff --git a/src/Components/test/testassets/Ignitor/CapturedRenderBatch.cs b/src/Components/Ignitor/src/CapturedRenderBatch.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/CapturedRenderBatch.cs rename to src/Components/Ignitor/src/CapturedRenderBatch.cs diff --git a/src/Components/test/testassets/Ignitor/CommentNode.cs b/src/Components/Ignitor/src/CommentNode.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/CommentNode.cs rename to src/Components/Ignitor/src/CommentNode.cs diff --git a/src/Components/test/testassets/Ignitor/ComponentNode.cs b/src/Components/Ignitor/src/ComponentNode.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/ComponentNode.cs rename to src/Components/Ignitor/src/ComponentNode.cs diff --git a/src/Components/Ignitor/src/ComponentState.cs b/src/Components/Ignitor/src/ComponentState.cs new file mode 100644 index 0000000000..2acae3af21 --- /dev/null +++ b/src/Components/Ignitor/src/ComponentState.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Ignitor +{ + public class ComponentState + { + public ComponentState(int componentId) + { + ComponentId = componentId; + } + + public int ComponentId { get; } + public IComponent Component { get; } + } +} diff --git a/src/Components/test/testassets/Ignitor/ContainerNode.cs b/src/Components/Ignitor/src/ContainerNode.cs similarity index 98% rename from src/Components/test/testassets/Ignitor/ContainerNode.cs rename to src/Components/Ignitor/src/ContainerNode.cs index 0a8f8a2580..9e933dee23 100644 --- a/src/Components/test/testassets/Ignitor/ContainerNode.cs +++ b/src/Components/Ignitor/src/ContainerNode.cs @@ -41,7 +41,7 @@ namespace Ignitor if (childIndex < Children.Count) { // Insert - _children[childIndex] = child; + _children.Insert(childIndex, child); } else { diff --git a/src/Components/test/testassets/Ignitor/ElementHive.cs b/src/Components/Ignitor/src/ElementHive.cs similarity index 99% rename from src/Components/test/testassets/Ignitor/ElementHive.cs rename to src/Components/Ignitor/src/ElementHive.cs index 90ab247c51..95c4c02397 100644 --- a/src/Components/test/testassets/Ignitor/ElementHive.cs +++ b/src/Components/Ignitor/src/ElementHive.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; namespace Ignitor { diff --git a/src/Components/test/testassets/Ignitor/ElementNode.cs b/src/Components/Ignitor/src/ElementNode.cs similarity index 90% rename from src/Components/test/testassets/Ignitor/ElementNode.cs rename to src/Components/Ignitor/src/ElementNode.cs index d97197619d..cebcaef323 100644 --- a/src/Components/test/testassets/Ignitor/ElementNode.cs +++ b/src/Components/Ignitor/src/ElementNode.cs @@ -5,10 +5,6 @@ using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.SignalR.Client; namespace Ignitor @@ -71,17 +67,17 @@ namespace Ignitor throw new InvalidOperationException("Element does not have a change event."); } - var args = new ChangeEventArgs() + var args = new { Value = value }; - var webEventDescriptor = new WebEventDescriptor() + var webEventDescriptor = new { BrowserRendererId = 0, EventHandlerId = changeEventDescriptor.EventId, EventArgsType = "change", - EventFieldInfo = new EventFieldInfo + EventFieldInfo = new { ComponentId = 0, FieldValue = value @@ -98,12 +94,12 @@ namespace Ignitor throw new InvalidOperationException("Element does not have a click event."); } - var mouseEventArgs = new MouseEventArgs() + var mouseEventArgs = new { Type = clickEventDescriptor.EventName, Detail = 1 }; - var webEventDescriptor = new WebEventDescriptor + var webEventDescriptor = new { BrowserRendererId = 0, EventHandlerId = clickEventDescriptor.EventId, diff --git a/src/Components/Ignitor/src/ElementReference.cs b/src/Components/Ignitor/src/ElementReference.cs new file mode 100644 index 0000000000..8b0f769a9f --- /dev/null +++ b/src/Components/Ignitor/src/ElementReference.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Ignitor +{ + /// + /// Represents a reference to a rendered element. + /// + public readonly struct ElementReference + { + /// + /// Gets a unique identifier for . + /// + /// + /// The Id is unique at least within the scope of a given user/circuit. + /// This property is public to support Json serialization and should not be used by user code. + /// + public string Id { get; } + + public ElementReference(string id) + { + Id = id; + } + } +} diff --git a/src/Components/test/testassets/Ignitor/Error.cs b/src/Components/Ignitor/src/Error.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/Error.cs rename to src/Components/Ignitor/src/Error.cs diff --git a/src/Components/Ignitor/src/IComponent.cs b/src/Components/Ignitor/src/IComponent.cs new file mode 100644 index 0000000000..ce9b3d324c --- /dev/null +++ b/src/Components/Ignitor/src/IComponent.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Ignitor +{ + public interface IComponent + { + } +} diff --git a/src/Components/Ignitor/src/Ignitor.csproj b/src/Components/Ignitor/src/Ignitor.csproj new file mode 100644 index 0000000000..33688dd3ad --- /dev/null +++ b/src/Components/Ignitor/src/Ignitor.csproj @@ -0,0 +1,34 @@ + + + + netcoreapp3.0 + true + false + false + $(DefineConstants);IGNITOR + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Components/test/testassets/Ignitor/IgnitorMessagePackHubProtocol.cs b/src/Components/Ignitor/src/IgnitorMessagePackHubProtocol.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/IgnitorMessagePackHubProtocol.cs rename to src/Components/Ignitor/src/IgnitorMessagePackHubProtocol.cs diff --git a/src/Components/test/testassets/Ignitor/MarkupNode.cs b/src/Components/Ignitor/src/MarkupNode.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/MarkupNode.cs rename to src/Components/Ignitor/src/MarkupNode.cs diff --git a/src/Components/test/testassets/Ignitor/Node.cs b/src/Components/Ignitor/src/Node.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/Node.cs rename to src/Components/Ignitor/src/Node.cs diff --git a/src/Components/test/testassets/Ignitor/NodeSerializer.cs b/src/Components/Ignitor/src/NodeSerializer.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/NodeSerializer.cs rename to src/Components/Ignitor/src/NodeSerializer.cs diff --git a/src/Components/test/testassets/Ignitor/Operations.cs b/src/Components/Ignitor/src/Operations.cs similarity index 83% rename from src/Components/test/testassets/Ignitor/Operations.cs rename to src/Components/Ignitor/src/Operations.cs index 4dcf8798b5..efcb5346fb 100644 --- a/src/Components/test/testassets/Ignitor/Operations.cs +++ b/src/Components/Ignitor/src/Operations.cs @@ -7,6 +7,8 @@ namespace Ignitor { public sealed class Operations { + public ConcurrentQueue AttachComponent { get; } = new ConcurrentQueue(); + public ConcurrentQueue Batches { get; } = new ConcurrentQueue(); public ConcurrentQueue DotNetCompletions { get; } = new ConcurrentQueue(); diff --git a/src/Components/test/testassets/Ignitor/Properties/AssemblyInfo.cs b/src/Components/Ignitor/src/Properties/AssemblyInfo.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/Properties/AssemblyInfo.cs rename to src/Components/Ignitor/src/Properties/AssemblyInfo.cs diff --git a/src/Components/test/testassets/Ignitor/RenderBatchReader.cs b/src/Components/Ignitor/src/RenderBatchReader.cs similarity index 90% rename from src/Components/test/testassets/Ignitor/RenderBatchReader.cs rename to src/Components/Ignitor/src/RenderBatchReader.cs index 324f4af88f..1581fc7022 100644 --- a/src/Components/test/testassets/Ignitor/RenderBatchReader.cs +++ b/src/Components/Ignitor/src/RenderBatchReader.cs @@ -3,12 +3,6 @@ using System; using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; namespace Ignitor { @@ -16,8 +10,6 @@ namespace Ignitor { private const int ReferenceFrameSize = 20; - private static readonly Renderer Renderer = new FakeRenderer(); - public static RenderBatch Read(ReadOnlySpan data) { var sections = Sections.Parse(data); @@ -161,7 +153,7 @@ namespace Ignitor var componentId = BitConverter.ToInt32(frameData.Slice(8, 4)); // Nowhere to put this without creating a ComponentState result[i / ReferenceFrameSize] = RenderTreeFrame.ChildComponent(0, componentType: null) .WithComponentSubtreeLength(componentSubtreeLength) - .WithComponent(new ComponentState(Renderer, componentId, new FakeComponent(), null)); + .WithComponent(new ComponentState(componentId)); break; case RenderTreeFrameType.ComponentReferenceCapture: @@ -285,33 +277,5 @@ namespace Ignitor return data.Slice(_strings, data.Length - 20 - _strings); } } - - public class FakeRenderer : Renderer - { - public FakeRenderer() - : base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - protected override void HandleException(Exception exception) - { - throw new NotImplementedException(); - } - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - => throw new NotImplementedException(); - } - - - public class FakeComponent : IComponent - { - public void Attach(RenderHandle renderHandle) - => throw new NotImplementedException(); - - public Task SetParametersAsync(ParameterView parameters) - => throw new NotImplementedException(); - } } } diff --git a/src/Components/test/testassets/Ignitor/TextNode.cs b/src/Components/Ignitor/src/TextNode.cs similarity index 100% rename from src/Components/test/testassets/Ignitor/TextNode.cs rename to src/Components/Ignitor/src/TextNode.cs diff --git a/src/Components/Ignitor/test/Ignitor.Test.csproj b/src/Components/Ignitor/test/Ignitor.Test.csproj new file mode 100644 index 0000000000..1362b03c02 --- /dev/null +++ b/src/Components/Ignitor/test/Ignitor.Test.csproj @@ -0,0 +1,16 @@ + + + + netcoreapp3.0 + $(DefineConstants);IGNITOR + + + + + + + + + + + diff --git a/src/Components/test/Ignitor.Test/RenderBatchReaderTest.cs b/src/Components/Ignitor/test/RenderBatchReaderTest.cs similarity index 89% rename from src/Components/test/Ignitor.Test/RenderBatchReaderTest.cs rename to src/Components/Ignitor/test/RenderBatchReaderTest.cs index a3165c48aa..7a703be6c6 100644 --- a/src/Components/test/Ignitor.Test/RenderBatchReaderTest.cs +++ b/src/Components/Ignitor/test/RenderBatchReaderTest.cs @@ -5,20 +5,13 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; -using Microsoft.AspNetCore.Components.Server.Circuits; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using Xunit; namespace Ignitor { public class RenderBatchReaderTest { - static object NullStringMarker = new object(); + static readonly object NullStringMarker = new object(); // All of these tests are copies from the RenderBatchWriterTest but converted to be round-trippable tests. @@ -102,7 +95,7 @@ namespace Ignitor RenderTreeEdit.UpdateMarkup(108, 109), RenderTreeEdit.RemoveAttribute(110, "Some removed attribute"), // To test deduplication }; - var editsBuilder = new Microsoft.AspNetCore.Components.RenderTree.ArrayBuilder(); + var editsBuilder = new ArrayBuilder(); editsBuilder.Append(edits, 0, edits.Length); var editsSegment = editsBuilder.ToSegment(1, edits.Length); // Skip first to show offset is respected var bytes = RoundTripSerialize(new RenderBatch( @@ -142,7 +135,6 @@ namespace Ignitor public void CanRoundTripReferenceFrames() { // Arrange/Act - var renderer = new FakeRenderer(); var bytes = RoundTripSerialize(new RenderBatch( default, new ArrayRange(new[] { @@ -152,7 +144,7 @@ namespace Ignitor .WithAttributeEventHandlerId((ulong)uint.MaxValue + 1), RenderTreeFrame.ChildComponent(126, typeof(object)) .WithComponentSubtreeLength(5678) - .WithComponent(new ComponentState(renderer, 2000, new FakeComponent(), null)), + .WithComponent(new ComponentState(2000)), RenderTreeFrame.ComponentReferenceCapture(127, value => { }, 1001), RenderTreeFrame.Element(128, "Some element") .WithElementSubtreeLength(1234), @@ -325,32 +317,5 @@ namespace Ignitor return result; } - - class FakeComponent : IComponent - { - public void Attach(RenderHandle renderHandle) - => throw new NotImplementedException(); - - public Task SetParametersAsync(ParameterView parameters) - => throw new NotImplementedException(); - } - - class FakeRenderer : Renderer - { - public FakeRenderer() - : base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance) - { - } - - public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - - protected override void HandleException(Exception exception) - { - throw new NotImplementedException(); - } - - protected override Task UpdateDisplayAsync(in RenderBatch renderBatch) - => throw new NotImplementedException(); - } } } diff --git a/src/Components/Server/src/Circuits/ArrayBuilderMemoryStream.cs b/src/Components/Server/src/Circuits/ArrayBuilderMemoryStream.cs index 2b8f2eed56..4970ce6caa 100644 --- a/src/Components/Server/src/Circuits/ArrayBuilderMemoryStream.cs +++ b/src/Components/Server/src/Circuits/ArrayBuilderMemoryStream.cs @@ -6,6 +6,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.RenderTree; namespace Microsoft.AspNetCore.Components.Server.Circuits { diff --git a/src/Components/Server/src/Circuits/RemoteRenderer.cs b/src/Components/Server/src/Circuits/RemoteRenderer.cs index 31046788a9..3596ffbcc6 100644 --- a/src/Components/Server/src/Circuits/RemoteRenderer.cs +++ b/src/Components/Server/src/Circuits/RemoteRenderer.cs @@ -6,10 +6,10 @@ using System.Collections.Concurrent; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.RenderTree; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; -using Microsoft.JSInterop; namespace Microsoft.AspNetCore.Components.Server.Circuits { diff --git a/src/Components/Server/src/Circuits/RenderBatchWriter.cs b/src/Components/Server/src/Circuits/RenderBatchWriter.cs index 4238447c81..97ff9ac09d 100644 --- a/src/Components/Server/src/Circuits/RenderBatchWriter.cs +++ b/src/Components/Server/src/Circuits/RenderBatchWriter.cs @@ -5,9 +5,15 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +#if !IGNITOR using Microsoft.AspNetCore.Components.RenderTree; +#endif +#if IGNITOR +namespace Ignitor +#else namespace Microsoft.AspNetCore.Components.Server.Circuits +#endif { // TODO: We should consider *not* having this type of infrastructure in the .Server // project, but instead in some new project called .Remote or similar, since it diff --git a/src/Components/Shared/src/ArrayBuilder.cs b/src/Components/Shared/src/ArrayBuilder.cs index 26bf5d0537..2705a54dc4 100644 --- a/src/Components/Shared/src/ArrayBuilder.cs +++ b/src/Components/Shared/src/ArrayBuilder.cs @@ -6,7 +6,9 @@ using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; -#if COMPONENTS_SERVER +#if IGNITOR +namespace Ignitor +#elif COMPONENTS_SERVER namespace Microsoft.AspNetCore.Components.Server.Circuits #else namespace Microsoft.AspNetCore.Components.RenderTree diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj index 6b91b2d230..9f09d3f16c 100644 --- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj +++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj @@ -9,13 +9,13 @@ false - + true - + false @@ -31,6 +31,7 @@ + @@ -44,7 +45,6 @@ - diff --git a/src/Components/test/Ignitor.Test/Ignitor.Test.csproj b/src/Components/test/Ignitor.Test/Ignitor.Test.csproj deleted file mode 100644 index ad35b17b42..0000000000 --- a/src/Components/test/Ignitor.Test/Ignitor.Test.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - netcoreapp3.0 - - - - - - - diff --git a/src/Components/test/testassets/Ignitor/Ignitor.csproj b/src/Components/test/testassets/Ignitor/Ignitor.csproj deleted file mode 100644 index 6816e44df1..0000000000 --- a/src/Components/test/testassets/Ignitor/Ignitor.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - diff --git a/src/Components/test/testassets/Ignitor/Program.cs b/src/Components/test/testassets/Ignitor/Program.cs deleted file mode 100644 index 43486d490e..0000000000 --- a/src/Components/test/testassets/Ignitor/Program.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.SignalR.Client; -using Microsoft.AspNetCore.SignalR.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; - -namespace Ignitor -{ - internal class Program - { - public static async Task Main(string[] args) - { - if (args.Length == 0) - { - Console.WriteLine("a uri is required"); - return 1; - } - - Console.WriteLine("Press the ANY key to begin."); - Console.ReadLine(); - - var uri = new Uri(args[0]); - - var client = new BlazorClient(); - client.JSInterop += OnJSInterop; - Console.CancelKeyPress += (sender, e) => client.Cancel(); - - var done = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - // Click the counter button 1000 times - client.RenderBatchReceived += (batch) => - { - if (batch.Id < 1000) - { - var _ = client.ClickAsync("thecounter"); - } - else - { - done.TrySetResult(true); - } - }; - - await client.ConnectAsync(uri); - await done.Task; - - return 0; - } - - private static void OnJSInterop(CapturedJSInteropCall call) => - Console.WriteLine("JS Invoke: " + call.Identifier + " (" + call.ArgsJson + ")"); - - public Program() - { - CancellationTokenSource = new CancellationTokenSource(); - TaskCompletionSource = new TaskCompletionSource(); - - CancellationTokenSource.Token.Register(() => - { - TaskCompletionSource.TrySetCanceled(); - }); - } - - private CancellationTokenSource CancellationTokenSource { get; } - private CancellationToken CancellationToken => CancellationTokenSource.Token; - private TaskCompletionSource TaskCompletionSource { get; } - - public async Task ExecuteAsync(Uri uri) - { - var builder = new HubConnectionBuilder(); - builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); - builder.WithUrl(new Uri(uri, "_blazor/")); - builder.ConfigureLogging(l => l.AddConsole().SetMinimumLevel(LogLevel.Trace)); - var hive = new ElementHive(); - - await using var connection = builder.Build(); - await connection.StartAsync(CancellationToken); - Console.WriteLine("Connected"); - - connection.On("JS.BeginInvokeJS", OnBeginInvokeJS); - connection.On("JS.RenderBatch", OnRenderBatch); - connection.On("JS.OnError", OnError); - connection.Closed += OnClosedAsync; - - // Now everything is registered so we can start the circuit. - var success = await connection.InvokeAsync("StartCircuit", uri.AbsoluteUri, uri.GetLeftPart(UriPartial.Authority)); - - await TaskCompletionSource.Task; - - void OnBeginInvokeJS(int asyncHandle, string identifier, string argsJson) - { - Console.WriteLine("JS Invoke: " + identifier + " (" + argsJson + ")"); - } - - void OnRenderBatch(int browserRendererId, int batchId, byte[] batchData) - { - var batch = RenderBatchReader.Read(batchData); - hive.Update(batch); - - // This will click the Counter component repeatedly resulting in infinite requests. - _ = ClickAsync("thecounter", hive, connection); - } - - void OnError(Error error) - { - Console.WriteLine("ERROR: " + error.Stack); - } - - Task OnClosedAsync(Exception ex) - { - if (ex == null) - { - TaskCompletionSource.TrySetResult(null); - } - else - { - TaskCompletionSource.TrySetException(ex); - } - - return Task.CompletedTask; - } - } - - private static async Task ClickAsync(string id, ElementHive hive, HubConnection connection) - { - if (!hive.TryFindElementById(id, out var elementNode)) - { - Console.WriteLine("Could not find the counter to perform a click. Exiting."); - return; - } - - await elementNode.ClickAsync(connection); - } - - public void Cancel() - { - CancellationTokenSource.Cancel(); - CancellationTokenSource.Dispose(); - } - } -}