Use a JsonConverter with ElementRef
This commit is contained in:
parent
4f638f8e11
commit
6f05f83a97
|
|
@ -154,8 +154,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public readonly partial struct ElementReference
|
public readonly partial struct ElementReference
|
||||||
{
|
{
|
||||||
private readonly object _dummy;
|
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)]
|
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
|
||||||
public readonly partial struct EventCallback
|
public readonly partial struct EventCallback
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.Globalization;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Components
|
namespace Microsoft.AspNetCore.Components
|
||||||
|
|
@ -10,25 +12,23 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a reference to a rendered element.
|
/// Represents a reference to a rendered element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(ElementReferenceConverter))]
|
||||||
public readonly struct ElementReference
|
public readonly struct ElementReference
|
||||||
{
|
{
|
||||||
private static long _nextIdForWebAssemblyOnly = 1;
|
private static long _nextIdForWebAssemblyOnly = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a unique identifier for <see cref="ElementRef" />.
|
/// Gets a unique identifier for <see cref="ElementReference" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The Id is unique at least within the scope of a given user/circuit.
|
/// 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.
|
/// This property is public to support Json serialization and should not be used by user code.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
internal string Id { get; }
|
||||||
public string __internalId { get; }
|
|
||||||
|
|
||||||
internal string Id => __internalId;
|
|
||||||
|
|
||||||
private ElementReference(string id)
|
private ElementReference(string id)
|
||||||
{
|
{
|
||||||
__internalId = id;
|
Id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ElementReference CreateWithUniqueId()
|
internal static ElementReference CreateWithUniqueId()
|
||||||
|
|
@ -45,13 +45,45 @@ namespace Microsoft.AspNetCore.Components
|
||||||
// fields for ElementRefCaptureId, of which only one would be in use depending
|
// fields for ElementRefCaptureId, of which only one would be in use depending
|
||||||
// on the platform.
|
// on the platform.
|
||||||
var id = Interlocked.Increment(ref _nextIdForWebAssemblyOnly);
|
var id = Interlocked.Increment(ref _nextIdForWebAssemblyOnly);
|
||||||
return id.ToString();
|
return id.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// For remote rendering, it's important not to disclose any cross-user state,
|
// For remote rendering, it's important not to disclose any cross-user state,
|
||||||
// such as the number of IDs that have been assigned.
|
// such as the number of IDs that have been assigned.
|
||||||
return Guid.NewGuid().ToString("D");
|
return Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class ElementReferenceConverter : JsonConverter<ElementReference>
|
||||||
|
{
|
||||||
|
private static readonly JsonEncodedText IdProperty = JsonEncodedText.Encode("__internalId");
|
||||||
|
|
||||||
|
public override ElementReference Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
string id = null;
|
||||||
|
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
|
||||||
|
{
|
||||||
|
if (reader.ValueTextEquals(IdProperty.EncodedUtf8Bytes))
|
||||||
|
{
|
||||||
|
reader.Read();
|
||||||
|
id = reader.GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id is null)
|
||||||
|
{
|
||||||
|
throw new JsonException("__internalId is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ElementReference(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, ElementReference value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WriteString(IdProperty, value.Id);
|
||||||
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// 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.Text.Json;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Components
|
||||||
|
{
|
||||||
|
public class ElementReferenceTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Serializing_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var elementReference = ElementReference.CreateWithUniqueId();
|
||||||
|
var expected = $"{{\"__internalId\":\"{elementReference.Id}\"}}";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var json = JsonSerializer.Serialize(elementReference, JsonSerializerOptionsProvider.Options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deserializing_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = ElementReference.CreateWithUniqueId().Id;
|
||||||
|
var json = $"{{\"__internalId\":\"{id}\"}}";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var elementReference = JsonSerializer.Deserialize<ElementReference>(json, JsonSerializerOptionsProvider.Options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(id, elementReference.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deserializing_WithFormatting_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var id = ElementReference.CreateWithUniqueId().Id;
|
||||||
|
var json =
|
||||||
|
@$"{{
|
||||||
|
""__internalId"": ""{id}""
|
||||||
|
}}";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var elementReference = JsonSerializer.Deserialize<ElementReference>(json, JsonSerializerOptionsProvider.Options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(id, elementReference.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deserializing_Throws_IfIdIsNotSpecified()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var json = "{\"id\":\"some-value\"}";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<ElementReference>(json, JsonSerializerOptionsProvider.Options));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("__internalId is required.", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue