V14: Migrate nucache to use System.Text.Json (#15685)
* Create system text serializer * Assign property names with system text * Use the new serializer * Impement AutoInterningStringConverter with System.Text.Json * Implement TextAutoInterningStringKeyCaseInsensitiveDictionaryConverter * Make CaseInsensitiveDictionaryConverter * Force datetimes to be read as UTC * Remove usages of Newtonsoft.Json * Remove text prefixes * Remove unused Newtonsoft converter * Remove more newtonsoft * Remove duplicate implementation * Rmove usage of missing class in tests * Ignore null values * Fix tests * Remove Newtonstoft reference from NuCache --------- Co-authored-by: Elitsa <elm@umbraco.dk>
This commit is contained in:
@@ -1,39 +1,26 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// When applied to a string or string collection field will ensure the deserialized strings are interned
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Borrowed from https://stackoverflow.com/a/34906004/694494
|
||||
/// On the same page an interesting approach of using a local intern pool https://stackoverflow.com/a/39605620/694494
|
||||
/// which re-uses .NET System.Xml.NameTable
|
||||
/// </remarks>
|
||||
public class AutoInterningStringConverter : JsonConverter
|
||||
public class AutoInterningStringConverter : JsonConverter<string>
|
||||
{
|
||||
public override bool CanWrite => false;
|
||||
// This is a hacky workaround to creating a "read only converter", since System.Text.Json doesn't support it.
|
||||
// Taken from https://github.com/dotnet/runtime/issues/46372#issuecomment-1660515178
|
||||
private readonly JsonConverter<string> _fallbackConverter = (JsonConverter<string>)JsonSerializerOptions.Default.GetConverter(typeof(string));
|
||||
|
||||
public override bool CanConvert(Type objectType) => throw
|
||||
|
||||
// CanConvert is not called when a converter is applied directly to a property.
|
||||
new NotImplementedException($"{nameof(AutoInterningStringConverter)} should not be used globally");
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
|
||||
reader.TokenType switch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
JsonTokenType.Null => null,
|
||||
JsonTokenType.String =>
|
||||
// It's safe to ignore nullability here, because according to the docs:
|
||||
// Returns null when TokenType is JsonTokenType.Null
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.text.json.utf8jsonreader.getstring?view=net-8.0#remarks
|
||||
string.Intern(reader.GetString()!),
|
||||
_ => throw new InvalidOperationException($"{nameof(AutoInterningStringConverter)} only supports strings."),
|
||||
};
|
||||
|
||||
// Check is in case the value is a non-string literal such as an integer.
|
||||
var s = reader.TokenType == JsonToken.String
|
||||
? string.Intern((string)reader.Value!)
|
||||
: string.Intern((string)JToken.Load(reader)!);
|
||||
return s;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) =>
|
||||
throw new NotImplementedException();
|
||||
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
|
||||
=> _fallbackConverter.Write(writer, value, options);
|
||||
}
|
||||
|
||||
@@ -1,54 +1,49 @@
|
||||
using System.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// When applied to a dictionary with a string key, will ensure the deserialized string keys are interned
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <remarks>
|
||||
/// borrowed from https://stackoverflow.com/a/36116462/694494
|
||||
/// </remarks>
|
||||
public class AutoInterningStringKeyCaseInsensitiveDictionaryConverter<TValue> : CaseInsensitiveDictionaryConverter<TValue>
|
||||
public class AutoInterningStringKeyCaseInsensitiveDictionaryConverter<TValue> : JsonConverter<IDictionary<string, TValue>>
|
||||
{
|
||||
public AutoInterningStringKeyCaseInsensitiveDictionaryConverter()
|
||||
{
|
||||
}
|
||||
// This is a hacky workaround to creating a "read only converter", since System.Text.Json doesn't support it.
|
||||
// Taken from https://github.com/dotnet/runtime/issues/46372#issuecomment-1660515178
|
||||
private readonly JsonConverter<IDictionary<string, TValue>> _fallbackConverter = (JsonConverter<IDictionary<string, TValue>>)JsonSerializerOptions.Default.GetConverter(typeof(IDictionary<string, TValue>));
|
||||
|
||||
public AutoInterningStringKeyCaseInsensitiveDictionaryConverter(StringComparer comparer)
|
||||
: base(comparer)
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert) => typeof(IDictionary<string, TValue>).IsAssignableFrom(typeToConvert);
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
public override Dictionary<string, TValue>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.StartObject)
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
IDictionary dictionary = Create(objectType);
|
||||
while (reader.Read())
|
||||
return null;
|
||||
}
|
||||
|
||||
var dictionary = new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase);
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
var key = string.Intern(reader.Value!.ToString()!);
|
||||
case JsonTokenType.PropertyName:
|
||||
var key = string.Intern(reader.GetString()!);
|
||||
|
||||
if (!reader.Read())
|
||||
{
|
||||
throw new Exception("Unexpected end when reading object.");
|
||||
}
|
||||
if (reader.Read() is false)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
TValue? v = serializer.Deserialize<TValue>(reader);
|
||||
dictionary[key] = v;
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
return dictionary;
|
||||
}
|
||||
TValue? value = JsonSerializer.Deserialize<TValue>(ref reader, options);
|
||||
dictionary[key] = value!;
|
||||
break;
|
||||
case JsonTokenType.Comment:
|
||||
break;
|
||||
case JsonTokenType.EndObject:
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, IDictionary<string, TValue> value, JsonSerializerOptions options) => _fallbackConverter.Write(writer, value, options);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
using System.Collections;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Marks dictionaries so they are deserialized as case-insensitive.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// [JsonConverter(typeof(CaseInsensitiveDictionaryConverter{PropertyData[]}))]
|
||||
/// public Dictionary{string, PropertyData[]} PropertyData {{ get; set; }}
|
||||
/// </example>
|
||||
public class CaseInsensitiveDictionaryConverter<T> : CustomCreationConverter<IDictionary>
|
||||
public class CaseInsensitiveDictionaryConverter<TValue> : JsonConverter<IDictionary<string, TValue>>
|
||||
{
|
||||
private readonly StringComparer _comparer;
|
||||
// This is a hacky workaround to creating a "read only converter", since System.Text.Json doesn't support it.
|
||||
// Taken from https://github.com/dotnet/runtime/issues/46372#issuecomment-1660515178
|
||||
private readonly JsonConverter<IDictionary<string, TValue>> _fallbackConverter = (JsonConverter<IDictionary<string, TValue>>)JsonSerializerOptions.Default.GetConverter(typeof(IDictionary<string, TValue>));
|
||||
|
||||
public CaseInsensitiveDictionaryConverter()
|
||||
: this(StringComparer.OrdinalIgnoreCase)
|
||||
public override IDictionary<string, TValue>? Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
IDictionary<string, TValue>? defaultDictionary = JsonSerializer.Deserialize<IDictionary<string, TValue>>(ref reader, options);
|
||||
return defaultDictionary is null
|
||||
? null
|
||||
: new Dictionary<string, TValue>(defaultDictionary, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public CaseInsensitiveDictionaryConverter(StringComparer comparer) =>
|
||||
_comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanConvert(Type objectType) => typeof(IDictionary<string, T>).IsAssignableFrom(objectType);
|
||||
|
||||
public override IDictionary Create(Type objectType) => new Dictionary<string, T>(_comparer);
|
||||
public override void Write(Utf8JsonWriter writer, IDictionary<string, TValue> value, JsonSerializerOptions options) => _fallbackConverter.Write(writer, value, options);
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
public class ForceInt32Converter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => objectType == typeof(object) || objectType == typeof(int);
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JValue? jsonValue = serializer.Deserialize<JValue>(reader);
|
||||
|
||||
return jsonValue?.Type == JTokenType.Integer
|
||||
? jsonValue.Value<int>()
|
||||
: serializer.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// In order to match the existing behaviour, and that os messagepack, we need to ensure that DateTimes are always read as UTC.
|
||||
/// This is not the case by default for System.Text.Json, see: https://github.com/dotnet/runtime/issues/1566
|
||||
/// </summary>
|
||||
public class ForceUtcDateTimeConverter : JsonConverter<DateTime>
|
||||
{
|
||||
private readonly JsonConverter<DateTime> _fallBackConverter = (JsonConverter<DateTime>)JsonSerializerOptions.Default.GetConverter(typeof(DateTime));
|
||||
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
=> reader.GetDateTime().ToUniversalTime();
|
||||
|
||||
// The existing behaviour is fine for writing, it's only reading that's an issue.
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
=> _fallBackConverter.Write(writer, value, options);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
|
||||
@@ -14,34 +14,33 @@ public class ContentCacheDataModel
|
||||
// TODO: We don't want to allocate empty arrays
|
||||
// dont serialize empty properties
|
||||
[DataMember(Order = 0)]
|
||||
[JsonProperty("pd")]
|
||||
[JsonPropertyName("pd")]
|
||||
[JsonConverter(typeof(AutoInterningStringKeyCaseInsensitiveDictionaryConverter<PropertyData[]>))]
|
||||
[MessagePackFormatter(typeof(MessagePackAutoInterningStringKeyCaseInsensitiveDictionaryFormatter<PropertyData[]>))]
|
||||
public Dictionary<string, PropertyData[]>? PropertyData { get; set; }
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
[JsonProperty("cd")]
|
||||
[JsonPropertyName("cd")]
|
||||
[JsonConverter(typeof(AutoInterningStringKeyCaseInsensitiveDictionaryConverter<CultureVariation>))]
|
||||
[MessagePackFormatter(
|
||||
typeof(MessagePackAutoInterningStringKeyCaseInsensitiveDictionaryFormatter<CultureVariation>))]
|
||||
[MessagePackFormatter(typeof(MessagePackAutoInterningStringKeyCaseInsensitiveDictionaryFormatter<CultureVariation>))]
|
||||
public Dictionary<string, CultureVariation>? CultureData { get; set; }
|
||||
|
||||
[DataMember(Order = 2)]
|
||||
[JsonProperty("us")]
|
||||
[JsonPropertyName("us")]
|
||||
public string? UrlSegment { get; set; }
|
||||
|
||||
// Legacy properties used to deserialize existing nucache db entries
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("properties")]
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonConverter(typeof(CaseInsensitiveDictionaryConverter<PropertyData[]>))]
|
||||
private Dictionary<string, PropertyData[]> LegacyPropertyData { set => PropertyData = value; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("cultureData")]
|
||||
[JsonPropertyName("cultureData")]
|
||||
[JsonConverter(typeof(CaseInsensitiveDictionaryConverter<CultureVariation>))]
|
||||
private Dictionary<string, CultureVariation> LegacyCultureData { set => CultureData = value; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("urlSegment")]
|
||||
[JsonPropertyName("urlSegment")]
|
||||
private string LegacyUrlSegment { set => UrlSegment = value; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
|
||||
|
||||
@@ -10,35 +11,37 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
|
||||
public class CultureVariation
|
||||
{
|
||||
[DataMember(Order = 0)]
|
||||
[JsonProperty("nm")]
|
||||
[JsonPropertyName("nm")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
[JsonProperty("us")]
|
||||
[JsonPropertyName("us")]
|
||||
public string? UrlSegment { get; set; }
|
||||
|
||||
[DataMember(Order = 2)]
|
||||
[JsonProperty("dt")]
|
||||
[JsonPropertyName("dt")]
|
||||
[JsonConverter(typeof(ForceUtcDateTimeConverter))]
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
[DataMember(Order = 3)]
|
||||
[JsonProperty("isd")]
|
||||
[JsonPropertyName("isd")]
|
||||
public bool IsDraft { get; set; }
|
||||
|
||||
// Legacy properties used to deserialize existing nucache db entries
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("name")]
|
||||
[JsonPropertyName("nam")]
|
||||
private string LegacyName { set => Name = value; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("urlSegment")]
|
||||
[JsonPropertyName("urlSegment")]
|
||||
private string LegacyUrlSegment { set => UrlSegment = value; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("date")]
|
||||
[JsonPropertyName("date")]
|
||||
[JsonConverter(typeof(ForceUtcDateTimeConverter))]
|
||||
private DateTime LegacyDate { set => Date = value; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("isDraft")]
|
||||
[JsonPropertyName("isDraft")]
|
||||
private bool LegacyIsDraft { set => IsDraft = value; }
|
||||
}
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
using System.Buffers;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
|
||||
|
||||
public class JsonContentNestedDataSerializer : IContentCacheDataSerializer
|
||||
{
|
||||
// by default JsonConvert will deserialize our numeric values as Int64
|
||||
// which is bad, because they were Int32 in the database - take care
|
||||
private readonly JsonSerializerSettings _jsonSerializerSettings = new()
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
Converters = new List<JsonConverter> { new ForceInt32Converter() },
|
||||
|
||||
// Explicitly specify date handling so that it's consistent and follows the same date handling as MessagePack
|
||||
DateParseHandling = DateParseHandling.DateTime,
|
||||
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
|
||||
DateFormatString = "o",
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
|
||||
private readonly JsonNameTable _propertyNameTable = new DefaultJsonNameTable();
|
||||
|
||||
public ContentCacheDataModel? Deserialize(IReadOnlyContentBase content, string? stringData, byte[]? byteData, bool published)
|
||||
/// <inheritdoc />
|
||||
public ContentCacheDataModel? Deserialize(
|
||||
IReadOnlyContentBase content,
|
||||
string? stringData,
|
||||
byte[]? byteData,
|
||||
bool published)
|
||||
{
|
||||
if (stringData == null && byteData != null)
|
||||
{
|
||||
@@ -30,62 +24,16 @@ public class JsonContentNestedDataSerializer : IContentCacheDataSerializer
|
||||
$"{typeof(JsonContentNestedDataSerializer)} does not support byte[] serialization");
|
||||
}
|
||||
|
||||
var serializer = JsonSerializer.Create(_jsonSerializerSettings);
|
||||
using (var reader = new JsonTextReader(new StringReader(stringData!)))
|
||||
{
|
||||
// reader will get buffer from array pool
|
||||
reader.ArrayPool = JsonArrayPool.Instance;
|
||||
reader.PropertyNameTable = _propertyNameTable;
|
||||
return serializer.Deserialize<ContentCacheDataModel>(reader);
|
||||
}
|
||||
return JsonSerializer.Deserialize<ContentCacheDataModel>(stringData!, _jsonSerializerOptions);
|
||||
}
|
||||
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
/// <inheritdoc />
|
||||
public ContentCacheDataSerializationResult Serialize(
|
||||
IReadOnlyContentBase content,
|
||||
ContentCacheDataModel model,
|
||||
bool published)
|
||||
{
|
||||
// note that numeric values (which are Int32) are serialized without their
|
||||
// type (eg "value":1234) and JsonConvert by default deserializes them as Int64
|
||||
var json = JsonConvert.SerializeObject(model);
|
||||
var json = JsonSerializer.Serialize(model, _jsonSerializerOptions);
|
||||
return new ContentCacheDataSerializationResult(json, null);
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonArrayPool : IArrayPool<char>
|
||||
{
|
||||
public static readonly JsonArrayPool Instance = new();
|
||||
|
||||
public char[] Rent(int minimumLength) =>
|
||||
|
||||
// get char array from System.Buffers shared pool
|
||||
ArrayPool<char>.Shared.Rent(minimumLength);
|
||||
|
||||
public void Return(char[]? array)
|
||||
{
|
||||
// return char array to System.Buffers shared pool
|
||||
if (array is not null)
|
||||
{
|
||||
ArrayPool<char>.Shared.Return(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AutomaticJsonNameTable : DefaultJsonNameTable
|
||||
{
|
||||
private readonly int maxToAutoAdd;
|
||||
private int nAutoAdded;
|
||||
|
||||
public AutomaticJsonNameTable(int maxToAdd) => maxToAutoAdd = maxToAdd;
|
||||
|
||||
public override string? Get(char[] key, int start, int length)
|
||||
{
|
||||
var s = base.Get(key, start, length);
|
||||
|
||||
if (s == null && nAutoAdded < maxToAutoAdd)
|
||||
{
|
||||
s = new string(key, start, length);
|
||||
Add(s);
|
||||
nAutoAdded++;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
|
||||
@@ -14,7 +14,7 @@ public class PropertyData
|
||||
[DataMember(Order = 0)]
|
||||
[JsonConverter(typeof(AutoInterningStringConverter))]
|
||||
[DefaultValue("")]
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, PropertyName = "c")]
|
||||
[JsonPropertyName("c")]
|
||||
public string? Culture
|
||||
{
|
||||
get => _culture;
|
||||
@@ -26,7 +26,7 @@ public class PropertyData
|
||||
[DataMember(Order = 1)]
|
||||
[JsonConverter(typeof(AutoInterningStringConverter))]
|
||||
[DefaultValue("")]
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, PropertyName = "s")]
|
||||
[JsonPropertyName("s")]
|
||||
public string? Segment
|
||||
{
|
||||
get => _segment;
|
||||
@@ -36,26 +36,25 @@ public class PropertyData
|
||||
}
|
||||
|
||||
[DataMember(Order = 2)]
|
||||
[JsonProperty("v")]
|
||||
[JsonPropertyName("v")]
|
||||
public object? Value { get; set; }
|
||||
|
||||
// Legacy properties used to deserialize existing nucache db entries
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("culture")]
|
||||
private string LegacyCulture
|
||||
{
|
||||
set => Culture = value;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("seg")]
|
||||
[JsonPropertyName("seg")]
|
||||
private string LegacySegment
|
||||
{
|
||||
set => Segment = value;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
[JsonProperty("val")]
|
||||
[JsonPropertyName("val")]
|
||||
private object LegacyValue
|
||||
{
|
||||
set => Value = value;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<PackageReference Include="Umbraco.CSharpTest.Net.Collections" />
|
||||
<PackageReference Include="MessagePack" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" />
|
||||
<PackageReference Include="Newtonsoft.Json"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -568,7 +568,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'en','s':'','v':'v1en'},{'c':'fr','s':'','v':'v1fr'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch content type to Nothing
|
||||
contentType.Variations = ContentVariation.Nothing;
|
||||
@@ -586,7 +586,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'v':'v1en'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'','s':'','v':'v1en'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch content back to Culture
|
||||
contentType.Variations = ContentVariation.Culture;
|
||||
@@ -604,7 +604,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'v':'v1en'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'','s':'','v':'v1en'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch property back to Culture
|
||||
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture;
|
||||
@@ -621,7 +621,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'en','s':'','v':'v1en'},{'c':'fr','s':'','v':'v1fr'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -664,7 +664,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'v':'v1'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'','s':'','v':'v1'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch content type to Culture
|
||||
contentType.Variations = ContentVariation.Culture;
|
||||
@@ -681,7 +681,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'v':'v1'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'','s':'','v':'v1'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch property to Culture
|
||||
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture;
|
||||
@@ -697,7 +697,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'c':'en','v':'v1'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'en','s':'','v':'v1'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch content back to Nothing
|
||||
contentType.Variations = ContentVariation.Nothing;
|
||||
@@ -715,7 +715,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'v':'v1'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'','s':'','v':'v1'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -753,7 +753,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'en','s':'','v':'v1en'},{'c':'fr','s':'','v':'v1fr'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch property type to Nothing
|
||||
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Nothing;
|
||||
@@ -771,7 +771,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'v':'v1en'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'','s':'','v':'v1en'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch property back to Culture
|
||||
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture;
|
||||
@@ -788,7 +788,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'en','s':'','v':'v1en'},{'c':'fr','s':'','v':'v1fr'}],'value2':[{'c':'','s':'','v':'v2'}]},'cd':");
|
||||
|
||||
// switch other property to Culture
|
||||
contentType.PropertyTypes.First(x => x.Alias == "value2").Variations = ContentVariation.Culture;
|
||||
@@ -807,7 +807,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'c':'en','v':'v2'}]},'cd':");
|
||||
"{'pd':{'value1':[{'c':'en','s':'','v':'v1en'},{'c':'fr','s':'','v':'v1fr'}],'value2':[{'c':'en','s':'','v':'v2'}]},'cd':");
|
||||
}
|
||||
|
||||
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
|
||||
@@ -1070,7 +1070,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
composed.Variations = ContentVariation.Nothing;
|
||||
ContentTypeService.Save(composed);
|
||||
@@ -1079,7 +1079,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'v':'v21en'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11en'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'','s':'','v':'v21en'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
composed.Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composed);
|
||||
@@ -1088,7 +1088,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'v':'v21en'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'','s':'','v':'v21en'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
composed.PropertyTypes.First(x => x.Alias == "value21").Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composed);
|
||||
@@ -1097,7 +1097,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
composing.Variations = ContentVariation.Nothing;
|
||||
ContentTypeService.Save(composing);
|
||||
@@ -1106,7 +1106,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11en'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
composing.Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composing);
|
||||
@@ -1115,7 +1115,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11en'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
composing.PropertyTypes.First(x => x.Alias == "value11").Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composing);
|
||||
@@ -1124,7 +1124,7 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document.Id));
|
||||
AssertJsonStartsWith(
|
||||
document.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -1189,12 +1189,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
|
||||
composed1.Variations = ContentVariation.Nothing;
|
||||
ContentTypeService.Save(composed1);
|
||||
@@ -1203,12 +1203,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'v':'v21en'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11en'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'','s':'','v':'v21en'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
|
||||
composed1.Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composed1);
|
||||
@@ -1217,12 +1217,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'v':'v21en'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'','s':'','v':'v21en'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
|
||||
composed1.PropertyTypes.First(x => x.Alias == "value21").Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composed1);
|
||||
@@ -1231,12 +1231,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
|
||||
composing.Variations = ContentVariation.Nothing;
|
||||
ContentTypeService.Save(composing);
|
||||
@@ -1245,12 +1245,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11en'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
|
||||
composing.Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composing);
|
||||
@@ -1259,12 +1259,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11en'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
|
||||
composing.PropertyTypes.First(x => x.Alias == "value11").Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(composing);
|
||||
@@ -1273,12 +1273,12 @@ public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest
|
||||
Console.WriteLine(GetJson(document1.Id));
|
||||
AssertJsonStartsWith(
|
||||
document1.Id,
|
||||
"{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'en','s':'','v':'v11en'},{'c':'fr','s':'','v':'v11fr'}],'value12':[{'c':'','s':'','v':'v12'}],'value21':[{'c':'en','s':'','v':'v21en'},{'c':'fr','s':'','v':'v21fr'}],'value22':[{'c':'','s':'','v':'v22'}]},'cd':");
|
||||
|
||||
Console.WriteLine(GetJson(document2.Id));
|
||||
AssertJsonStartsWith(
|
||||
document2.Id,
|
||||
"{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':");
|
||||
"{'pd':{'value11':[{'c':'','s':'','v':'v11'}],'value12':[{'c':'','s':'','v':'v12'}],'value31':[{'c':'','s':'','v':'v31'}],'value32':[{'c':'','s':'','v':'v32'}]},'cd':");
|
||||
}
|
||||
|
||||
private async Task CreateFrenchAndEnglishLangs()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
@@ -18,8 +17,8 @@ public class AutoInterningStringConverterTests
|
||||
// ensure the raw value is not interned
|
||||
Assert.IsNull(string.IsInterned(obj.Name));
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(obj);
|
||||
obj = JsonConvert.DeserializeObject<Test>(serialized);
|
||||
var serialized = JsonSerializer.Serialize(obj);
|
||||
obj = JsonSerializer.Deserialize<Test>(serialized);
|
||||
|
||||
Assert.IsNotNull(string.IsInterned(obj.Name));
|
||||
}
|
||||
@@ -37,8 +36,8 @@ public class AutoInterningStringConverterTests
|
||||
Assert.IsNull(string.IsInterned(obj.Values.Keys.First()));
|
||||
Assert.IsNull(string.IsInterned(obj.Values.Keys.Last()));
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(obj);
|
||||
obj = JsonConvert.DeserializeObject<Test>(serialized);
|
||||
var serialized = JsonSerializer.Serialize(obj);
|
||||
obj = JsonSerializer.Deserialize<Test>(serialized);
|
||||
|
||||
Assert.IsNotNull(string.IsInterned(obj.Values.Keys.First()));
|
||||
Assert.IsNotNull(string.IsInterned(obj.Values.Keys.Last()));
|
||||
|
||||
Reference in New Issue
Block a user