/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Shared/Components/ComponentMarker.cs
159 строк
6 KB
Copilot
[Blazor] Fix Blazor root component state persistence across render modes (#62370)
18 июн 2025, 17:16
Не верифицирован
18 июн 2025, 17:16
ef0da55
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable enable using System.Diagnostics; namespace Microsoft.AspNetCore.Components; [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")] internal struct ComponentMarker { public const string ServerMarkerType = "server"; public const string WebAssemblyMarkerType = "webassembly"; public const string AutoMarkerType = "auto"; #region Common marker data // The marker type. Can be "server", "webassembly", or "auto". public string? Type { get; set; } // A string to allow the clients to differentiate between prerendered // and non prerendered components and to uniquely identify start and end // markers in prererendered components. // The value will be null if this marker represents a non-prerendered component. public string? PrerenderId { get; set; } // A key that the browser can use when comparing markers to determine // whether they represent different component instances. public ComponentMarkerKey? Key { get; set; } #endregion #region Server marker data // The order in which this component was rendered/produced // on the server. It matches the number on the descriptor // and is used to prevent an infinite amount of components // from being rendered from the client-side. public int? Sequence { get; set; } // A data-protected payload that allows the server to validate the legitimacy // of the invocation. // The value will be null for end markers. public string? Descriptor { get; set; } #endregion #region WebAssembly marker data // The assembly containing the component type. public string? Assembly { get; set; } // The full name of the component type. public string? TypeName { get; set; } // Serialized definitions of the component's parameters. public string? ParameterDefinitions { get; set; } // Serialized values of the component's parameters. public string? ParameterValues { get; set; } #endregion public static ComponentMarker Create(string type, bool prerendered, ComponentMarkerKey? key) { return new() { Type = type, PrerenderId = prerendered ? GeneratePrerenderId() : null, Key = key, }; } public void WriteServerData(int sequence, string descriptor) { Sequence = sequence; Descriptor = descriptor; } public void WriteWebAssemblyData(string assembly, string typeName, string parameterDefinitions, string parameterValues) { Assembly = assembly; TypeName = typeName; ParameterDefinitions = parameterDefinitions; ParameterValues = parameterValues; } public ComponentEndMarker? ToEndMarker() => PrerenderId is null ? default : new() { PrerenderId = PrerenderId }; private static string GeneratePrerenderId() => Guid.NewGuid().ToString("N"); private string GetDebuggerDisplay() { switch (Type) { case ServerMarkerType: return $"Server Component: {TypeName}, Sequence: {Sequence}, Key: {Key?.FormattedComponentKey} Descriptor: {Descriptor?.Substring(5)}..."; case WebAssemblyMarkerType: return $"WebAssembly Component: {TypeName}, Assembly: {Assembly}, Key: {Key?.FormattedComponentKey}"; case AutoMarkerType: return $"Auto Component: {TypeName}, Assembly: {Assembly}, Key: {Key?.FormattedComponentKey}, Descriptor: {Descriptor?.Substring(5)}..."; default: return $"Unknown Component Type: {Type}, Key: {Key?.FormattedComponentKey}"; } } } internal struct ComponentEndMarker { public string? PrerenderId { get; set; } } [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")] internal struct ComponentMarkerKey : IEquatable<ComponentMarkerKey> { public ComponentMarkerKey(string locationHash, string? formattedComponentKey) => (LocationHash, FormattedComponentKey) = (locationHash, formattedComponentKey); // A hash that distinguishes this component from other components in the render tree. // The output should be deterministic between endpoint invocations so that the client // can match up component instances between renders. // The current implementation uses the hashed component type name and its render tree // sequence number. public string LocationHash { get; set; } // The formatted component key (@key), if any. This helps the developer further distinguish // between component instances if they have the same type and sequence number (e.g., components // rendered in a list). // In addition, specifying a @key lets interactive components receive parameter updates dynamically. public string? FormattedComponentKey { get; set; } public static bool operator ==(ComponentMarkerKey left, ComponentMarkerKey right) => left.Equals(right); public static bool operator !=(ComponentMarkerKey left, ComponentMarkerKey right) => !(left == right); public readonly bool Equals(ComponentMarkerKey other) => string.Equals(LocationHash, other.LocationHash, StringComparison.Ordinal) && string.Equals(FormattedComponentKey, other.FormattedComponentKey, StringComparison.Ordinal); public override readonly bool Equals(object? obj) => obj is ComponentMarkerKey other && Equals(other); public override readonly int GetHashCode() => HashCode.Combine(LocationHash, FormattedComponentKey); private readonly string GetDebuggerDisplay() => $"LocationHash: {LocationHash}, Key: {FormattedComponentKey ?? "null"}"; internal readonly string? Serialized() { return this == default ? null : $"{LocationHash}:{FormattedComponentKey}"; } }