diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index 834d211994..fef096498c 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -37,6 +37,7 @@ namespace Umbraco.Tests.PublishedContent private ContentType _contentTypeInvariant; private ContentType _contentTypeVariant; private TestDataSource _source; + private IContentNestedDataSerializer _contentNestedDataSerializer; [TearDown] public void Teardown() @@ -134,6 +135,7 @@ namespace Umbraco.Tests.PublishedContent // create a data source for NuCache _source = new TestDataSource(kits()); + _contentNestedDataSerializer = new JsonContentNestedDataSerializer(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; @@ -155,7 +157,8 @@ namespace Umbraco.Tests.PublishedContent globalSettings, Mock.Of(), Mock.Of(), - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() })); + new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), + _contentNestedDataSerializer); // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 0e05e6baad..792ccc8529 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -33,6 +33,7 @@ namespace Umbraco.Tests.PublishedContent { private IPublishedSnapshotService _snapshotService; private IVariationContextAccessor _variationAccesor; + private IContentNestedDataSerializer _contentNestedDataSerializer; private ContentType _contentType; private PropertyType _propertyType; @@ -114,6 +115,7 @@ namespace Umbraco.Tests.PublishedContent // create a data source for NuCache var dataSource = new TestDataSource(kit); + _contentNestedDataSerializer = new JsonContentNestedDataSerializer(); var runtime = Mock.Of(); Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); @@ -201,7 +203,8 @@ namespace Umbraco.Tests.PublishedContent globalSettings, Mock.Of(), Mock.Of(), - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() })); + new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), + _contentNestedDataSerializer); // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index c7c403b260..5f72947382 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -82,6 +82,7 @@ namespace Umbraco.Tests.Scoping var mediaRepository = Mock.Of(); var memberRepository = Mock.Of(); + var nestedContentDataSerializer = new JsonContentNestedDataSerializer(); return new PublishedSnapshotService( options, null, @@ -95,11 +96,12 @@ namespace Umbraco.Tests.Scoping ScopeProvider, documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, - new DatabaseDataSource(), + new DatabaseDataSource(nestedContentDataSerializer), Factory.GetInstance(), Factory.GetInstance(), Mock.Of(), - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() })); + new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), + nestedContentDataSerializer); } protected UmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable urlProviders = null) diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index 9391b7442f..938b14c3a9 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -53,6 +53,8 @@ namespace Umbraco.Tests.Services var mediaRepository = Mock.Of(); var memberRepository = Mock.Of(); + var nestedContentDataSerializer = new JsonContentNestedDataSerializer(); + return new PublishedSnapshotService( options, null, @@ -66,11 +68,12 @@ namespace Umbraco.Tests.Services ScopeProvider, documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, - new DatabaseDataSource(), + new DatabaseDataSource(nestedContentDataSerializer), Factory.GetInstance(), Factory.GetInstance(), Mock.Of(), - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() })); + new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), + nestedContentDataSerializer); } public class LocalServerMessenger : ServerMessengerBase diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs index 751644c715..413ab4ab63 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs @@ -7,7 +7,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource /// /// The content item 1:M data that is serialized to JSON /// - internal class ContentNestedData + public class ContentNestedData { //dont serialize empty properties [JsonProperty("pd")] diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs index 57ffbba34e..b59e8c403c 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs @@ -6,7 +6,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource /// /// Represents the culture variation information on a content item /// - internal class CultureVariation + public class CultureVariation { [JsonProperty("nm")] public string Name { get; set; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs index 694dac04df..80cfabd470 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs @@ -20,7 +20,15 @@ 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) + { + _contentNestedDataSerializer = contentNestedDataSerializer; + } // we want arrays, we want them all loaded, not an enumerable @@ -198,7 +206,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource yield return CreateMediaNodeKit(row); } - private static ContentNodeKit CreateContentNodeKit(ContentSourceDto dto) + private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto) { ContentData d = null; ContentData p = null; @@ -213,7 +221,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource } else { - var nested = DeserializeNestedData(dto.EditData); + var nested = _contentNestedDataSerializer.Deserialize(dto.EditData); d = new ContentData { @@ -240,7 +248,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource } else { - var nested = DeserializeNestedData(dto.PubData); + var nested = _contentNestedDataSerializer.Deserialize(dto.PubData); p = new ContentData { @@ -271,12 +279,12 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource return s; } - private static ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto) + private ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto) { if (dto.EditData == null) throw new Exception("No data for media " + dto.Id); - var nested = DeserializeNestedData(dto.EditData); + var nested = _contentNestedDataSerializer.Deserialize(dto.EditData); var p = new ContentData { @@ -303,17 +311,6 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource return s; } - private static ContentNestedData DeserializeNestedData(string data) - { - // by default JsonConvert will deserialize our numeric values as Int64 - // which is bad, because they were Int32 in the database - take care - - var settings = new JsonSerializerSettings - { - Converters = new List { new ForceInt32Converter() } - }; - - return JsonConvert.DeserializeObject(data, settings); - } + } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/IContentNestedDataSerializer.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/IContentNestedDataSerializer.cs new file mode 100644 index 0000000000..d9e2702d08 --- /dev/null +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/IContentNestedDataSerializer.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Umbraco.Web.PublishedCache.NuCache.DataSource +{ + public interface IContentNestedDataSerializer + { + ContentNestedData Deserialize(string data); + string Serialize(ContentNestedData nestedData); + } +} diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/JsonContentNestedDataSerializer.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/JsonContentNestedDataSerializer.cs new file mode 100644 index 0000000000..4ef63c09fb --- /dev/null +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/JsonContentNestedDataSerializer.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core.Serialization; + +namespace Umbraco.Web.PublishedCache.NuCache.DataSource +{ + internal class JsonContentNestedDataSerializer : IContentNestedDataSerializer + { + public ContentNestedData Deserialize(string data) + { + // by default JsonConvert will deserialize our numeric values as Int64 + // which is bad, because they were Int32 in the database - take care + + var settings = new JsonSerializerSettings + { + Converters = new List { new ForceInt32Converter() } + }; + + return JsonConvert.DeserializeObject(data, settings); + } + + public string Serialize(ContentNestedData nestedData) + { + return JsonConvert.SerializeObject(nestedData); + } + } +} diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/PropertyData.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/PropertyData.cs index 6ccb1dc210..d49a976b7a 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/PropertyData.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/PropertyData.cs @@ -5,7 +5,7 @@ using Umbraco.Core.Serialization; namespace Umbraco.Web.PublishedCache.NuCache.DataSource { - internal class PropertyData + public class PropertyData { private string _culture; private string _segment; diff --git a/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComposer.cs b/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComposer.cs index f748fd555c..f67256bb6b 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComposer.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/NuCacheComposer.cs @@ -10,6 +10,9 @@ namespace Umbraco.Web.PublishedCache.NuCache { base.Compose(composition); + // register the NuCache NestedContentData serializer + composition.Register(); + // register the NuCache database data source composition.Register(); diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index fcea6e6227..5ce62271a7 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -49,6 +49,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IPublishedModelFactory _publishedModelFactory; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly UrlSegmentProviderCollection _urlSegmentProviders; + private readonly IContentNestedDataSerializer _contentNestedDataSerializer; // volatile because we read it with no lock private volatile bool _isReady; @@ -82,7 +83,7 @@ namespace Umbraco.Web.PublishedCache.NuCache IDataSource dataSource, IGlobalSettings globalSettings, IEntityXmlSerializer entitySerializer, IPublishedModelFactory publishedModelFactory, - UrlSegmentProviderCollection urlSegmentProviders) + UrlSegmentProviderCollection urlSegmentProviders, IContentNestedDataSerializer contentNestedDataSerializer) : base(publishedSnapshotAccessor, variationContextAccessor) { //if (Interlocked.Increment(ref _singletonCheck) > 1) @@ -99,6 +100,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings; _urlSegmentProviders = urlSegmentProviders; + _contentNestedDataSerializer = contentNestedDataSerializer; // we need an Xml serializer here so that the member cache can support XPath, // for members this is done by navigating the serialized-to-xml member @@ -1458,7 +1460,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // note that numeric values (which are Int32) are serialized without their // type (eg "value":1234) and JsonConvert by default deserializes them as Int64 - Data = JsonConvert.SerializeObject(nestedData) + Data = _contentNestedDataSerializer.Serialize(nestedData) }; //Core.Composing.Current.Logger.Debug(dto.Data); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b1cbff0fef..01f81cfc83 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -245,6 +245,8 @@ + +