Merge branch 'v8/8.15' into v8/dev

This commit is contained in:
Sebastiaan Janssen
2021-07-20 10:18:18 +02:00
24 changed files with 192 additions and 75 deletions

View File

@@ -43,7 +43,8 @@
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.1,4.999999)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.9.0,4.999999)" />
<dependency id="System.Text.Encoding.CodePages" version="[4.7.1,4.999999)" />
<dependency id="MessagePack" version="[2.1.165,2.999999)" />
<dependency id="MessagePack" version="[2.2.85,2.999999)" />
<dependency id="K4os.Compression.LZ4" version="[1.1.11,1.999999)" />
</group>

View File

@@ -19,4 +19,4 @@ using System.Resources;
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.15.0")]
[assembly: AssemblyInformationalVersion("8.15.0-rc")]
[assembly: AssemblyInformationalVersion("8.15.0")]

View File

@@ -9,6 +9,8 @@ namespace Umbraco.Core.Migrations.Expressions.Create.Table
public class CreateTableOfDtoBuilder : IExecutableBuilder
{
private readonly IMigrationContext _context;
// TODO: This doesn't do anything.
private readonly DatabaseType[] _supportedDatabaseTypes;
public CreateTableOfDtoBuilder(IMigrationContext context, params DatabaseType[] supportedDatabaseTypes)

View File

@@ -1,5 +1,10 @@
using System.Linq;
using NPoco;
using System.Data;
using System.Linq;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_15_0
{
@@ -13,9 +18,46 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_15_0
public override void Migrate()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
// allow null for the `data` field
if (DatabaseType.IsSqlCe())
{
// SQLCE does not support altering NTEXT, so we have to jump through some hoops to do it
// All column ordering must remain the same as what is defined in the DTO so we need to create a temp table,
// drop orig and then re-create/copy.
Create.Table<ContentNuDtoTemp>(withoutKeysAndIndexes: true).Do();
Execute.Sql($"INSERT INTO [{TempTableName}] SELECT nodeId, published, data, rv FROM [{Constants.DatabaseSchema.Tables.NodeData}]").Do();
Delete.Table(Constants.DatabaseSchema.Tables.NodeData).Do();
Create.Table<ContentNuDto>().Do();
Execute.Sql($"INSERT INTO [{Constants.DatabaseSchema.Tables.NodeData}] SELECT nodeId, published, data, rv, NULL FROM [{TempTableName}]").Do();
}
else
{
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
}
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
AddColumnIfNotExists<ContentNuDto>(columns, "dataRaw");
}
private const string TempTableName = Constants.DatabaseSchema.TableNamePrefix + "cms" + "ContentNuTEMP";
[TableName(TempTableName)]
[ExplicitColumns]
private class ContentNuDtoTemp
{
[Column("nodeId")]
public int NodeId { get; set; }
[Column("published")]
public bool Published { get; set; }
[Column("data")]
[SpecialDbType(SpecialDbTypes.NTEXT)]
[NullSetting(NullSetting = NullSettings.Null)]
public string Data { get; set; }
[Column("rv")]
public long Rv { get; set; }
}
}
}

View File

@@ -62,26 +62,33 @@ namespace Umbraco.Core.Persistence
/// <returns>The number of records that were inserted.</returns>
public static int BulkInsertRecords<T>(this IUmbracoDatabase database, IEnumerable<T> records, bool useNativeBulkInsert = true)
{
var recordsA = records.ToArray();
if (recordsA.Length == 0) return 0;
if (!records.Any()) return 0;
var pocoData = database.PocoDataFactory.ForType(typeof(T));
if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
if (database.DatabaseType.IsSqlCe())
{
if (useNativeBulkInsert) return BulkInsertRecordsSqlCe(database, pocoData, recordsA);
if (useNativeBulkInsert)
{
return BulkInsertRecordsSqlCe(database, pocoData, records);
}
// else, no other choice
foreach (var record in recordsA)
var count = 0;
foreach (var record in records)
{
database.Insert(record);
return recordsA.Length;
count++;
}
return count;
}
if (database.DatabaseType.IsSqlServer())
{
return useNativeBulkInsert && database.DatabaseType.IsSqlServer2008OrLater()
? BulkInsertRecordsSqlServer(database, pocoData, recordsA)
: BulkInsertRecordsWithCommands(database, recordsA);
? BulkInsertRecordsSqlServer(database, pocoData, records)
: BulkInsertRecordsWithCommands(database, records.ToArray());
}
throw new NotSupportedException();
}
@@ -96,7 +103,9 @@ namespace Umbraco.Core.Persistence
private static int BulkInsertRecordsWithCommands<T>(IUmbracoDatabase database, T[] records)
{
foreach (var command in database.GenerateBulkInsertCommands(records))
{
command.ExecuteNonQuery();
}
return records.Length; // what else?
}
@@ -241,6 +250,10 @@ namespace Umbraco.Core.Persistence
/// <returns>The number of records that were inserted.</returns>
internal static int BulkInsertRecordsSqlServer<T>(IUmbracoDatabase database, PocoData pocoData, IEnumerable<T> records)
{
// TODO: The main reason this exists is because the NPoco InsertBulk method doesn't return the number of items.
// It is worth investigating the performance of this vs NPoco's because we use a custom BulkDataReader
// which in theory should be more efficient than NPocos way of building up an in-memory DataTable.
// create command against the original database.Connection
using (var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty))
{
@@ -252,7 +265,13 @@ namespace Umbraco.Core.Persistence
var syntax = database.SqlContext.SqlSyntax as SqlServerSyntaxProvider;
if (syntax == null) throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider.");
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName })
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction)
{
BulkCopyTimeout = 0, // 0 = no bulk copy timeout. If a timeout occurs it will be an connection/command timeout.
DestinationTableName = tableName,
// be consistent with NPoco: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L50
BatchSize = 4096
})
using (var bulkReader = new PocoDataDataReader<T, SqlServerSyntaxProvider>(records, pocoData, syntax))
{
//we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared

View File

@@ -40,9 +40,10 @@ namespace Umbraco.Core.Persistence
_tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.Type);
// only real columns, exclude result columns
// only real columns, exclude result/computed columns
// Like NPoco does: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L59
_readerColumns = pd.Columns
.Where(x => x.Value.ResultColumn == false)
.Where(x => x.Value.ResultColumn == false && x.Value.ComputedColumn == false)
.Select(x => x.Value)
.ToArray();

View File

@@ -352,7 +352,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
sql.Append(" ");
sql.Append(FormatIdentity(column));
var isNullable = column.IsNullable;
//var isNullable = column.IsNullable;
//var constraint = FormatConstraint(column)?.TrimStart("CONSTRAINT ");
//var hasConstraint = !string.IsNullOrWhiteSpace(constraint);
@@ -360,11 +360,14 @@ namespace Umbraco.Core.Persistence.SqlSyntax
//var defaultValue = FormatDefaultValue(column);
//var hasDefaultValue = !string.IsNullOrWhiteSpace(defaultValue);
if (isNullable /*&& !hasConstraint && !hasDefaultValue*/)
{
sqls = Enumerable.Empty<string>();
return sql.ToString();
}
// TODO: This used to exit if nullable but that means this would never work
// to return SQL if the column was nullable?!? I don't get it. This was here
// 4 years ago, I've removed it so that this works for nullable columns.
//if (isNullable /*&& !hasConstraint && !hasDefaultValue*/)
//{
// sqls = Enumerable.Empty<string>();
// return sql.ToString();
//}
var msql = new List<string>();
sqls = msql;

View File

@@ -6,10 +6,16 @@ namespace Umbraco.Core.PropertyEditors
/// Determines if a property type's value should be compressed in memory
/// </summary>
/// <remarks>
///
///
/// </remarks>
public interface IPropertyCacheCompression
{
bool IsCompressed(IReadOnlyContentBase content, string propertyTypeAlias);
{
/// <summary>
/// Whether a property on the content is/should be compressed
/// </summary>
/// <param name="content">The content</param>
/// <param name="propertyTypeAlias">The property to compress or not</param>
/// <param name="published">Whether this content is the published version</param>
bool IsCompressed(IReadOnlyContentBase content, string propertyTypeAlias, bool published);
}
}

View File

@@ -4,6 +4,13 @@ namespace Umbraco.Core.PropertyEditors
{
public interface IPropertyCacheCompressionOptions
{
bool IsCompressed(IReadOnlyContentBase content, PropertyType propertyType, IDataEditor dataEditor);
/// <summary>
/// Whether a property on the content is/should be compressed
/// </summary>
/// <param name="content">The content</param>
/// <param name="propertyType">The property to compress or not</param>
/// <param name="dataEditor">The datatype of the property to compress or not</param>
/// <param name="published">Whether this content is the published version</param>
bool IsCompressed(IReadOnlyContentBase content, PropertyType propertyType, IDataEditor dataEditor, bool published);
}
}

View File

@@ -7,6 +7,6 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
internal class NoopPropertyCacheCompressionOptions : IPropertyCacheCompressionOptions
{
public bool IsCompressed(IReadOnlyContentBase content, PropertyType propertyType, IDataEditor dataEditor) => false;
public bool IsCompressed(IReadOnlyContentBase content, PropertyType propertyType, IDataEditor dataEditor, bool published) => false;
}
}

View File

@@ -14,13 +14,13 @@ namespace Umbraco.Core.PropertyEditors
private readonly IPropertyCacheCompressionOptions _compressionOptions;
private readonly IReadOnlyDictionary<int, IContentTypeComposition> _contentTypes;
private readonly PropertyEditorCollection _propertyEditors;
private readonly ConcurrentDictionary<(int contentTypeId, string propertyAlias), bool> _isCompressedCache;
private readonly ConcurrentDictionary<(int contentTypeId, string propertyAlias, bool published), bool> _isCompressedCache;
public PropertyCacheCompression(
IPropertyCacheCompressionOptions compressionOptions,
IReadOnlyDictionary<int, IContentTypeComposition> contentTypes,
PropertyEditorCollection propertyEditors,
ConcurrentDictionary<(int, string), bool> compressedStoragePropertyEditorCache)
ConcurrentDictionary<(int, string, bool), bool> compressedStoragePropertyEditorCache)
{
_compressionOptions = compressionOptions;
_contentTypes = contentTypes ?? throw new System.ArgumentNullException(nameof(contentTypes));
@@ -28,9 +28,9 @@ namespace Umbraco.Core.PropertyEditors
_isCompressedCache = compressedStoragePropertyEditorCache;
}
public bool IsCompressed(IReadOnlyContentBase content, string alias)
public bool IsCompressed(IReadOnlyContentBase content, string alias, bool published)
{
var compressedStorage = _isCompressedCache.GetOrAdd((content.ContentTypeId, alias), x =>
var compressedStorage = _isCompressedCache.GetOrAdd((content.ContentTypeId, alias, published), x =>
{
if (!_contentTypes.TryGetValue(x.contentTypeId, out var ct))
return false;
@@ -40,7 +40,7 @@ namespace Umbraco.Core.PropertyEditors
if (!_propertyEditors.TryGet(propertyType.PropertyEditorAlias, out var propertyEditor)) return false;
return _compressionOptions.IsCompressed(content, propertyType, propertyEditor);
return _compressionOptions.IsCompressed(content, propertyType, propertyEditor, published);
});
return compressedStorage;

View File

@@ -0,0 +1,20 @@
using Umbraco.Core.Models;
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Compress large, non published text properties
/// </summary>
internal class UnPublishedContentPropertyCacheCompressionOptions : IPropertyCacheCompressionOptions
{
public bool IsCompressed(IReadOnlyContentBase content, PropertyType propertyType, IDataEditor dataEditor, bool published)
{
if (!published && propertyType.SupportsPublishing && propertyType.ValueStorageType == ValueStorageType.Ntext)
{
//Only compress non published content that supports publishing and the property is text
return true;
}
return false;
}
}
}

View File

@@ -171,6 +171,7 @@
<Compile Include="PropertyEditors\NoopPropertyCacheCompressionOptions.cs" />
<Compile Include="PropertyEditors\PropertyCacheCompression.cs" />
<Compile Include="PropertyEditors\IPropertyCacheCompression.cs" />
<Compile Include="PropertyEditors\UnPublishedContentPropertyCacheCompressionOptions.cs" />
<Compile Include="Serialization\AutoInterningStringConverter.cs" />
<Compile Include="Serialization\AutoInterningStringKeyCaseInsensitiveDictionaryConverter.cs" />
<Compile Include="PropertyEditors\EyeDropperColorPickerConfiguration.cs" />

View File

@@ -56,14 +56,14 @@ namespace Umbraco.Tests.PublishedContent
var content = Mock.Of<IReadOnlyContentBase>(x => x.ContentTypeId == 1);
var json = jsonSerializer.Serialize(content, cacheModel).StringData;
var msgPack = msgPackSerializer.Serialize(content, cacheModel).ByteData;
var json = jsonSerializer.Serialize(content, cacheModel, false).StringData;
var msgPack = msgPackSerializer.Serialize(content, cacheModel, false).ByteData;
Console.WriteLine(json);
Console.WriteLine(msgPackSerializer.ToJson(msgPack));
var jsonContent = jsonSerializer.Deserialize(content, json, null);
var msgPackContent = msgPackSerializer.Deserialize(content, null, msgPack);
var jsonContent = jsonSerializer.Deserialize(content, json, null, false);
var msgPackContent = msgPackSerializer.Deserialize(content, null, msgPack, false);
CollectionAssert.AreEqual(jsonContent.CultureData.Keys, msgPackContent.CultureData.Keys);

View File

@@ -351,9 +351,6 @@
<DevelopmentServerPort>8150</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:8150</IISUrl>
<DevelopmentServerPort>8131</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:8131</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>

View File

@@ -393,12 +393,13 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
else
{
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
bool published = false;
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published);
d = new ContentData
{
Name = dto.EditName,
Published = false,
Published = published,
TemplateId = dto.EditTemplateId,
VersionId = dto.VersionId,
VersionDate = dto.EditVersionDate,
@@ -420,13 +421,14 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
else
{
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw);
bool published = true;
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw, published);
p = new ContentData
{
Name = dto.PubName,
UrlSegment = deserializedContent.UrlSegment,
Published = true,
Published = published,
TemplateId = dto.PubTemplateId,
VersionId = dto.VersionId,
VersionDate = dto.PubVersionDate,
@@ -456,12 +458,13 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
if (dto.EditData == null && dto.EditDataRaw == null)
throw new InvalidOperationException("No data for media " + dto.Id);
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
bool published = true;
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published);
var p = new ContentData
{
Name = dto.EditName,
Published = true,
Published = published,
TemplateId = -1,
VersionId = dto.VersionId,
VersionDate = dto.EditVersionDate,

View File

@@ -14,12 +14,12 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// <summary>
/// Deserialize the data into a <see cref="ContentCacheDataModel"/>
/// </summary>
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData);
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published);
/// <summary>
/// Serializes the <see cref="ContentCacheDataModel"/>
/// Serializes the <see cref="ContentCacheDataModel"/>
/// </summary>
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model);
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published);
}
}

View File

@@ -24,7 +24,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
DateFormatString = "o"
};
private readonly JsonNameTable _propertyNameTable = new DefaultJsonNameTable();
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published)
{
if (stringData == null && byteData != null)
throw new NotSupportedException($"{typeof(JsonContentNestedDataSerializer)} does not support byte[] serialization");
@@ -39,7 +39,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
}
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
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

View File

@@ -39,7 +39,8 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
_options = defaultOptions
.WithResolver(resolver)
.WithCompression(MessagePackCompression.Lz4BlockArray);
.WithCompression(MessagePackCompression.Lz4BlockArray)
.WithSecurity(MessagePackSecurity.UntrustedData);
}
public string ToJson(byte[] bin)
@@ -48,12 +49,12 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return json;
}
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published)
{
if (byteData != null)
{
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(byteData, _options);
Expand(content, cacheModel);
Expand(content, cacheModel, published);
return cacheModel;
}
else if (stringData != null)
@@ -61,7 +62,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
// NOTE: We don't really support strings but it's possible if manually used (i.e. tests)
var bin = Convert.FromBase64String(stringData);
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(bin, _options);
Expand(content, cacheModel);
Expand(content, cacheModel, published);
return cacheModel;
}
else
@@ -70,9 +71,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
}
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
{
Compress(content, model);
Compress(content, model, published);
var bytes = MessagePackSerializer.Serialize(model, _options);
return new ContentCacheDataSerializationResult(null, bytes);
}
@@ -80,7 +81,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// <summary>
/// Used during serialization to compress properties
/// </summary>
/// <param name="content"></param>
/// <param name="model"></param>
/// <param name="published"></param>
/// <remarks>
/// This will essentially 'double compress' property data. The MsgPack data as a whole will already be compressed
/// but this will go a step further and double compress property data so that it is stored in the nucache file
@@ -88,11 +91,11 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// read/decompressed as a string to be displayed on the front-end. This allows for potentially a significant
/// memory savings but could also affect performance of first rendering pages while decompression occurs.
/// </remarks>
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model)
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
{
foreach(var propertyAliasToData in model.PropertyData)
{
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key, published))
{
foreach(var property in propertyAliasToData.Value.Where(x => x.Value != null && x.Value is string))
{
@@ -105,12 +108,14 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// <summary>
/// Used during deserialization to map the property data as lazy or expand the value
/// </summary>
/// <param name="content"></param>
/// <param name="nestedData"></param>
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData)
/// <param name="published"></param>
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData, bool published)
{
foreach (var propertyAliasToData in nestedData.PropertyData)
{
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key,published))
{
foreach (var property in propertyAliasToData.Value.Where(x => x.Value != null))
{

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
private readonly IMemberTypeService _memberTypeService;
private readonly PropertyEditorCollection _propertyEditors;
private readonly IPropertyCacheCompressionOptions _compressionOptions;
private readonly ConcurrentDictionary<(int, string), bool> _isCompressedCache = new ConcurrentDictionary<(int, string), bool>();
private readonly ConcurrentDictionary<(int, string, bool), bool> _isCompressedCache = new ConcurrentDictionary<(int, string, bool), bool>();
public MsgPackContentNestedDataSerializerFactory(
IContentTypeService contentTypeService,

View File

@@ -24,10 +24,18 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
else
{
composition.RegisterUnique<IContentCacheDataSerializerFactory, MsgPackContentNestedDataSerializerFactory>();
composition.RegisterUnique<IContentCacheDataSerializerFactory, MsgPackContentNestedDataSerializerFactory>();
}
var unPublishedContentCompression = ConfigurationManager.AppSettings[NuCacheSerializerComponent.Nucache_UnPublishedContentCompression_Key];
if (serializer == "MsgPack" && unPublishedContentCompression == "true")
{
composition.RegisterUnique<IPropertyCacheCompressionOptions, UnPublishedContentPropertyCacheCompressionOptions>();
}
else
{
composition.RegisterUnique<IPropertyCacheCompressionOptions, NoopPropertyCacheCompressionOptions>();
}
composition.RegisterUnique<IPropertyCacheCompressionOptions, NoopPropertyCacheCompressionOptions>();
composition.RegisterUnique(factory => new ContentDataSerializer(new DictionaryOfPropertyDataSerializer()));

View File

@@ -16,6 +16,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public class NuCacheSerializerComponent : IComponent
{
internal const string Nucache_Serializer_Key = "Umbraco.Web.PublishedCache.NuCache.Serializer";
internal const string Nucache_UnPublishedContentCompression_Key = "Umbraco.Web.PublishedCache.NuCache.CompressUnPublishedContent";
private const string JSON_SERIALIZER_VALUE = "JSON";
private readonly Lazy<IPublishedSnapshotService> _service;
private readonly IKeyValueService _keyValueService;
@@ -54,7 +55,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
_profilingLogger.Warn<NuCacheSerializerComponent>($"Database NuCache was serialized using {currentSerializer}. Currently configured NuCache serializer {serializer}. Rebuilding Nucache");
using (_profilingLogger.TraceDuration<NuCacheSerializerComponent>($"Rebuilding NuCache database with {currentSerializer} serializer"))
using (_profilingLogger.TraceDuration<NuCacheSerializerComponent>($"Rebuilding NuCache database with {serializer} serializer"))
{
_service.Value.Rebuild();
_keyValueService.SetValue(Nucache_Serializer_Key, serializer);

View File

@@ -89,7 +89,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
IPublishedModelFactory publishedModelFactory,
UrlSegmentProviderCollection urlSegmentProviders,
ISyncBootStateAccessor syncBootStateAccessor,
IContentCacheDataSerializerFactory contentCacheDataSerializerFactory,
IContentCacheDataSerializerFactory contentCacheDataSerializerFactory,
ContentDataSerializer contentDataSerializer = null)
: base(publishedSnapshotAccessor, variationContextAccessor)
{
@@ -177,7 +177,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_localContentDb = BTree.GetTree(localContentDbPath, _localContentDbExists, _contentDataSerializer);
_localMediaDb = BTree.GetTree(localMediaDbPath, _localMediaDbExists, _contentDataSerializer);
_logger.Info<PublishedSnapshotService,bool,bool>("Registered with MainDom, localContentDbExists? {LocalContentDbExists}, localMediaDbExists? {LocalMediaDbExists}", _localContentDbExists, _localMediaDbExists);
_logger.Info<PublishedSnapshotService, bool, bool>("Registered with MainDom, localContentDbExists? {LocalContentDbExists}, localMediaDbExists? {LocalMediaDbExists}", _localContentDbExists, _localMediaDbExists);
}
/// <summary>
@@ -262,7 +262,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (!okMedia)
_logger.Warn<PublishedSnapshotService>("Loading media from local db raised warnings, will reload from database.");
}
if (!okContent)
LockAndLoadContent(scope => LoadContentFromDatabaseLocked(scope, true));
@@ -1168,7 +1168,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (Volatile.Read(ref _isReady) == false)
{
throw new InvalidOperationException("The published snapshot service has not properly initialized.");
}
}
var preview = previewToken.IsNullOrWhiteSpace() == false;
return new PublishedSnapshot(this, preview);
@@ -1491,7 +1491,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
UrlSegment = content.GetUrlSegment(_urlSegmentProviders)
};
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData);
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData, published);
var dto = new ContentNuDto
{

View File

@@ -281,14 +281,15 @@ namespace Umbraco.Web
return CreateHtmlString(url, htmlEncode);
}
public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue imageCropperValue, string cropAlias, bool htmlEncode = true)
{
if (imageCropperValue == null || string.IsNullOrEmpty(imageCropperValue.Src)) return EmptyHtmlString;
var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, cropAlias: cropAlias, useCropDimensions: true);
return CreateHtmlString(url, htmlEncode);
}
// TODO: enable again in v9 and make sure to document that `@Url.GetCropUrl(Model.Property, cropAlias: "Featured")` needs to be updated - see https://github.com/umbraco/Umbraco-CMS/pull/10527 for alternatives
// public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue imageCropperValue, string cropAlias, bool htmlEncode = true)
// {
// if (imageCropperValue == null || string.IsNullOrEmpty(imageCropperValue.Src)) return EmptyHtmlString;
//
// var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, cropAlias: cropAlias, useCropDimensions: true);
//
// return CreateHtmlString(url, htmlEncode);
// }
public static IHtmlString GetCropUrl(this UrlHelper urlHelper,
ImageCropperValue imageCropperValue,