Allows serializer to be configured
This commit is contained in:
@@ -19,8 +19,8 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
VersionDate = PrimitiveSerializer.DateTime.ReadFrom(stream),
|
||||
WriterId = PrimitiveSerializer.Int32.ReadFrom(stream),
|
||||
TemplateId = PrimitiveSerializer.Int32.ReadFrom(stream),
|
||||
Properties = PropertiesSerializer.ReadFrom(stream),
|
||||
CultureInfos = CultureVariationsSerializer.ReadFrom(stream)
|
||||
Properties = PropertiesSerializer.ReadFrom(stream), // TODO: We don't want to allocate empty arrays
|
||||
CultureInfos = CultureVariationsSerializer.ReadFrom(stream) // TODO: We don't want to allocate empty arrays
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
@@ -7,29 +9,37 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
/// <summary>
|
||||
/// The content item 1:M data that is serialized to JSON
|
||||
/// </summary>
|
||||
[DataContract] // NOTE: Use DataContract annotations here to control how MessagePack serializes/deserializes the data to use INT keys
|
||||
public class ContentNestedData
|
||||
{
|
||||
// TODO: We don't want to allocate empty arrays
|
||||
//dont serialize empty properties
|
||||
[DataMember(Order = 0)]
|
||||
[JsonProperty("pd")]
|
||||
[JsonConverter(typeof(AutoInterningStringKeyCaseInsensitiveDictionaryConverter<PropertyData[]>))]
|
||||
public Dictionary<string, PropertyData[]> PropertyData { get; set; }
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
[JsonProperty("cd")]
|
||||
[JsonConverter(typeof(AutoInterningStringKeyCaseInsensitiveDictionaryConverter<CultureVariation>))]
|
||||
public Dictionary<string, CultureVariation> CultureData { get; set; }
|
||||
|
||||
[DataMember(Order = 2)]
|
||||
[JsonProperty("us")]
|
||||
public string UrlSegment { get; set; }
|
||||
|
||||
//Legacy properties used to deserialize existing nucache db entries
|
||||
[DataMember(Order = 3)]
|
||||
[JsonProperty("properties")]
|
||||
[JsonConverter(typeof(CaseInsensitiveDictionaryConverter<PropertyData[]>))]
|
||||
private Dictionary<string, PropertyData[]> LegacyPropertyData { set { PropertyData = value; } }
|
||||
|
||||
[DataMember(Order = 4)]
|
||||
[JsonProperty("cultureData")]
|
||||
[JsonConverter(typeof(CaseInsensitiveDictionaryConverter<CultureVariation>))]
|
||||
private Dictionary<string, CultureVariation> LegacyCultureData { set { CultureData = value; } }
|
||||
|
||||
[DataMember(Order = 5)]
|
||||
[JsonProperty("urlSegment")]
|
||||
private string LegacyUrlSegment { set { UrlSegment = value; } }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
@@ -6,30 +7,39 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
/// <summary>
|
||||
/// Represents the culture variation information on a content item
|
||||
/// </summary>
|
||||
[DataContract] // NOTE: Use DataContract annotations here to control how MessagePack serializes/deserializes the data to use INT keys
|
||||
public class CultureVariation
|
||||
{
|
||||
[DataMember(Order = 0)]
|
||||
[JsonProperty("nm")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
[JsonProperty("us")]
|
||||
public string UrlSegment { get; set; }
|
||||
|
||||
[DataMember(Order = 2)]
|
||||
[JsonProperty("dt")]
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
[DataMember(Order = 3)]
|
||||
[JsonProperty("isd")]
|
||||
public bool IsDraft { get; set; }
|
||||
|
||||
//Legacy properties used to deserialize existing nucache db entries
|
||||
[DataMember(Order = 4)]
|
||||
[JsonProperty("name")]
|
||||
private string LegacyName { set { Name = value; } }
|
||||
|
||||
[DataMember(Order = 5)]
|
||||
[JsonProperty("urlSegment")]
|
||||
private string LegacyUrlSegment { set { UrlSegment = value; } }
|
||||
|
||||
[DataMember(Order = 6)]
|
||||
[JsonProperty("date")]
|
||||
private DateTime LegacyDate { set { Date = value; } }
|
||||
|
||||
[DataMember(Order = 7)]
|
||||
[JsonProperty("isDraft")]
|
||||
private bool LegacyIsDraft { set { IsDraft = value; } }
|
||||
}
|
||||
|
||||
@@ -20,12 +20,10 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
// provides efficient database access for NuCache
|
||||
internal class DatabaseDataSource : IDataSource
|
||||
{
|
||||
|
||||
|
||||
private const int PageSize = 500;
|
||||
private readonly IContentNestedDataSerializer _contentNestedDataSerializer;
|
||||
|
||||
internal DatabaseDataSource(IContentNestedDataSerializer contentNestedDataSerializer)
|
||||
public DatabaseDataSource(IContentNestedDataSerializer contentNestedDataSerializer)
|
||||
{
|
||||
_contentNestedDataSerializer = contentNestedDataSerializer;
|
||||
}
|
||||
@@ -231,7 +229,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.EditVersionDate,
|
||||
WriterId = dto.EditWriterId,
|
||||
Properties = nested.PropertyData,
|
||||
Properties = nested.PropertyData, // TODO: We don't want to allocate empty arrays
|
||||
CultureInfos = nested.CultureData,
|
||||
UrlSegment = nested.UrlSegment
|
||||
};
|
||||
@@ -259,7 +257,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.PubVersionDate,
|
||||
WriterId = dto.PubWriterId,
|
||||
Properties = nested.PropertyData,
|
||||
Properties = nested.PropertyData, // TODO: We don't want to allocate empty arrays
|
||||
CultureInfos = nested.CultureData
|
||||
};
|
||||
}
|
||||
@@ -294,7 +292,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.EditVersionDate,
|
||||
WriterId = dto.CreatorId, // what-else?
|
||||
Properties = nested.PropertyData,
|
||||
Properties = nested.PropertyData, // TODO: We don't want to allocate empty arrays
|
||||
CultureInfos = nested.CultureData
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using MessagePack;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Resolvers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
{
|
||||
@@ -9,7 +12,24 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
|
||||
public MsgPackContentNestedDataSerializer()
|
||||
{
|
||||
_options = MessagePack.Resolvers.ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.Lz4BlockArray);
|
||||
var defaultOptions = ContractlessStandardResolver.Options;
|
||||
|
||||
var resolver = CompositeResolver.Create(
|
||||
|
||||
// TODO: We want to be able to intern the strings for aliases when deserializing like we do for Newtonsoft but I'm unsure exactly how
|
||||
// to do that but it would seem to be with a custom message pack resolver but I haven't quite figured out based on the docs how
|
||||
// to do that since that is part of the int key -> string mapping operation, might have to see the source code to figure that one out.
|
||||
|
||||
// resolver custom types first
|
||||
// new ContentNestedDataResolver(),
|
||||
|
||||
// finally use standard resolver
|
||||
defaultOptions.Resolver
|
||||
);
|
||||
|
||||
_options = defaultOptions
|
||||
.WithResolver(resolver)
|
||||
.WithCompression(MessagePackCompression.Lz4BlockArray);
|
||||
}
|
||||
|
||||
public string ToJson(string serialized)
|
||||
@@ -21,9 +41,6 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
|
||||
// TODO: Instead of returning base64 it would be more ideal to avoid that translation entirely and just store/retrieve raw bytes
|
||||
|
||||
// TODO: We need to write tests to serialize/deserialize between either of these serializers to ensure we end up with the same object
|
||||
// i think this one is a bit quirky so far :)
|
||||
|
||||
public ContentNestedData Deserialize(string data)
|
||||
{
|
||||
var bin = Convert.FromBase64String(data);
|
||||
@@ -32,11 +49,89 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
}
|
||||
|
||||
public string Serialize(ContentNestedData nestedData)
|
||||
{
|
||||
var bin = MessagePackSerializer.Serialize(
|
||||
nestedData,
|
||||
_options);
|
||||
{
|
||||
var bin = MessagePackSerializer.Serialize(nestedData, _options);
|
||||
return Convert.ToBase64String(bin);
|
||||
}
|
||||
|
||||
//private class ContentNestedDataResolver : IFormatterResolver
|
||||
//{
|
||||
// // GetFormatter<T>'s get cost should be minimized so use type cache.
|
||||
// public IMessagePackFormatter<T> GetFormatter<T>() => FormatterCache<T>.Formatter;
|
||||
|
||||
// private static class FormatterCache<T>
|
||||
// {
|
||||
// public static readonly IMessagePackFormatter<T> Formatter;
|
||||
|
||||
// // generic's static constructor should be minimized for reduce type generation size!
|
||||
// // use outer helper method.
|
||||
// static FormatterCache()
|
||||
// {
|
||||
// Formatter = (IMessagePackFormatter<T>)SampleCustomResolverGetFormatterHelper.GetFormatter(typeof(T));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//internal static class SampleCustomResolverGetFormatterHelper
|
||||
//{
|
||||
// // If type is concrete type, use type-formatter map
|
||||
// static readonly Dictionary<Type, object> _formatterMap = new Dictionary<Type, object>()
|
||||
// {
|
||||
// {typeof(ContentNestedData), new ContentNestedDataFormatter()}
|
||||
// // add more your own custom serializers.
|
||||
// };
|
||||
|
||||
// internal static object GetFormatter(Type t)
|
||||
// {
|
||||
// object formatter;
|
||||
// if (_formatterMap.TryGetValue(t, out formatter))
|
||||
// {
|
||||
// return formatter;
|
||||
// }
|
||||
|
||||
// // If target type is generics, use MakeGenericType.
|
||||
// if (t.IsGenericParameter && t.GetGenericTypeDefinition() == typeof(ValueTuple<,>))
|
||||
// {
|
||||
// return Activator.CreateInstance(typeof(ValueTupleFormatter<,>).MakeGenericType(t.GenericTypeArguments));
|
||||
// }
|
||||
|
||||
// // If type can not get, must return null for fallback mechanism.
|
||||
// return null;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public class ContentNestedDataFormatter : IMessagePackFormatter<ContentNestedData>
|
||||
//{
|
||||
// public void Serialize(ref MessagePackWriter writer, ContentNestedData value, MessagePackSerializerOptions options)
|
||||
// {
|
||||
// if (value == null)
|
||||
// {
|
||||
// writer.WriteNil();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// writer.WriteArrayHeader(3);
|
||||
// writer.WriteString(value.UrlSegment);
|
||||
// writer.WriteString(value.FullName);
|
||||
// writer.WriteString(value.Age);
|
||||
|
||||
// writer.WriteString(value.FullName);
|
||||
// }
|
||||
|
||||
// public ContentNestedData Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
// {
|
||||
// if (reader.TryReadNil())
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// options.Security.DepthStep(ref reader);
|
||||
|
||||
// var path = reader.ReadString();
|
||||
|
||||
// reader.Depth--;
|
||||
// return new FileInfo(path);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
{
|
||||
|
||||
[DataContract] // NOTE: Use DataContract annotations here to control how MessagePack serializes/deserializes the data to use INT keys
|
||||
public class PropertyData
|
||||
{
|
||||
private string _culture;
|
||||
private string _segment;
|
||||
|
||||
[DataMember(Order = 0)]
|
||||
[JsonConverter(typeof(AutoInterningStringConverter))]
|
||||
[DefaultValue("")]
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, PropertyName = "c")]
|
||||
@@ -19,6 +23,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
set => _culture = value ?? throw new ArgumentNullException(nameof(value)); // TODO: or fallback to string.Empty? CANNOT be null
|
||||
}
|
||||
|
||||
[DataMember(Order = 1)]
|
||||
[JsonConverter(typeof(AutoInterningStringConverter))]
|
||||
[DefaultValue("")]
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, PropertyName = "s")]
|
||||
@@ -28,22 +33,26 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
set => _segment = value ?? throw new ArgumentNullException(nameof(value)); // TODO: or fallback to string.Empty? CANNOT be null
|
||||
}
|
||||
|
||||
[DataMember(Order = 2)]
|
||||
[JsonProperty("v")]
|
||||
public object Value { get; set; }
|
||||
|
||||
//Legacy properties used to deserialize existing nucache db entries
|
||||
[DataMember(Order = 3)]
|
||||
[JsonProperty("culture")]
|
||||
private string LegacyCulture
|
||||
{
|
||||
set => Culture = value;
|
||||
}
|
||||
|
||||
[DataMember(Order = 4)]
|
||||
[JsonProperty("seg")]
|
||||
private string LegacySegment
|
||||
{
|
||||
set => Segment = value;
|
||||
}
|
||||
|
||||
[DataMember(Order = 5)]
|
||||
[JsonProperty("val")]
|
||||
private object LegacyValue
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user