Merge remote-tracking branch 'origin/v12/dev' into v13/dev
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.DistributedLocking;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Persistence.EFCore.Factories;
|
||||
using Umbraco.Cms.Persistence.EFCore.Locking;
|
||||
using Umbraco.Cms.Persistence.EFCore.Migrations;
|
||||
using Umbraco.Cms.Persistence.EFCore.Scoping;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
@@ -17,6 +19,13 @@ public static class UmbracoEFCoreServiceCollectionExtensions
|
||||
public static IServiceCollection AddUmbracoEFCoreContext<T>(this IServiceCollection services, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
|
||||
where T : DbContext
|
||||
{
|
||||
var optionsBuilder = new DbContextOptionsBuilder<T>();
|
||||
services.TryAddSingleton<IDbContextFactory<T>>(
|
||||
sp =>
|
||||
{
|
||||
SetupDbContext(defaultEFCoreOptionsAction, sp, optionsBuilder);
|
||||
return new UmbracoPooledDbContextFactory<T>(sp.GetRequiredService<IRuntimeState>(),optionsBuilder.Options);
|
||||
});
|
||||
services.AddPooledDbContextFactory<T>((provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder));
|
||||
services.AddTransient(services => services.GetRequiredService<IDbContextFactory<T>>().CreateDbContext());
|
||||
|
||||
@@ -39,6 +48,13 @@ public static class UmbracoEFCoreServiceCollectionExtensions
|
||||
connectionString = connectionString.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory);
|
||||
}
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder<T>();
|
||||
services.TryAddSingleton<IDbContextFactory<T>>(
|
||||
sp =>
|
||||
{
|
||||
SetupDbContext(defaultEFCoreOptionsAction, sp, optionsBuilder);
|
||||
return new UmbracoPooledDbContextFactory<T>(sp.GetRequiredService<IRuntimeState>(),optionsBuilder.Options);
|
||||
});
|
||||
services.AddPooledDbContextFactory<T>(options => defaultEFCoreOptionsAction?.Invoke(options, providerName, connectionString));
|
||||
services.AddTransient(services => services.GetRequiredService<IDbContextFactory<T>>().CreateDbContext());
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Persistence.EFCore.Factories;
|
||||
|
||||
/// <inheritdoc/>
|
||||
internal class UmbracoPooledDbContextFactory<TContext> : PooledDbContextFactory<TContext>
|
||||
where TContext : DbContext
|
||||
{
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly DbContextOptions<TContext> _options;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public UmbracoPooledDbContextFactory(IRuntimeState runtimeState, DbContextOptions<TContext> options, int poolSize = 1024 /*DbContextPool<DbContext>.DefaultPoolSize*/) : base(options, poolSize)
|
||||
{
|
||||
_runtimeState = runtimeState;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TContext CreateDbContext()
|
||||
{
|
||||
if (_runtimeState.Level == RuntimeLevel.Run)
|
||||
{
|
||||
return base.CreateDbContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (TContext?)Activator.CreateInstance(typeof(TContext), _options) ?? throw new InvalidOperationException("Unable to create DbContext");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<TContext> CreateDbContextAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_runtimeState.Level == RuntimeLevel.Run)
|
||||
{
|
||||
return await base.CreateDbContextAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (TContext?)Activator.CreateInstance(typeof(TContext), _options) ?? throw new InvalidOperationException("Unable to create DbContext");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.DeliveryApi;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
@@ -16,7 +18,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
/// Since this is a default (umbraco) converter it will be ignored if another converter found conflicts with this one.
|
||||
/// </remarks>
|
||||
[DefaultPropertyValueConverter]
|
||||
public class JsonValueConverter : PropertyValueConverterBase
|
||||
public class JsonValueConverter : PropertyValueConverterBase, IDeliveryApiPropertyValueConverter
|
||||
{
|
||||
private readonly ILogger<JsonValueConverter> _logger;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
@@ -76,5 +78,14 @@ public class JsonValueConverter : PropertyValueConverterBase
|
||||
return sourceString;
|
||||
}
|
||||
|
||||
// TODO: Now to convert that to XPath!
|
||||
public PropertyCacheLevel GetDeliveryApiPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> GetPropertyCacheLevel(propertyType);
|
||||
|
||||
public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof(JsonNode);
|
||||
|
||||
public object? ConvertIntermediateToDeliveryApiObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview, bool expanding)
|
||||
=> inter is JObject jObject
|
||||
? JsonNode.Parse(jObject.ToString())
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi;
|
||||
|
||||
[TestFixture]
|
||||
public class JsonValueConverterTests : PropertyValueConverterTests
|
||||
{
|
||||
[Test]
|
||||
public void JsonValueConverterTests_ConvertsCustomPropertyWithValueTypeJson()
|
||||
{
|
||||
var valueEditor = Mock.Of<IDataValueEditor>(x => x.ValueType == ValueTypes.Json);
|
||||
var dataEditor = Mock.Of<IDataEditor>(x => x.GetValueEditor() == valueEditor);
|
||||
var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == "My.Custom.Json");
|
||||
|
||||
var valueConverter = new JsonValueConverter(propertyEditors, Mock.Of<ILogger<JsonValueConverter>>());
|
||||
var inter = valueConverter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, "{\"message\": \"Hello, JSON\"}", false);
|
||||
var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false, false);
|
||||
Assert.IsTrue(result is JsonNode);
|
||||
JsonNode jsonNode = (JsonNode)result;
|
||||
Assert.AreEqual("Hello, JSON", jsonNode["message"]!.GetValue<string>());
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
@@ -133,4 +135,19 @@ public class PropertyEditorValueConverterTests
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanConvertManifestBasedPropertyWithValueTypeJson()
|
||||
{
|
||||
var valueEditor = Mock.Of<IDataValueEditor>(x => x.ValueType == ValueTypes.Json);
|
||||
var dataEditor = Mock.Of<IDataEditor>(x => x.GetValueEditor() == valueEditor);
|
||||
var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => new[] { dataEditor }));
|
||||
var propertyType = Mock.Of<IPublishedPropertyType>(x => x.EditorAlias == "My.Custom.Json");
|
||||
|
||||
var valueConverter = new JsonValueConverter(propertyEditors, Mock.Of<ILogger<JsonValueConverter>>());
|
||||
var inter = valueConverter.ConvertSourceToIntermediate(Mock.Of<IPublishedElement>(), propertyType, "{\"message\": \"Hello, JSON\"}", false);
|
||||
var result = valueConverter.ConvertIntermediateToObject(Mock.Of<IPublishedElement>(), propertyType, PropertyCacheLevel.Element, inter, false) as JObject;
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual("Hello, JSON", result["message"]!.Value<string>());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user