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
|
||||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
// 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.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.AspNetCore.Components
|
||||
|
|
@ -10,25 +12,23 @@ namespace Microsoft.AspNetCore.Components
|
|||
/// <summary>
|
||||
/// Represents a reference to a rendered element.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(ElementReferenceConverter))]
|
||||
public readonly struct ElementReference
|
||||
{
|
||||
private static long _nextIdForWebAssemblyOnly = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a unique identifier for <see cref="ElementRef" />.
|
||||
/// Gets a unique identifier for <see cref="ElementReference" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public string __internalId { get; }
|
||||
|
||||
internal string Id => __internalId;
|
||||
internal string Id { get; }
|
||||
|
||||
private ElementReference(string id)
|
||||
{
|
||||
__internalId = id;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
internal static ElementReference CreateWithUniqueId()
|
||||
|
|
@ -45,13 +45,45 @@ namespace Microsoft.AspNetCore.Components
|
|||
// fields for ElementRefCaptureId, of which only one would be in use depending
|
||||
// on the platform.
|
||||
var id = Interlocked.Increment(ref _nextIdForWebAssemblyOnly);
|
||||
return id.ToString();
|
||||
return id.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
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");
|
||||
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