Use a JsonConverter with ElementRef

This commit is contained in:
Pranav K 2019-07-16 09:36:15 -07:00
parent 4f638f8e11
commit 6f05f83a97
No known key found for this signature in database
GPG Key ID: 1963DA6D96C3057A
3 changed files with 111 additions and 11 deletions

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}