diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs index 6097208bee..c887990cdb 100644 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs +++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs @@ -151,6 +151,13 @@ namespace Microsoft.AspNetCore.Components public string __internalId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } } [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct ElementReference + { + private readonly object _dummy; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public string __internalId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public readonly partial struct EventCallback { private readonly object _dummy; diff --git a/src/Components/Components/src/ElementReference.cs b/src/Components/Components/src/ElementReference.cs new file mode 100644 index 0000000000..be85bffab0 --- /dev/null +++ b/src/Components/Components/src/ElementReference.cs @@ -0,0 +1,58 @@ +// 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.ComponentModel; +using System.Threading; + +namespace Microsoft.AspNetCore.Components +{ + /// + /// Represents a reference to a rendered element. + /// + public readonly struct ElementReference + { + private static long _nextIdForWebAssemblyOnly = 1; + + /// + /// 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. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public string __internalId { get; } + + internal string Id => __internalId; + + private ElementReference(string id) + { + __internalId = id; + } + + internal static ElementReference CreateWithUniqueId() + => new ElementReference(CreateUniqueId()); + + private static string CreateUniqueId() + { + if (PlatformInfo.IsWebAssembly) + { + // On WebAssembly there's only one user, so it's fine to expose the number + // of IDs that have been assigned, and this is cheaper than creating a GUID. + // It's unfortunate that this still involves a heap allocation. If that becomes + // a problem we could extend RenderTreeFrame to have both "string" and "long" + // fields for ElementRefCaptureId, of which only one would be in use depending + // on the platform. + var id = Interlocked.Increment(ref _nextIdForWebAssemblyOnly); + return id.ToString(); + } + else + { + // For remote rendering, it's important not to disclose any cross-user state, + // such as the number of IDs that have been assigned. + return Guid.NewGuid().ToString("D"); + } + } + } +}