Merge remote-tracking branch 'origin/netcore/netcore' into netcore/feature/remove-httpresponseexception
# Conflicts: # src/Umbraco.Web.BackOffice/Controllers/EntityController.cs # src/Umbraco.Web.Common/Install/InstallApiController.cs
This commit is contained in:
14
NuGet.Config
14
NuGet.Config
@@ -1,13 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!--
|
<!--
|
||||||
this is Umbraco's NuGet configuration,
|
this is Umbraco's NuGet configuration,
|
||||||
content of this file is merged with the system-wide configuration,
|
content of this file is merged with the system-wide configuration,
|
||||||
at %APPDATA%\NuGet\NuGet.config
|
at %APPDATA%\NuGet\NuGet.config
|
||||||
-->
|
-->
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="UmbracoCoreMyGet" value="https://www.myget.org/F/umbracocore/api/v3/index.json" />
|
<clear />
|
||||||
<add key="ExamineAzurePipelines" value="https://shazwazza.pkgs.visualstudio.com/Examine/_packaging/Examine-Beta/nuget/v3/index.json" />
|
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||||
<add key="SmidgeAppVeyor" value="https://ci.appveyor.com/nuget/smidge" />
|
<add key="UmbracoCoreMyGet" value="https://www.myget.org/F/umbracocore/api/v3/index.json" />
|
||||||
</packageSources>
|
<add key="ExamineAzurePipelines" value="https://shazwazza.pkgs.visualstudio.com/Examine/_packaging/Examine-Beta/nuget/v3/index.json" />
|
||||||
|
<add key="SmidgeAppVeyor" value="https://ci.appveyor.com/nuget/smidge" />
|
||||||
|
</packageSources>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return;
|
if (refresherGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRefresh(
|
_serverMessenger.QueueRefresh(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
getNumericId,
|
getNumericId,
|
||||||
instances);
|
instances);
|
||||||
@@ -61,7 +61,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty || id == default(int)) return;
|
if (refresherGuid == Guid.Empty || id == default(int)) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRefresh(
|
_serverMessenger.QueueRefresh(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
id);
|
id);
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty || id == Guid.Empty) return;
|
if (refresherGuid == Guid.Empty || id == Guid.Empty) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRefresh(
|
_serverMessenger.QueueRefresh(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
id);
|
id);
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty || payload == null) return;
|
if (refresherGuid == Guid.Empty || payload == null) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRefresh(
|
_serverMessenger.QueueRefresh(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
payload);
|
payload);
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty || payloads == null) return;
|
if (refresherGuid == Guid.Empty || payloads == null) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRefresh(
|
_serverMessenger.QueueRefresh(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
payloads.ToArray());
|
payloads.ToArray());
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty) return;
|
if (refresherGuid == Guid.Empty) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRefreshAll(
|
_serverMessenger.QueueRefreshAll(
|
||||||
GetRefresherById(refresherGuid));
|
GetRefresherById(refresherGuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ namespace Umbraco.Web.Cache
|
|||||||
{
|
{
|
||||||
if (refresherGuid == Guid.Empty || id == default(int)) return;
|
if (refresherGuid == Guid.Empty || id == default(int)) return;
|
||||||
|
|
||||||
_serverMessenger.PerformRemove(
|
_serverMessenger.QueueRemove(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
id);
|
id);
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ namespace Umbraco.Web.Cache
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void Remove<T>(Guid refresherGuid, Func<T, int> getNumericId, params T[] instances)
|
public void Remove<T>(Guid refresherGuid, Func<T, int> getNumericId, params T[] instances)
|
||||||
{
|
{
|
||||||
_serverMessenger.PerformRemove(
|
_serverMessenger.QueueRemove(
|
||||||
GetRefresherById(refresherGuid),
|
GetRefresherById(refresherGuid),
|
||||||
getNumericId,
|
getNumericId,
|
||||||
instances);
|
instances);
|
||||||
@@ -164,9 +164,15 @@ namespace Umbraco.Web.Cache
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// helper method to get an ICacheRefresher by its unique identifier
|
// helper method to get an ICacheRefresher by its unique identifier
|
||||||
private ICacheRefresher GetRefresherById(Guid refresherGuid)
|
private ICacheRefresher GetRefresherById(Guid refresherGuid)
|
||||||
{
|
{
|
||||||
return _cacheRefreshers[refresherGuid];
|
ICacheRefresher refresher = _cacheRefreshers[refresherGuid];
|
||||||
|
if (refresher == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No cache refresher found with id {refresherGuid}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return refresher;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
using Umbraco.Core.Composing;
|
|
||||||
|
|
||||||
namespace Umbraco.Web.Cache
|
|
||||||
{
|
|
||||||
public class DistributedCacheBinderComponent : IComponent
|
|
||||||
{
|
|
||||||
private readonly IDistributedCacheBinder _binder;
|
|
||||||
|
|
||||||
public DistributedCacheBinderComponent(IDistributedCacheBinder distributedCacheBinder)
|
|
||||||
{
|
|
||||||
_binder = distributedCacheBinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
_binder.BindEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Terminate()
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
|
||||||
namespace Umbraco.Core.Composing
|
namespace Umbraco.Core.Composing
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -70,7 +70,6 @@ namespace Umbraco.Core.Composing
|
|||||||
|
|
||||||
foreach (var composer in composers)
|
foreach (var composer in composers)
|
||||||
{
|
{
|
||||||
var componentType = composer.GetType();
|
|
||||||
composer.Compose(_builder);
|
composer.Compose(_builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
using Umbraco.Web.PublishedCache;
|
using Umbraco.Web.PublishedCache;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
|
||||||
namespace Umbraco.Core.Composing
|
namespace Umbraco.Core.Composing
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
using Umbraco.Core.HealthCheck;
|
|
||||||
using Umbraco.Core.Manifest;
|
|
||||||
using Umbraco.Core.PropertyEditors;
|
|
||||||
using Umbraco.Web.Actions;
|
|
||||||
using Umbraco.Web.ContentApps;
|
|
||||||
using Umbraco.Web.Dashboards;
|
|
||||||
using Umbraco.Web.Editors;
|
|
||||||
using Umbraco.Web.Routing;
|
|
||||||
using Umbraco.Web.Sections;
|
|
||||||
using Umbraco.Web.Tour;
|
|
||||||
|
|
||||||
namespace Umbraco.Core
|
|
||||||
{
|
|
||||||
public static partial class CompositionExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
#region Collection Builders
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the actions collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<ActionCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the content apps collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<ContentAppFactoryCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the content finders collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<ContentFinderCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the editor validators collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<EditorValidatorCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the health checks collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<HealthCheckCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the TourFilters collection builder.
|
|
||||||
/// </summary>
|
|
||||||
public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<TourFilterCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the URL providers collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<UrlProviderCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the media url providers collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<MediaUrlProviderCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the backoffice sections/applications collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<SectionCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the components collection builder.
|
|
||||||
/// </summary>
|
|
||||||
public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<ComponentCollectionBuilder>();
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the backoffice dashboards collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<DashboardCollectionBuilder>()
|
|
||||||
.Add<ContentDashboard>()
|
|
||||||
.Add<ExamineDashboard>()
|
|
||||||
.Add<FormsDashboard>()
|
|
||||||
.Add<HealthCheckDashboard>()
|
|
||||||
.Add<ManifestDashboard>()
|
|
||||||
.Add<MediaDashboard>()
|
|
||||||
.Add<MembersDashboard>()
|
|
||||||
.Add<ProfilerDashboard>()
|
|
||||||
.Add<PublishedStatusDashboard>()
|
|
||||||
.Add<RedirectUrlDashboard>()
|
|
||||||
.Add<SettingsDashboard>();
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the content finders collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<MediaUrlGeneratorCollectionBuilder>();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Umbraco.Core;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
|
|
||||||
namespace Umbraco.Core
|
namespace Umbraco.Core.DependencyInjection
|
||||||
{
|
{
|
||||||
public static class ServiceCollectionExtensions
|
public static class ServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
@@ -21,7 +22,7 @@ namespace Umbraco.Core
|
|||||||
where TImplementing : class, TService1, TService2
|
where TImplementing : class, TService1, TService2
|
||||||
{
|
{
|
||||||
services.AddUnique<TService1, TImplementing>();
|
services.AddUnique<TService1, TImplementing>();
|
||||||
services.AddUnique<TService2>(factory => (TImplementing) factory.GetRequiredService<TService1>());
|
services.AddUnique<TService2>(factory => (TImplementing)factory.GetRequiredService<TService1>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddUnique<TImplementing>(this IServiceCollection services)
|
public static void AddUnique<TImplementing>(this IServiceCollection services)
|
||||||
@@ -48,9 +49,9 @@ namespace Umbraco.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void AddUnique<TService>(this IServiceCollection services, TService instance)
|
public static void AddUnique<TService>(this IServiceCollection services, TService instance)
|
||||||
where TService : class
|
where TService : class
|
||||||
=> services.Replace(ServiceDescriptor.Singleton<TService>(instance));
|
=> services.Replace(ServiceDescriptor.Singleton(instance));
|
||||||
|
|
||||||
public static IServiceCollection AddLazySupport(this IServiceCollection services)
|
internal static IServiceCollection AddLazySupport(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.Replace(ServiceDescriptor.Transient(typeof(Lazy<>), typeof(LazyResolve<>)));
|
services.Replace(ServiceDescriptor.Transient(typeof(Lazy<>), typeof(LazyResolve<>)));
|
||||||
return services;
|
return services;
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
|
|
||||||
namespace Umbraco.Core
|
namespace Umbraco.Core.DependencyInjection
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides extension methods to the <see cref="IFactory"/> class.
|
/// Provides extension methods to the <see cref="IFactory"/> class.
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using Umbraco.Core.Cache;
|
||||||
|
using Umbraco.Core.Composing;
|
||||||
|
using Umbraco.Core.Dashboards;
|
||||||
|
using Umbraco.Core.HealthCheck;
|
||||||
|
using Umbraco.Core.Manifest;
|
||||||
|
using Umbraco.Core.PackageActions;
|
||||||
|
using Umbraco.Core.PropertyEditors;
|
||||||
|
using Umbraco.Core.PropertyEditors.Validators;
|
||||||
|
using Umbraco.Core.Strings;
|
||||||
|
using Umbraco.Core.Trees;
|
||||||
|
using Umbraco.Web.Actions;
|
||||||
|
using Umbraco.Web.ContentApps;
|
||||||
|
using Umbraco.Web.Dashboards;
|
||||||
|
using Umbraco.Web.Editors;
|
||||||
|
using Umbraco.Web.HealthCheck;
|
||||||
|
using Umbraco.Web.HealthCheck.NotificationMethods;
|
||||||
|
using Umbraco.Web.Media.EmbedProviders;
|
||||||
|
using Umbraco.Web.Routing;
|
||||||
|
using Umbraco.Web.Sections;
|
||||||
|
using Umbraco.Web.Tour;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="IUmbracoBuilder"/>
|
||||||
|
/// </summary>
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds all core collection builders
|
||||||
|
/// </summary>
|
||||||
|
internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
builder.CacheRefreshers().Add(() => builder.TypeLoader.GetCacheRefreshers());
|
||||||
|
builder.DataEditors().Add(() => builder.TypeLoader.GetDataEditors());
|
||||||
|
builder.Actions().Add(() => builder.TypeLoader.GetTypes<IAction>());
|
||||||
|
// register known content apps
|
||||||
|
builder.ContentApps()
|
||||||
|
.Append<ListViewContentAppFactory>()
|
||||||
|
.Append<ContentEditorContentAppFactory>()
|
||||||
|
.Append<ContentInfoContentAppFactory>()
|
||||||
|
.Append<ContentTypeDesignContentAppFactory>()
|
||||||
|
.Append<ContentTypeListViewContentAppFactory>()
|
||||||
|
.Append<ContentTypePermissionsContentAppFactory>()
|
||||||
|
.Append<ContentTypeTemplatesContentAppFactory>();
|
||||||
|
// all built-in finders in the correct order,
|
||||||
|
// devs can then modify this list on application startup
|
||||||
|
builder.ContentFinders()
|
||||||
|
.Append<ContentFinderByPageIdQuery>()
|
||||||
|
.Append<ContentFinderByUrl>()
|
||||||
|
.Append<ContentFinderByIdPath>()
|
||||||
|
/*.Append<ContentFinderByUrlAndTemplate>() // disabled, this is an odd finder */
|
||||||
|
.Append<ContentFinderByUrlAlias>()
|
||||||
|
.Append<ContentFinderByRedirectUrl>();
|
||||||
|
builder.EditorValidators().Add(() => builder.TypeLoader.GetTypes<IEditorValidator>());
|
||||||
|
builder.HealthChecks().Add(() => builder.TypeLoader.GetTypes<Core.HealthCheck.HealthCheck>());
|
||||||
|
builder.HealthCheckNotificationMethods().Add(() => builder.TypeLoader.GetTypes<IHealthCheckNotificationMethod>());
|
||||||
|
builder.TourFilters();
|
||||||
|
builder.UrlProviders()
|
||||||
|
.Append<AliasUrlProvider>()
|
||||||
|
.Append<DefaultUrlProvider>();
|
||||||
|
builder.MediaUrlProviders()
|
||||||
|
.Append<DefaultMediaUrlProvider>();
|
||||||
|
// register back office sections in the order we want them rendered
|
||||||
|
builder.Sections()
|
||||||
|
.Append<ContentSection>()
|
||||||
|
.Append<MediaSection>()
|
||||||
|
.Append<SettingsSection>()
|
||||||
|
.Append<PackagesSection>()
|
||||||
|
.Append<UsersSection>()
|
||||||
|
.Append<MembersSection>()
|
||||||
|
.Append<FormsSection>()
|
||||||
|
.Append<TranslationSection>();
|
||||||
|
builder.Components();
|
||||||
|
// register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards
|
||||||
|
builder.Dashboards()
|
||||||
|
.Add<ContentDashboard>()
|
||||||
|
.Add<ExamineDashboard>()
|
||||||
|
.Add<FormsDashboard>()
|
||||||
|
.Add<HealthCheckDashboard>()
|
||||||
|
.Add<ManifestDashboard>()
|
||||||
|
.Add<MediaDashboard>()
|
||||||
|
.Add<MembersDashboard>()
|
||||||
|
.Add<ProfilerDashboard>()
|
||||||
|
.Add<PublishedStatusDashboard>()
|
||||||
|
.Add<RedirectUrlDashboard>()
|
||||||
|
.Add<SettingsDashboard>()
|
||||||
|
.Add(builder.TypeLoader.GetTypes<IDashboard>());
|
||||||
|
builder.PackageActions().Add(() => builder.TypeLoader.GetPackageActions());
|
||||||
|
builder.DataValueReferenceFactories();
|
||||||
|
builder.PropertyValueConverters().Append(builder.TypeLoader.GetTypes<IPropertyValueConverter>());
|
||||||
|
builder.UrlSegmentProviders().Append<DefaultUrlSegmentProvider>();
|
||||||
|
builder.ManifestValueValidators()
|
||||||
|
.Add<RequiredValidator>()
|
||||||
|
.Add<RegexValidator>()
|
||||||
|
.Add<DelimitedValueValidator>()
|
||||||
|
.Add<EmailValidator>()
|
||||||
|
.Add<IntegerValidator>()
|
||||||
|
.Add<DecimalValidator>();
|
||||||
|
builder.ManifestFilters();
|
||||||
|
builder.MediaUrlGenerators();
|
||||||
|
// register OEmbed providers - no type scanning - all explicit opt-in of adding types, IEmbedProvider is not IDiscoverable
|
||||||
|
builder.OEmbedProviders()
|
||||||
|
.Append<YouTube>()
|
||||||
|
.Append<Twitter>()
|
||||||
|
.Append<Vimeo>()
|
||||||
|
.Append<DailyMotion>()
|
||||||
|
.Append<Flickr>()
|
||||||
|
.Append<Slideshare>()
|
||||||
|
.Append<Kickstarter>()
|
||||||
|
.Append<GettyImages>()
|
||||||
|
.Append<Ted>()
|
||||||
|
.Append<Soundcloud>()
|
||||||
|
.Append<Issuu>()
|
||||||
|
.Append<Hulu>()
|
||||||
|
.Append<Giphy>();
|
||||||
|
builder.SearchableTrees().Add(() => builder.TypeLoader.GetTypes<ISearchableTree>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actions collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<ActionCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the content apps collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<ContentAppFactoryCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the content finders collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<ContentFinderCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the editor validators collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<EditorValidatorCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the health checks collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<HealthCheckCollectionBuilder>();
|
||||||
|
|
||||||
|
public static HealthCheckNotificationMethodCollectionBuilder HealthCheckNotificationMethods(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<HealthCheckNotificationMethodCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the TourFilters collection builder.
|
||||||
|
/// </summary>
|
||||||
|
public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<TourFilterCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the URL providers collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<UrlProviderCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the media url providers collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<MediaUrlProviderCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the backoffice sections/applications collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<SectionCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the components collection builder.
|
||||||
|
/// </summary>
|
||||||
|
public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the backoffice dashboards collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<DashboardCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cache refreshers collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<CacheRefresherCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the package actions collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<PackageActionCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data editor collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<DataEditorCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data value reference factory collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<DataValueReferenceFactoryCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the property value converters collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the url segment providers collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<UrlSegmentProviderCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the validators collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the manifest filter collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<ManifestFilterCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the content finders collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<MediaUrlGeneratorCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the backoffice OEmbed Providers collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<EmbedProvidersCollectionBuilder>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the back office searchable tree collection builder
|
||||||
|
/// </summary>
|
||||||
|
public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<SearchableTreeCollectionBuilder>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Umbraco.Core.Composing;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="IUmbracoBuilder"/>
|
||||||
|
/// </summary>
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds Umbraco composers for plugins
|
||||||
|
/// </summary>
|
||||||
|
public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
// TODO: Should have a better name
|
||||||
|
|
||||||
|
IEnumerable<Type> composerTypes = builder.TypeLoader.GetTypes<IComposer>();
|
||||||
|
IEnumerable<Attribute> enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute));
|
||||||
|
new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger<Composers>()).Compose();
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Core.Configuration.Models;
|
||||||
|
using Umbraco.Core.Configuration.Models.Validation;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="IUmbracoBuilder"/>
|
||||||
|
/// </summary>
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Add Umbraco configuration services and options
|
||||||
|
/// </summary>
|
||||||
|
public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
// Register configuration validators.
|
||||||
|
builder.Services.AddSingleton<IValidateOptions<ContentSettings>, ContentSettingsValidator>();
|
||||||
|
builder.Services.AddSingleton<IValidateOptions<GlobalSettings>, GlobalSettingsValidator>();
|
||||||
|
builder.Services.AddSingleton<IValidateOptions<HealthChecksSettings>, HealthChecksSettingsValidator>();
|
||||||
|
builder.Services.AddSingleton<IValidateOptions<RequestHandlerSettings>, RequestHandlerSettingsValidator>();
|
||||||
|
|
||||||
|
// Register configuration sections.
|
||||||
|
builder.Services.Configure<ActiveDirectorySettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigActiveDirectory));
|
||||||
|
builder.Services.Configure<ConnectionStrings>(builder.Config.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true);
|
||||||
|
builder.Services.Configure<ContentSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigContent));
|
||||||
|
builder.Services.Configure<CoreDebugSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigCoreDebug));
|
||||||
|
builder.Services.Configure<ExceptionFilterSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigExceptionFilter));
|
||||||
|
builder.Services.Configure<GlobalSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigGlobal));
|
||||||
|
builder.Services.Configure<HealthChecksSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigHealthChecks));
|
||||||
|
builder.Services.Configure<HostingSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigHosting));
|
||||||
|
builder.Services.Configure<ImagingSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigImaging));
|
||||||
|
builder.Services.Configure<IndexCreatorSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigExamine));
|
||||||
|
builder.Services.Configure<KeepAliveSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigKeepAlive));
|
||||||
|
builder.Services.Configure<LoggingSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigLogging));
|
||||||
|
builder.Services.Configure<MemberPasswordConfigurationSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigMemberPassword));
|
||||||
|
builder.Services.Configure<ModelsBuilderSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true);
|
||||||
|
builder.Services.Configure<NuCacheSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigNuCache));
|
||||||
|
builder.Services.Configure<RequestHandlerSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigRequestHandler));
|
||||||
|
builder.Services.Configure<RuntimeSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntime));
|
||||||
|
builder.Services.Configure<SecuritySettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigSecurity));
|
||||||
|
builder.Services.Configure<TourSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigTours));
|
||||||
|
builder.Services.Configure<TypeFinderSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigTypeFinder));
|
||||||
|
builder.Services.Configure<UserPasswordConfigurationSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigUserPassword));
|
||||||
|
builder.Services.Configure<WebRoutingSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigWebRouting));
|
||||||
|
builder.Services.Configure<UmbracoPluginSettings>(builder.Config.GetSection(Core.Constants.Configuration.ConfigPlugins));
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// See LICENSE for more details.
|
// See LICENSE for more details.
|
||||||
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
|
|
||||||
namespace Umbraco.Core.DependencyInjection
|
namespace Umbraco.Core.DependencyInjection
|
||||||
@@ -23,7 +24,15 @@ namespace Umbraco.Core.DependencyInjection
|
|||||||
where TNotification : INotification
|
where TNotification : INotification
|
||||||
{
|
{
|
||||||
// Register the handler as transient. This ensures that anything can be injected into it.
|
// Register the handler as transient. This ensures that anything can be injected into it.
|
||||||
builder.Services.AddTransient(typeof(INotificationHandler<TNotification>), typeof(TNotificationHandler));
|
var descriptor = new ServiceDescriptor(typeof(INotificationHandler<TNotification>), typeof(TNotificationHandler), ServiceLifetime.Transient);
|
||||||
|
|
||||||
|
// TODO: Waiting on feedback here https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 about whether
|
||||||
|
// we perform this duplicate check or not.
|
||||||
|
if (!builder.Services.Contains(descriptor))
|
||||||
|
{
|
||||||
|
builder.Services.Add(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,28 +3,65 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Core.Cache;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
|
using Umbraco.Core.Configuration;
|
||||||
|
using Umbraco.Core.Configuration.Grid;
|
||||||
|
using Umbraco.Core.Configuration.Models;
|
||||||
|
using Umbraco.Core.Diagnostics;
|
||||||
|
using Umbraco.Core.Dictionary;
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
|
using Umbraco.Core.Hosting;
|
||||||
|
using Umbraco.Core.IO;
|
||||||
|
using Umbraco.Core.Logging;
|
||||||
|
using Umbraco.Core.Mail;
|
||||||
|
using Umbraco.Core.Manifest;
|
||||||
|
using Umbraco.Core.Models.PublishedContent;
|
||||||
|
using Umbraco.Core.PropertyEditors;
|
||||||
|
using Umbraco.Core.Runtime;
|
||||||
|
using Umbraco.Core.Security;
|
||||||
|
using Umbraco.Core.Services;
|
||||||
|
using Umbraco.Core.Sync;
|
||||||
|
using Umbraco.Web;
|
||||||
|
using Umbraco.Web.Cache;
|
||||||
|
using Umbraco.Web.Editors;
|
||||||
|
using Umbraco.Web.Features;
|
||||||
|
using Umbraco.Web.Install;
|
||||||
|
using Umbraco.Web.Models.PublishedContent;
|
||||||
|
using Umbraco.Web.Routing;
|
||||||
|
using Umbraco.Web.Services;
|
||||||
|
using Umbraco.Web.Templates;
|
||||||
|
|
||||||
namespace Umbraco.Core.DependencyInjection
|
namespace Umbraco.Core.DependencyInjection
|
||||||
{
|
{
|
||||||
public class UmbracoBuilder : IUmbracoBuilder
|
public class UmbracoBuilder : IUmbracoBuilder
|
||||||
{
|
{
|
||||||
public IServiceCollection Services { get; }
|
|
||||||
public IConfiguration Config { get; }
|
|
||||||
public TypeLoader TypeLoader { get; }
|
|
||||||
public ILoggerFactory BuilderLoggerFactory { get; }
|
|
||||||
|
|
||||||
private readonly Dictionary<Type, ICollectionBuilder> _builders = new Dictionary<Type, ICollectionBuilder>();
|
private readonly Dictionary<Type, ICollectionBuilder> _builders = new Dictionary<Type, ICollectionBuilder>();
|
||||||
|
|
||||||
|
public IServiceCollection Services { get; }
|
||||||
|
|
||||||
|
public IConfiguration Config { get; }
|
||||||
|
|
||||||
|
public TypeLoader TypeLoader { get; }
|
||||||
|
|
||||||
|
public ILoggerFactory BuilderLoggerFactory { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UmbracoBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader)
|
public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader)
|
||||||
: this(services, config, typeLoader, NullLoggerFactory.Instance)
|
: this(services, config, typeLoader, NullLoggerFactory.Instance)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UmbracoBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader, ILoggerFactory loggerFactory)
|
public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
Services = services;
|
Services = services;
|
||||||
@@ -43,10 +80,12 @@ namespace Umbraco.Core.DependencyInjection
|
|||||||
public TBuilder WithCollectionBuilder<TBuilder>()
|
public TBuilder WithCollectionBuilder<TBuilder>()
|
||||||
where TBuilder : ICollectionBuilder, new()
|
where TBuilder : ICollectionBuilder, new()
|
||||||
{
|
{
|
||||||
var typeOfBuilder = typeof(TBuilder);
|
Type typeOfBuilder = typeof(TBuilder);
|
||||||
|
|
||||||
if (_builders.TryGetValue(typeOfBuilder, out var o))
|
if (_builders.TryGetValue(typeOfBuilder, out ICollectionBuilder o))
|
||||||
|
{
|
||||||
return (TBuilder)o;
|
return (TBuilder)o;
|
||||||
|
}
|
||||||
|
|
||||||
var builder = new TBuilder();
|
var builder = new TBuilder();
|
||||||
_builders[typeOfBuilder] = builder;
|
_builders[typeOfBuilder] = builder;
|
||||||
@@ -55,8 +94,10 @@ namespace Umbraco.Core.DependencyInjection
|
|||||||
|
|
||||||
public void Build()
|
public void Build()
|
||||||
{
|
{
|
||||||
foreach (var builder in _builders.Values)
|
foreach (ICollectionBuilder builder in _builders.Values)
|
||||||
|
{
|
||||||
builder.RegisterWith(Services);
|
builder.RegisterWith(Services);
|
||||||
|
}
|
||||||
|
|
||||||
_builders.Clear();
|
_builders.Clear();
|
||||||
}
|
}
|
||||||
@@ -66,6 +107,115 @@ namespace Umbraco.Core.DependencyInjection
|
|||||||
// Register as singleton to allow injection everywhere.
|
// Register as singleton to allow injection everywhere.
|
||||||
Services.AddSingleton<ServiceFactory>(p => p.GetService);
|
Services.AddSingleton<ServiceFactory>(p => p.GetService);
|
||||||
Services.AddSingleton<IEventAggregator, EventAggregator>();
|
Services.AddSingleton<IEventAggregator, EventAggregator>();
|
||||||
|
|
||||||
|
Services.AddLazySupport();
|
||||||
|
|
||||||
|
// Adds no-op registrations as many core services require these dependencies but these
|
||||||
|
// dependencies cannot be fulfilled in the Core project
|
||||||
|
Services.AddUnique<IMarchal, NoopMarchal>();
|
||||||
|
Services.AddUnique<IProfiler, NoopProfiler>();
|
||||||
|
Services.AddUnique<IApplicationShutdownRegistry, NoopApplicationShutdownRegistry>();
|
||||||
|
Services.AddUnique<IUmbracoApplicationLifetimeManager, NoopUmbracoApplicationLifetimeManager>();
|
||||||
|
|
||||||
|
Services.AddUnique<IMainDom, MainDom>();
|
||||||
|
Services.AddUnique<IMainDomLock, MainDomSemaphoreLock>();
|
||||||
|
|
||||||
|
Services.AddUnique<IIOHelper>(factory =>
|
||||||
|
{
|
||||||
|
IHostingEnvironment hostingEnvironment = factory.GetRequiredService<IHostingEnvironment>();
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
|
return new IOHelperLinux(hostingEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
|
{
|
||||||
|
return new IOHelperOSX(hostingEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IOHelperWindows(hostingEnvironment);
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.AddUnique(factory => factory.GetRequiredService<AppCaches>().RuntimeCache);
|
||||||
|
Services.AddUnique(factory => factory.GetRequiredService<AppCaches>().RequestCache);
|
||||||
|
Services.AddUnique<IProfilingLogger, ProfilingLogger>();
|
||||||
|
Services.AddUnique<IUmbracoVersion, UmbracoVersion>();
|
||||||
|
|
||||||
|
this.AddAllCoreCollectionBuilders();
|
||||||
|
this.AddNotificationHandler<UmbracoApplicationStarting, EssentialDirectoryCreator>();
|
||||||
|
|
||||||
|
Services.AddSingleton<ManifestWatcher>();
|
||||||
|
this.AddNotificationHandler<UmbracoApplicationStarting, AppPluginsManifestWatcherNotificationHandler>();
|
||||||
|
|
||||||
|
Services.AddUnique<InstallStatusTracker>();
|
||||||
|
|
||||||
|
// by default, register a noop factory
|
||||||
|
Services.AddUnique<IPublishedModelFactory, NoopPublishedModelFactory>();
|
||||||
|
|
||||||
|
Services.AddUnique<ICultureDictionaryFactory, DefaultCultureDictionaryFactory>();
|
||||||
|
Services.AddSingleton(f => f.GetRequiredService<ICultureDictionaryFactory>().CreateDictionary());
|
||||||
|
|
||||||
|
Services.AddUnique<UriUtility>();
|
||||||
|
|
||||||
|
Services.AddUnique<IDashboardService, DashboardService>();
|
||||||
|
|
||||||
|
// will be injected in controllers when needed to invoke rest endpoints on Our
|
||||||
|
Services.AddUnique<IInstallationService, InstallationService>();
|
||||||
|
Services.AddUnique<IUpgradeService, UpgradeService>();
|
||||||
|
|
||||||
|
// Grid config is not a real config file as we know them
|
||||||
|
Services.AddUnique<IGridConfig, GridConfig>();
|
||||||
|
|
||||||
|
Services.AddUnique<IPublishedUrlProvider, UrlProvider>();
|
||||||
|
Services.AddUnique<ISiteDomainHelper, SiteDomainHelper>();
|
||||||
|
|
||||||
|
Services.AddUnique<HtmlLocalLinkParser>();
|
||||||
|
Services.AddUnique<HtmlImageSourceParser>();
|
||||||
|
Services.AddUnique<HtmlUrlParser>();
|
||||||
|
|
||||||
|
// register properties fallback
|
||||||
|
Services.AddUnique<IPublishedValueFallback, PublishedValueFallback>();
|
||||||
|
|
||||||
|
Services.AddUnique<UmbracoFeatures>();
|
||||||
|
|
||||||
|
// register published router
|
||||||
|
Services.AddUnique<IPublishedRouter, PublishedRouter>();
|
||||||
|
|
||||||
|
Services.AddUnique<IEventMessagesFactory, DefaultEventMessagesFactory>();
|
||||||
|
Services.AddUnique<IEventMessagesAccessor, HybridEventMessagesAccessor>();
|
||||||
|
Services.AddUnique<ITreeService, TreeService>();
|
||||||
|
Services.AddUnique<ISectionService, SectionService>();
|
||||||
|
|
||||||
|
Services.AddUnique<ISmsSender, NotImplementedSmsSender>();
|
||||||
|
Services.AddUnique<IEmailSender, NotImplementedEmailSender>();
|
||||||
|
|
||||||
|
// register distributed cache
|
||||||
|
Services.AddUnique(f => new DistributedCache(f.GetRequiredService<IServerMessenger>(), f.GetRequiredService<CacheRefresherCollection>()));
|
||||||
|
|
||||||
|
// register the http context and umbraco context accessors
|
||||||
|
// we *should* use the HttpContextUmbracoContextAccessor, however there are cases when
|
||||||
|
// we have no http context, eg when booting Umbraco or in background threads, so instead
|
||||||
|
// let's use an hybrid accessor that can fall back to a ThreadStatic context.
|
||||||
|
Services.AddUnique<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
|
||||||
|
|
||||||
|
Services.AddUnique<LegacyPasswordSecurity>();
|
||||||
|
Services.AddUnique<UserEditorAuthorizationHelper>();
|
||||||
|
Services.AddUnique<ContentPermissions>();
|
||||||
|
Services.AddUnique<MediaPermissions>();
|
||||||
|
|
||||||
|
Services.AddUnique<PropertyEditorCollection>();
|
||||||
|
Services.AddUnique<ParameterEditorCollection>();
|
||||||
|
|
||||||
|
// register a server registrar, by default it's the db registrar
|
||||||
|
Services.AddUnique<IServerRoleAccessor>(f =>
|
||||||
|
{
|
||||||
|
GlobalSettings globalSettings = f.GetRequiredService<IOptions<GlobalSettings>>().Value;
|
||||||
|
var singleServer = globalSettings.DisableElectionForSingleServer;
|
||||||
|
return singleServer
|
||||||
|
? (IServerRoleAccessor)new SingleServerRoleAccessor()
|
||||||
|
: new ElectedServerRoleAccessor(f.GetRequiredService<IServerRegistrationService>());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/Umbraco.Core/Diagnostics/NoopMarchal.cs
Normal file
9
src/Umbraco.Core/Diagnostics/NoopMarchal.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.Diagnostics
|
||||||
|
{
|
||||||
|
internal class NoopMarchal : IMarchal
|
||||||
|
{
|
||||||
|
public IntPtr GetExceptionPointers() => IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using Microsoft.Extensions.Options;
|
|||||||
using Umbraco.Core;
|
using Umbraco.Core;
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
using Umbraco.Core.HealthCheck;
|
using Umbraco.Core.HealthCheck;
|
||||||
|
using Umbraco.Core.Mail;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
using Umbraco.Core.Services;
|
using Umbraco.Core.Services;
|
||||||
using Umbraco.Infrastructure.HealthCheck;
|
using Umbraco.Infrastructure.HealthCheck;
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Umbraco.Net
|
namespace Umbraco.Core.Hosting
|
||||||
{
|
{
|
||||||
// TODO: This shouldn't be in this namespace?
|
|
||||||
public interface IUmbracoApplicationLifetime
|
public interface IUmbracoApplicationLifetime
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A value indicating whether the application is restarting after the current request.
|
/// A value indicating whether the application is restarting after the current request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsRestarting { get; }
|
bool IsRestarting { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Terminates the current application. The application restarts the next time a request is received for it.
|
/// Terminates the current application. The application restarts the next time a request is received for it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Restart();
|
void Restart();
|
||||||
|
|
||||||
|
// TODO: Should be killed and replaced with UmbracoApplicationStarting notifications
|
||||||
event EventHandler ApplicationInit;
|
event EventHandler ApplicationInit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface IUmbracoApplicationLifetimeManager
|
|
||||||
{
|
|
||||||
void InvokeApplicationInit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Umbraco.Core.Hosting
|
||||||
|
{
|
||||||
|
// TODO: Should be killed and replaced with UmbracoApplicationStarting notifications
|
||||||
|
public interface IUmbracoApplicationLifetimeManager
|
||||||
|
{
|
||||||
|
void InvokeApplicationInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Umbraco.Core.Hosting
|
||||||
|
{
|
||||||
|
internal class NoopApplicationShutdownRegistry : IApplicationShutdownRegistry
|
||||||
|
{
|
||||||
|
public void RegisterObject(IRegisteredObject registeredObject) { }
|
||||||
|
public void UnregisterObject(IRegisteredObject registeredObject) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Umbraco.Core.Hosting
|
||||||
|
{
|
||||||
|
internal class NoopUmbracoApplicationLifetimeManager : IUmbracoApplicationLifetimeManager
|
||||||
|
{
|
||||||
|
public void InvokeApplicationInit() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Umbraco.Core.Hosting;
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
|
||||||
namespace Umbraco.Core.IO
|
namespace Umbraco.Core.IO
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.Security;
|
using Umbraco.Core.Security;
|
||||||
using Umbraco.Core.Services;
|
using Umbraco.Core.Services;
|
||||||
using Umbraco.Net;
|
|
||||||
using Umbraco.Web.Install.Models;
|
using Umbraco.Web.Install.Models;
|
||||||
|
|
||||||
namespace Umbraco.Web.Install.InstallSteps
|
namespace Umbraco.Web.Install.InstallSteps
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Umbraco.Core.Logging
|
namespace Umbraco.Core.Logging
|
||||||
{
|
{
|
||||||
public class VoidProfiler : IProfiler
|
public class NoopProfiler : IProfiler
|
||||||
{
|
{
|
||||||
private readonly VoidDisposable _disposable = new VoidDisposable();
|
private readonly VoidDisposable _disposable = new VoidDisposable();
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
|
|
||||||
namespace Umbraco.Core
|
namespace Umbraco.Core.Mail
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simple abstraction to send an email message
|
/// Simple abstraction to send an email message
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Umbraco.Core
|
namespace Umbraco.Core.Mail
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Service to send an SMS
|
/// Service to send an SMS
|
||||||
12
src/Umbraco.Core/Mail/NotImplementedEmailSender.cs
Normal file
12
src/Umbraco.Core/Mail/NotImplementedEmailSender.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Umbraco.Core.Models;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.Mail
|
||||||
|
{
|
||||||
|
internal class NotImplementedEmailSender : IEmailSender
|
||||||
|
{
|
||||||
|
public Task SendAsync(EmailMessage message)
|
||||||
|
=> throw new NotImplementedException("To send an Email ensure IEmailSender is implemented with a custom implementation");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Umbraco.Core
|
namespace Umbraco.Core.Mail
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="ISmsSender"/> that throws <see cref="NotImplementedException"/>
|
/// An <see cref="ISmsSender"/> that throws <see cref="NotImplementedException"/>
|
||||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Umbraco.Net;
|
using Umbraco.Core.Hosting;
|
||||||
|
|
||||||
namespace Umbraco.Core.Manifest
|
namespace Umbraco.Core.Manifest
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
using Umbraco.Core.Manifest;
|
using Umbraco.Core.Manifest;
|
||||||
|
|
||||||
namespace Umbraco.Core.PropertyEditors
|
namespace Umbraco.Core.PropertyEditors
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public class PropertyEditorCollection : BuilderCollectionBase<IDataEditor>
|
public class PropertyEditorCollection : BuilderCollectionBase<IDataEditor>
|
||||||
{
|
{
|
||||||
public PropertyEditorCollection(DataEditorCollection dataEditors, IManifestParser manifestParser)
|
public PropertyEditorCollection(DataEditorCollection dataEditors, IManifestParser manifestParser)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Umbraco.Core.Models.PublishedContent;
|
using Umbraco.Core.Models.PublishedContent;
|
||||||
using Umbraco.Core.Strings;
|
using Umbraco.Core.Strings;
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
|||||||
/// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used.
|
/// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultPropertyValueConverter]
|
[DefaultPropertyValueConverter]
|
||||||
public class TinyMceValueConverter : PropertyValueConverterBase
|
public class SimpleTinyMceValueConverter : PropertyValueConverterBase
|
||||||
{
|
{
|
||||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||||
=> propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce;
|
=> propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce;
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using Umbraco.Core.Models.PublishedContent;
|
|
||||||
|
|
||||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
|
||||||
{
|
|
||||||
[DefaultPropertyValueConverter]
|
|
||||||
public class TextStringValueConverter : PropertyValueConverterBase
|
|
||||||
{
|
|
||||||
private static readonly string[] PropertyTypeAliases =
|
|
||||||
{
|
|
||||||
Constants.PropertyEditors.Aliases.TextBox,
|
|
||||||
Constants.PropertyEditors.Aliases.TextArea
|
|
||||||
};
|
|
||||||
|
|
||||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
|
||||||
=> PropertyTypeAliases.Contains(propertyType.EditorAlias);
|
|
||||||
|
|
||||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
|
||||||
=> typeof (string);
|
|
||||||
|
|
||||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
|
||||||
=> PropertyCacheLevel.Element;
|
|
||||||
|
|
||||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
|
||||||
{
|
|
||||||
// in xml a string is: string
|
|
||||||
// in the database a string is: string
|
|
||||||
// default value is: null
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
|
||||||
{
|
|
||||||
// source should come from ConvertSource and be a string (or null) already
|
|
||||||
return inter ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
|
||||||
{
|
|
||||||
// source should come from ConvertSource and be a string (or null) already
|
|
||||||
return inter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,12 +2,11 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
using Umbraco.Core.Hosting;
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.Manifest;
|
using Umbraco.Core.Manifest;
|
||||||
|
|
||||||
namespace Umbraco.Infrastructure.Runtime
|
namespace Umbraco.Core.Runtime
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts monitoring AppPlugins directory during debug runs, to restart site when a plugin manifest changes.
|
/// Starts monitoring AppPlugins directory during debug runs, to restart site when a plugin manifest changes.
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
using Umbraco.Core.Hosting;
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.IO;
|
using Umbraco.Core.IO;
|
||||||
|
|
||||||
namespace Umbraco.Infrastructure.Runtime
|
namespace Umbraco.Core.Runtime
|
||||||
{
|
{
|
||||||
public class EssentialDirectoryCreator : INotificationHandler<UmbracoApplicationStarting>
|
public class EssentialDirectoryCreator : INotificationHandler<UmbracoApplicationStarting>
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Runtime
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
//WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread
|
// WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread
|
||||||
public Task ListenAsync() => _signal.WaitOneAsync();
|
public Task ListenAsync() => _signal.WaitOneAsync();
|
||||||
|
|
||||||
public Task<bool> AcquireLockAsync(int millisecondsTimeout)
|
public Task<bool> AcquireLockAsync(int millisecondsTimeout)
|
||||||
@@ -44,7 +44,7 @@ namespace Umbraco.Core.Runtime
|
|||||||
// if more than 1 instance reach that point, one will get the lock
|
// if more than 1 instance reach that point, one will get the lock
|
||||||
// and the other one will timeout, which is accepted
|
// and the other one will timeout, which is accepted
|
||||||
|
|
||||||
//This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset.
|
// This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_lockRelease = _systemLock.Lock(millisecondsTimeout);
|
_lockRelease = _systemLock.Lock(millisecondsTimeout);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
using Umbraco.Core.Sync;
|
using Umbraco.Core.Sync;
|
||||||
@@ -11,9 +11,8 @@ namespace Umbraco.Core.Services
|
|||||||
/// Touches a server to mark it as active; deactivate stale servers.
|
/// Touches a server to mark it as active; deactivate stale servers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serverAddress">The server URL.</param>
|
/// <param name="serverAddress">The server URL.</param>
|
||||||
/// <param name="serverIdentity">The server unique identity.</param>
|
|
||||||
/// <param name="staleTimeout">The time after which a server is considered stale.</param>
|
/// <param name="staleTimeout">The time after which a server is considered stale.</param>
|
||||||
void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout);
|
void TouchServer(string serverAddress, TimeSpan staleTimeout);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deactivates a server.
|
/// Deactivates a server.
|
||||||
@@ -38,11 +37,6 @@ namespace Umbraco.Core.Services
|
|||||||
/// from the database.</remarks>
|
/// from the database.</remarks>
|
||||||
IEnumerable<IServerRegistration> GetActiveServers(bool refresh = false);
|
IEnumerable<IServerRegistration> GetActiveServers(bool refresh = false);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current server identity.
|
|
||||||
/// </summary>
|
|
||||||
string CurrentServerIdentity { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the role of the current server.
|
/// Gets the role of the current server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
using Umbraco.Core.Persistence.Repositories;
|
using Umbraco.Core.Persistence.Repositories;
|
||||||
|
|
||||||
namespace Umbraco.Core.Services.Implement
|
namespace Umbraco.Core.Services
|
||||||
{
|
{
|
||||||
public class InstallationService : IInstallationService
|
public class InstallationService : IInstallationService
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Semver;
|
using Semver;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
using Umbraco.Core.Persistence.Repositories;
|
using Umbraco.Core.Persistence.Repositories;
|
||||||
using Umbraco.Core.Services;
|
|
||||||
|
|
||||||
namespace Umbraco.Core
|
namespace Umbraco.Core.Services
|
||||||
{
|
{
|
||||||
public class UpgradeService : IUpgradeService
|
public class UpgradeService : IUpgradeService
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Umbraco.Core.Sync
|
namespace Umbraco.Core.Sync
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds a list of callbacks associated with implementations of <see cref="IBatchedDatabaseServerMessenger"/>.
|
/// Holds a list of callbacks associated with implementations of <see cref="IServerMessenger"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DatabaseServerMessengerCallbacks
|
public class DatabaseServerMessengerCallbacks
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Umbraco.Core.Services;
|
|
||||||
|
|
||||||
namespace Umbraco.Core.Sync
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A registrar that stores registered server nodes in the database.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is the default registrar which determines a server's role by using a master election process.
|
|
||||||
/// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase.
|
|
||||||
/// </remarks>
|
|
||||||
public sealed class DatabaseServerRegistrar : IServerRegistrar
|
|
||||||
{
|
|
||||||
private readonly Lazy<IServerRegistrationService> _registrationService;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DatabaseServerRegistrar"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="registrationService">The registration service.</param>
|
|
||||||
/// <param name="options">Some options.</param>
|
|
||||||
public DatabaseServerRegistrar(Lazy<IServerRegistrationService> registrationService)
|
|
||||||
{
|
|
||||||
_registrationService = registrationService ?? throw new ArgumentNullException(nameof(registrationService));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the registered servers.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<IServerAddress> Registrations => _registrationService.Value.GetActiveServers();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the role of the current server in the application environment.
|
|
||||||
/// </summary>
|
|
||||||
public ServerRole GetCurrentServerRole()
|
|
||||||
{
|
|
||||||
var service = _registrationService.Value;
|
|
||||||
return service.GetCurrentServerRole();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs
Normal file
29
src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using Umbraco.Core.Services;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.Sync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current server's <see cref="ServerRole"/> based on active servers registered with <see cref="IServerRegistrationService"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is the default service which determines a server's role by using a master election process.
|
||||||
|
/// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase.
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class ElectedServerRoleAccessor : IServerRoleAccessor
|
||||||
|
{
|
||||||
|
private readonly IServerRegistrationService _registrationService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ElectedServerRoleAccessor"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="registrationService">The registration service.</param>
|
||||||
|
/// <param name="options">Some options.</param>
|
||||||
|
public ElectedServerRoleAccessor(IServerRegistrationService registrationService) => _registrationService = registrationService ?? throw new ArgumentNullException(nameof(registrationService));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the role of the current server in the application environment.
|
||||||
|
/// </summary>
|
||||||
|
public ServerRole CurrentServerRole => _registrationService.GetCurrentServerRole();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Umbraco.Core.Sync
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An <see cref="IServerMessenger"/> implementation that works by storing messages in the database.
|
|
||||||
/// </summary>
|
|
||||||
public interface IBatchedDatabaseServerMessenger : IDatabaseServerMessenger
|
|
||||||
{
|
|
||||||
void FlushBatch();
|
|
||||||
DatabaseServerMessengerCallbacks Callbacks { get; }
|
|
||||||
void Startup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Umbraco.Core.Sync
|
|
||||||
{
|
|
||||||
public interface IDatabaseServerMessenger: IServerMessenger
|
|
||||||
{
|
|
||||||
void Sync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,30 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Umbraco.Core.Cache;
|
using Umbraco.Core.Cache;
|
||||||
|
|
||||||
namespace Umbraco.Core.Sync
|
namespace Umbraco.Core.Sync
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcasts distributed cache notifications to all servers of a load balanced environment.
|
/// Transmits distributed cache notifications for all servers of a load balanced environment.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Also ensures that the notification is processed on the local environment.</remarks>
|
/// <remarks>Also ensures that the notification is processed on the local environment.</remarks>
|
||||||
public interface IServerMessenger
|
public interface IServerMessenger
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called to synchronize a server with queued notifications
|
||||||
|
/// </summary>
|
||||||
|
void Sync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called to send/commit the queued messages created with the Perform methods
|
||||||
|
/// </summary>
|
||||||
|
void SendMessages();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies the distributed cache, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies the distributed cache, for a specified <see cref="ICacheRefresher"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="payload">The notification content.</param>
|
/// <param name="payload">The notification content.</param>
|
||||||
void PerformRefresh<TPayload>(ICacheRefresher refresher, TPayload[] payload);
|
void QueueRefresh<TPayload>(ICacheRefresher refresher, TPayload[] payload);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies the distributed cache of specified item invalidation, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies the distributed cache of specified item invalidation, for a specified <see cref="ICacheRefresher"/>.
|
||||||
@@ -24,7 +33,7 @@ namespace Umbraco.Core.Sync
|
|||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="getNumericId">A function returning the unique identifier of items.</param>
|
/// <param name="getNumericId">A function returning the unique identifier of items.</param>
|
||||||
/// <param name="instances">The invalidated items.</param>
|
/// <param name="instances">The invalidated items.</param>
|
||||||
void PerformRefresh<T>(ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances);
|
void QueueRefresh<T>(ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies the distributed cache of specified item invalidation, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies the distributed cache of specified item invalidation, for a specified <see cref="ICacheRefresher"/>.
|
||||||
@@ -33,7 +42,7 @@ namespace Umbraco.Core.Sync
|
|||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="getGuidId">A function returning the unique identifier of items.</param>
|
/// <param name="getGuidId">A function returning the unique identifier of items.</param>
|
||||||
/// <param name="instances">The invalidated items.</param>
|
/// <param name="instances">The invalidated items.</param>
|
||||||
void PerformRefresh<T>(ICacheRefresher refresher, Func<T, Guid> getGuidId, params T[] instances);
|
void QueueRefresh<T>(ICacheRefresher refresher, Func<T, Guid> getGuidId, params T[] instances);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies all servers of specified items removal, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies all servers of specified items removal, for a specified <see cref="ICacheRefresher"/>.
|
||||||
@@ -42,33 +51,33 @@ namespace Umbraco.Core.Sync
|
|||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="getNumericId">A function returning the unique identifier of items.</param>
|
/// <param name="getNumericId">A function returning the unique identifier of items.</param>
|
||||||
/// <param name="instances">The removed items.</param>
|
/// <param name="instances">The removed items.</param>
|
||||||
void PerformRemove<T>(ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances);
|
void QueueRemove<T>(ICacheRefresher refresher, Func<T, int> getNumericId, params T[] instances);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies all servers of specified items removal, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies all servers of specified items removal, for a specified <see cref="ICacheRefresher"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="numericIds">The unique identifiers of the removed items.</param>
|
/// <param name="numericIds">The unique identifiers of the removed items.</param>
|
||||||
void PerformRemove(ICacheRefresher refresher, params int[] numericIds);
|
void QueueRemove(ICacheRefresher refresher, params int[] numericIds);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies all servers of specified items invalidation, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies all servers of specified items invalidation, for a specified <see cref="ICacheRefresher"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="numericIds">The unique identifiers of the invalidated items.</param>
|
/// <param name="numericIds">The unique identifiers of the invalidated items.</param>
|
||||||
void PerformRefresh(ICacheRefresher refresher, params int[] numericIds);
|
void QueueRefresh(ICacheRefresher refresher, params int[] numericIds);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies all servers of specified items invalidation, for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies all servers of specified items invalidation, for a specified <see cref="ICacheRefresher"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
/// <param name="guidIds">The unique identifiers of the invalidated items.</param>
|
/// <param name="guidIds">The unique identifiers of the invalidated items.</param>
|
||||||
void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds);
|
void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies all servers of a global invalidation for a specified <see cref="ICacheRefresher"/>.
|
/// Notifies all servers of a global invalidation for a specified <see cref="ICacheRefresher"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="refresher">The ICacheRefresher.</param>
|
/// <param name="refresher">The ICacheRefresher.</param>
|
||||||
void PerformRefreshAll(ICacheRefresher refresher);
|
void QueueRefreshAll(ICacheRefresher refresher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Umbraco.Core.Sync
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides server registrations to the distributed cache.
|
|
||||||
/// </summary>
|
|
||||||
public interface IServerRegistrar
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the server registrations.
|
|
||||||
/// </summary>
|
|
||||||
IEnumerable<IServerAddress> Registrations { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the role of the current server in the application environment.
|
|
||||||
/// </summary>
|
|
||||||
ServerRole GetCurrentServerRole();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
src/Umbraco.Core/Sync/IServerRoleAccessor.cs
Normal file
15
src/Umbraco.Core/Sync/IServerRoleAccessor.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.Sync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current server's <see cref="ServerRole"/>
|
||||||
|
/// </summary>
|
||||||
|
public interface IServerRoleAccessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the role of the current server in the application environment.
|
||||||
|
/// </summary>
|
||||||
|
ServerRole CurrentServerRole { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Umbraco.Web;
|
|
||||||
|
|
||||||
namespace Umbraco.Core.Sync
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Can be used when Umbraco is definitely not operating in a Load Balanced scenario to micro-optimize some startup performance
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the <see cref="ServerRole"/>
|
|
||||||
/// which by default is done with master election by a database query. The master election process doesn't occur until just after startup
|
|
||||||
/// so this micro optimization doesn't really affect the primary startup phase.
|
|
||||||
/// </remarks>
|
|
||||||
public class SingleServerRegistrar : IServerRegistrar
|
|
||||||
{
|
|
||||||
private readonly IRequestAccessor _requestAccessor;
|
|
||||||
private readonly Lazy<IServerAddress[]> _registrations;
|
|
||||||
|
|
||||||
public IEnumerable<IServerAddress> Registrations => _registrations.Value;
|
|
||||||
|
|
||||||
public SingleServerRegistrar(IRequestAccessor requestAccessor)
|
|
||||||
{
|
|
||||||
_requestAccessor = requestAccessor;
|
|
||||||
_registrations = new Lazy<IServerAddress[]>(() => new IServerAddress[] { new ServerAddressImpl(_requestAccessor.GetApplicationUrl().ToString()) });
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerRole GetCurrentServerRole()
|
|
||||||
{
|
|
||||||
return ServerRole.Single;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class ServerAddressImpl : IServerAddress
|
|
||||||
{
|
|
||||||
public ServerAddressImpl(string serverAddress)
|
|
||||||
{
|
|
||||||
ServerAddress = serverAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ServerAddress { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs
Normal file
19
src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Umbraco.Web;
|
||||||
|
|
||||||
|
namespace Umbraco.Core.Sync
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Can be used when Umbraco is definitely not operating in a Load Balanced scenario to micro-optimize some startup performance
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the <see cref="ServerRole"/>
|
||||||
|
/// which by default is done with master election by a database query. The master election process doesn't occur until just after startup
|
||||||
|
/// so this micro optimization doesn't really affect the primary startup phase.
|
||||||
|
/// </remarks>
|
||||||
|
public class SingleServerRoleAccessor : IServerRoleAccessor
|
||||||
|
{
|
||||||
|
public ServerRole CurrentServerRole => ServerRole.Single;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
using Umbraco.Web.Models.ContentEditing;
|
using Umbraco.Web.Models.ContentEditing;
|
||||||
|
|
||||||
namespace Umbraco.Web.Trees
|
namespace Umbraco.Core.Trees
|
||||||
{
|
{
|
||||||
public interface ISearchableTree : IDiscoverable
|
public interface ISearchableTree : IDiscoverable
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Umbraco.Web.Trees;
|
namespace Umbraco.Core.Trees
|
||||||
|
|
||||||
namespace Umbraco.Web.Search
|
|
||||||
{
|
{
|
||||||
public class SearchableApplicationTree
|
public class SearchableApplicationTree
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Umbraco.Core;
|
using Umbraco.Core;
|
||||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Composing;
|
|||||||
using Umbraco.Web.Services;
|
using Umbraco.Web.Services;
|
||||||
using Umbraco.Web.Trees;
|
using Umbraco.Web.Trees;
|
||||||
|
|
||||||
namespace Umbraco.Web.Search
|
namespace Umbraco.Core.Trees
|
||||||
{
|
{
|
||||||
public class SearchableTreeCollection : BuilderCollectionBase<ISearchableTree>
|
public class SearchableTreeCollection : BuilderCollectionBase<ISearchableTree>
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
using Umbraco.Web.Trees;
|
|
||||||
|
|
||||||
namespace Umbraco.Web.Search
|
namespace Umbraco.Core.Trees
|
||||||
{
|
{
|
||||||
public class SearchableTreeCollectionBuilder : LazyCollectionBuilderBase<SearchableTreeCollectionBuilder, SearchableTreeCollection, ISearchableTree>
|
public class SearchableTreeCollectionBuilder : LazyCollectionBuilderBase<SearchableTreeCollectionBuilder, SearchableTreeCollection, ISearchableTree>
|
||||||
{
|
{
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.8" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.8" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
||||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
|
||||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Umbraco.Core.Events;
|
||||||
|
using Umbraco.Core.Persistence;
|
||||||
|
using Umbraco.Core.Sync;
|
||||||
|
using Umbraco.Web;
|
||||||
|
using Umbraco.Web.Cache;
|
||||||
|
using Umbraco.Web.Routing;
|
||||||
|
|
||||||
|
namespace Umbraco.Infrastructure.Cache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that distributed cache events are setup and the <see cref="IServerMessenger"/> is initialized
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler<UmbracoApplicationStarting>
|
||||||
|
{
|
||||||
|
private readonly IServerMessenger _messenger;
|
||||||
|
private readonly IRequestAccessor _requestAccessor;
|
||||||
|
private readonly IUmbracoDatabaseFactory _databaseFactory;
|
||||||
|
private readonly IDistributedCacheBinder _distributedCacheBinder;
|
||||||
|
private readonly ILogger<DatabaseServerMessengerNotificationHandler> _logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DatabaseServerMessengerNotificationHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DatabaseServerMessengerNotificationHandler(
|
||||||
|
IServerMessenger serverMessenger,
|
||||||
|
IRequestAccessor requestAccessor,
|
||||||
|
IUmbracoDatabaseFactory databaseFactory,
|
||||||
|
IDistributedCacheBinder distributedCacheBinder,
|
||||||
|
ILogger<DatabaseServerMessengerNotificationHandler> logger)
|
||||||
|
{
|
||||||
|
_requestAccessor = requestAccessor;
|
||||||
|
_databaseFactory = databaseFactory;
|
||||||
|
_distributedCacheBinder = distributedCacheBinder;
|
||||||
|
_logger = logger;
|
||||||
|
_messenger = serverMessenger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services.
|
||||||
|
// The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL
|
||||||
|
// being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured).
|
||||||
|
// Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available
|
||||||
|
// for the hosted services to use when the HTTP request is not available.
|
||||||
|
_requestAccessor.RouteAttempt += EnsureApplicationUrlOnce;
|
||||||
|
_requestAccessor.EndRequest += EndRequest;
|
||||||
|
|
||||||
|
Startup();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Startup()
|
||||||
|
{
|
||||||
|
if (_databaseFactory.CanConnect == false)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_distributedCacheBinder.BindEvents();
|
||||||
|
|
||||||
|
// Sync on startup, this will run through the messenger's initialization sequence
|
||||||
|
_messenger?.Sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: I don't really know or think that the Application Url plays a role anymore with the DB dist cache,
|
||||||
|
// this might be really old stuff. I 'think' all this is doing is ensuring that the IRequestAccessor.GetApplicationUrl
|
||||||
|
// is definitely called during the first request. If that is still required, that logic doesn't belong here. That logic
|
||||||
|
// should be part of it's own service/middleware. There's also TODO notes within IRequestAccessor.GetApplicationUrl directly
|
||||||
|
// mentioning that the property doesn't belong on that service either. This should be investigated and resolved in a separate task.
|
||||||
|
private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest)
|
||||||
|
{
|
||||||
|
_requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce;
|
||||||
|
EnsureApplicationUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By retrieving the application URL within the context of a request (as we are here in responding
|
||||||
|
// to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for
|
||||||
|
// future requests that may not be within an HTTP request (e.g. from hosted services).
|
||||||
|
private void EnsureApplicationUrl() => _requestAccessor.GetApplicationUrl();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear the batch on end request
|
||||||
|
/// </summary>
|
||||||
|
private void EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.SendMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
|
|
||||||
namespace Umbraco.Web.Cache
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Installs listeners on service events in order to refresh our caches.
|
|
||||||
/// </summary>
|
|
||||||
[ComposeBefore(typeof(ICoreComposer))] // runs before every other IUmbracoCoreComponent!
|
|
||||||
public sealed class DistributedCacheBinderComposer : ComponentComposer<DistributedCacheBinderComponent>, ICoreComposer
|
|
||||||
{
|
|
||||||
public override void Compose(IUmbracoBuilder builder)
|
|
||||||
{
|
|
||||||
base.Compose(builder);
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IDistributedCacheBinder, DistributedCacheBinder>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
using Umbraco.Core.Services.Changes;
|
|
||||||
using Umbraco.Core.Sync;
|
|
||||||
using Umbraco.Web.Cache;
|
|
||||||
using Umbraco.Web.PublishedCache;
|
|
||||||
using Umbraco.Web.Routing;
|
|
||||||
using Umbraco.Web.Search;
|
|
||||||
|
|
||||||
namespace Umbraco.Web.Compose
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Ensures that servers are automatically registered in the database, when using the database server registrar.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>At the moment servers are automatically registered upon first request and then on every
|
|
||||||
/// request but not more than once per (configurable) period. This really is "for information & debug" purposes so
|
|
||||||
/// we can look at the table and see what servers are registered - but the info is not used anywhere.</para>
|
|
||||||
/// <para>Should we actually want to use this, we would need a better and more deterministic way of figuring
|
|
||||||
/// out the "server address" ie the address to which server-to-server requests should be sent - because it
|
|
||||||
/// probably is not the "current request address" - especially in multi-domains configurations.</para>
|
|
||||||
/// </remarks>
|
|
||||||
// during Initialize / Startup, we end up checking Examine, which needs to be initialized beforehand
|
|
||||||
// TODO: should not be a strong dependency on "examine" but on an "indexing component"
|
|
||||||
[ComposeAfter(typeof(ExamineComposer))]
|
|
||||||
|
|
||||||
public sealed class DatabaseServerRegistrarAndMessengerComposer : ComponentComposer<DatabaseServerRegistrarAndMessengerComponent>, ICoreComposer
|
|
||||||
{
|
|
||||||
public static DatabaseServerMessengerCallbacks GetCallbacks(IServiceProvider factory)
|
|
||||||
{
|
|
||||||
return new DatabaseServerMessengerCallbacks
|
|
||||||
{
|
|
||||||
//These callbacks will be executed if the server has not been synced
|
|
||||||
// (i.e. it is a new server or the lastsynced.txt file has been removed)
|
|
||||||
InitializingCallbacks = new Action[]
|
|
||||||
{
|
|
||||||
//rebuild the xml cache file if the server is not synced
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
var publishedSnapshotService = factory.GetRequiredService<IPublishedSnapshotService>();
|
|
||||||
|
|
||||||
// rebuild the published snapshot caches entirely, if the server is not synced
|
|
||||||
// this is equivalent to DistributedCache RefreshAll... but local only
|
|
||||||
// (we really should have a way to reuse RefreshAll... locally)
|
|
||||||
// note: refresh all content & media caches does refresh content types too
|
|
||||||
publishedSnapshotService.Notify(new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) });
|
|
||||||
publishedSnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _);
|
|
||||||
publishedSnapshotService.Notify(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _);
|
|
||||||
},
|
|
||||||
|
|
||||||
//rebuild indexes if the server is not synced
|
|
||||||
// NOTE: This will rebuild ALL indexes including the members, if developers want to target specific
|
|
||||||
// indexes then they can adjust this logic themselves.
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
var indexRebuilder = factory.GetRequiredService<BackgroundIndexRebuilder>();
|
|
||||||
indexRebuilder.RebuildIndexes(false, 5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Compose(IUmbracoBuilder builder)
|
|
||||||
{
|
|
||||||
base.Compose(builder);
|
|
||||||
|
|
||||||
builder.SetDatabaseServerMessengerCallbacks(GetCallbacks);
|
|
||||||
builder.SetServerMessenger<BatchedDatabaseServerMessenger>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class DatabaseServerRegistrarAndMessengerComponent : IComponent
|
|
||||||
{
|
|
||||||
private readonly IBatchedDatabaseServerMessenger _messenger;
|
|
||||||
private readonly IRequestAccessor _requestAccessor;
|
|
||||||
|
|
||||||
public DatabaseServerRegistrarAndMessengerComponent(
|
|
||||||
IServerMessenger serverMessenger,
|
|
||||||
IRequestAccessor requestAccessor)
|
|
||||||
{
|
|
||||||
_requestAccessor = requestAccessor;
|
|
||||||
_messenger = serverMessenger as IBatchedDatabaseServerMessenger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
// The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services.
|
|
||||||
// The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL
|
|
||||||
// being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured).
|
|
||||||
// Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available
|
|
||||||
// for the hosted services to use when the HTTP request is not available.
|
|
||||||
_requestAccessor.RouteAttempt += EnsureApplicationUrlOnce;
|
|
||||||
|
|
||||||
// Must come last, as it references some _variables
|
|
||||||
_messenger?.Startup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Terminate()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest)
|
|
||||||
{
|
|
||||||
_requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce;
|
|
||||||
EnsureApplicationUrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureApplicationUrl()
|
|
||||||
{
|
|
||||||
// By retrieving the application URL within the context of a request (as we are here in responding
|
|
||||||
// to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for
|
|
||||||
// future requests that may not be within an HTTP request (e.g. from hosted services).
|
|
||||||
_requestAccessor.GetApplicationUrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Umbraco.Core;
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
|
|
||||||
namespace Umbraco.Web.Compose
|
namespace Umbraco.Web.Compose
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
using Umbraco.Web.Install;
|
|
||||||
using Umbraco.Web.Install.InstallSteps;
|
|
||||||
using Umbraco.Web.Install.Models;
|
|
||||||
|
|
||||||
namespace Umbraco.Web.Composing.CompositionExtensions
|
|
||||||
{
|
|
||||||
public static class Installer
|
|
||||||
{
|
|
||||||
public static IUmbracoBuilder ComposeInstaller(this IUmbracoBuilder builder)
|
|
||||||
{
|
|
||||||
// register the installer steps
|
|
||||||
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,NewInstallStep>();
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,UpgradeStep>();
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,FilePermissionsStep>();
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,DatabaseConfigureStep>();
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,DatabaseInstallStep>();
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,DatabaseUpgradeStep>();
|
|
||||||
|
|
||||||
// TODO: Add these back once we have a compatible Starter kit
|
|
||||||
// composition.Services.AddScoped<InstallSetupStep,StarterKitDownloadStep>();
|
|
||||||
// composition.Services.AddScoped<InstallSetupStep,StarterKitInstallStep>();
|
|
||||||
// composition.Services.AddScoped<InstallSetupStep,StarterKitCleanupStep>();
|
|
||||||
|
|
||||||
builder.Services.AddScoped<InstallSetupStep,CompleteInstallStep>();
|
|
||||||
|
|
||||||
builder.Services.AddTransient<InstallStepCollection>();
|
|
||||||
builder.Services.AddUnique<InstallHelper>();
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,335 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Cache;
|
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
using Umbraco.Core.Dictionary;
|
|
||||||
using Umbraco.Core.IO;
|
|
||||||
using Umbraco.Core.Logging.Viewer;
|
|
||||||
using Umbraco.Core.Manifest;
|
|
||||||
using Umbraco.Core.Models.PublishedContent;
|
|
||||||
using Umbraco.Core.PackageActions;
|
|
||||||
using Umbraco.Core.Persistence.Mappers;
|
|
||||||
using Umbraco.Core.PropertyEditors;
|
|
||||||
using Umbraco.Core.Strings;
|
|
||||||
using Umbraco.Core.Sync;
|
|
||||||
using Umbraco.Web.Media.EmbedProviders;
|
|
||||||
using Umbraco.Web.Search;
|
|
||||||
|
|
||||||
namespace Umbraco.Core
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides extension methods to the <see cref="Composition"/> class.
|
|
||||||
/// </summary>
|
|
||||||
public static partial class CompositionExtensions
|
|
||||||
{
|
|
||||||
#region Collection Builders
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the cache refreshers collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<CacheRefresherCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the mappers collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<MapperCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the package actions collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<PackageActionCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the data editor collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<DataEditorCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the data value reference factory collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<DataValueReferenceFactoryCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the property value converters collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the url segment providers collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<UrlSegmentProviderCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the validators collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the manifest filter collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<ManifestFilterCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the backoffice OEmbed Providers collection builder.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<EmbedProvidersCollectionBuilder>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the back office searchable tree collection builder
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder)
|
|
||||||
=> builder.WithCollectionBuilder<SearchableTreeCollectionBuilder>();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Uniques
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the culture dictionary factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the factory.</typeparam>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static void SetCultureDictionaryFactory<T>(this IUmbracoBuilder builder)
|
|
||||||
where T : class, ICultureDictionaryFactory
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<ICultureDictionaryFactory, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the culture dictionary factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating a culture dictionary factory.</param>
|
|
||||||
public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func<IServiceProvider, ICultureDictionaryFactory> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the culture dictionary factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A factory.</param>
|
|
||||||
public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the published content model factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the factory.</typeparam>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static void SetPublishedContentModelFactory<T>(this IUmbracoBuilder builder)
|
|
||||||
where T : class, IPublishedModelFactory
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<IPublishedModelFactory, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the published content model factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating a published content model factory.</param>
|
|
||||||
public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func<IServiceProvider, IPublishedModelFactory> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the published content model factory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A published content model factory.</param>
|
|
||||||
public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the server registrar.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the server registrar.</typeparam>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static void SetServerRegistrar<T>(this IUmbracoBuilder builder)
|
|
||||||
where T : class, IServerRegistrar
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<IServerRegistrar, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the server registrar.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating a server registrar.</param>
|
|
||||||
public static void SetServerRegistrar(this IUmbracoBuilder builder, Func<IServiceProvider, IServerRegistrar> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the server registrar.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="registrar">A server registrar.</param>
|
|
||||||
public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRegistrar registrar)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(registrar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the server messenger.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the server registrar.</typeparam>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static void SetServerMessenger<T>(this IUmbracoBuilder builder)
|
|
||||||
where T : class, IServerMessenger
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<IServerMessenger, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the server messenger.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating a server messenger.</param>
|
|
||||||
public static void SetServerMessenger(this IUmbracoBuilder builder, Func<IServiceProvider, IServerMessenger> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the server messenger.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="registrar">A server messenger.</param>
|
|
||||||
public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(registrar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the database server messenger options.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating the options.</param>
|
|
||||||
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
|
|
||||||
public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func<IServiceProvider, DatabaseServerMessengerCallbacks> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the database server messenger options.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="options">Options.</param>
|
|
||||||
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
|
|
||||||
public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the short string helper.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the short string helper.</typeparam>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static void SetShortStringHelper<T>(this IUmbracoBuilder builder)
|
|
||||||
where T : class, IShortStringHelper
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<IShortStringHelper, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the short string helper.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating a short string helper.</param>
|
|
||||||
public static void SetShortStringHelper(this IUmbracoBuilder builder, Func<IServiceProvider, IShortStringHelper> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the short string helper.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">A builder.</param>
|
|
||||||
/// <param name="helper">A short string helper.</param>
|
|
||||||
public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(helper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the underlying media filesystem.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">A builder.</param>
|
|
||||||
/// <param name="filesystemFactory">A filesystem factory.</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper
|
|
||||||
/// </remarks>
|
|
||||||
public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func<IServiceProvider, IFileSystem> filesystemFactory)
|
|
||||||
=> builder.Services.AddUnique<IMediaFileSystem>(factory =>
|
|
||||||
{
|
|
||||||
var fileSystems = factory.GetRequiredService<IO.FileSystems>();
|
|
||||||
return fileSystems.GetFileSystem<MediaFileSystem>(filesystemFactory(factory));
|
|
||||||
});
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the log viewer.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the log viewer.</typeparam>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
public static void SetLogViewer<T>(this IUmbracoBuilder builder)
|
|
||||||
where T : class, ILogViewer
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<ILogViewer, T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the log viewer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder.</param>
|
|
||||||
/// <param name="factory">A function creating a log viewer.</param>
|
|
||||||
public static void SetLogViewer(this IUmbracoBuilder builder, Func<IServiceProvider, ILogViewer> factory)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the log viewer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">A builder.</param>
|
|
||||||
/// <param name="helper">A log viewer.</param>
|
|
||||||
public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique(viewer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Umbraco.Core.Cache;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
using Umbraco.Core.Manifest;
|
||||||
|
using Umbraco.Core.PackageActions;
|
||||||
|
using Umbraco.Core.Persistence.Mappers;
|
||||||
|
using Umbraco.Core.PropertyEditors;
|
||||||
|
using Umbraco.Core.Strings;
|
||||||
|
using Umbraco.Core.Trees;
|
||||||
|
using Umbraco.Web.Media.EmbedProviders;
|
||||||
|
|
||||||
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods to the <see cref="IUmbracoBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the mappers collection builder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder)
|
||||||
|
=> builder.WithCollectionBuilder<MapperCollectionBuilder>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Examine;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Core;
|
||||||
|
using Umbraco.Core.Configuration;
|
||||||
|
using Umbraco.Core.Configuration.Models;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
using Umbraco.Core.Hosting;
|
||||||
|
using Umbraco.Core.Install;
|
||||||
|
using Umbraco.Core.Logging.Serilog.Enrichers;
|
||||||
|
using Umbraco.Core.Mail;
|
||||||
|
using Umbraco.Core.Manifest;
|
||||||
|
using Umbraco.Core.Media;
|
||||||
|
using Umbraco.Core.Migrations;
|
||||||
|
using Umbraco.Core.Migrations.Install;
|
||||||
|
using Umbraco.Core.Migrations.PostMigrations;
|
||||||
|
using Umbraco.Core.Models.PublishedContent;
|
||||||
|
using Umbraco.Core.Packaging;
|
||||||
|
using Umbraco.Core.Persistence;
|
||||||
|
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||||
|
using Umbraco.Core.Runtime;
|
||||||
|
using Umbraco.Core.Scoping;
|
||||||
|
using Umbraco.Core.Serialization;
|
||||||
|
using Umbraco.Core.Strings;
|
||||||
|
using Umbraco.Core.Templates;
|
||||||
|
using Umbraco.Examine;
|
||||||
|
using Umbraco.Infrastructure.Examine;
|
||||||
|
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
|
||||||
|
using Umbraco.Infrastructure.Media;
|
||||||
|
using Umbraco.Infrastructure.Runtime;
|
||||||
|
using Umbraco.Web;
|
||||||
|
using Umbraco.Web.HealthCheck;
|
||||||
|
using Umbraco.Web.HealthCheck.NotificationMethods;
|
||||||
|
using Umbraco.Web.Install;
|
||||||
|
using Umbraco.Web.Media;
|
||||||
|
using Umbraco.Web.Migrations.PostMigrations;
|
||||||
|
using Umbraco.Web.Models.PublishedContent;
|
||||||
|
using Umbraco.Web.PropertyEditors;
|
||||||
|
using Umbraco.Web.PropertyEditors.ValueConverters;
|
||||||
|
using Umbraco.Web.PublishedCache;
|
||||||
|
using Umbraco.Web.Routing;
|
||||||
|
using Umbraco.Web.Search;
|
||||||
|
using Umbraco.Web.Trees;
|
||||||
|
|
||||||
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
|
{
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds all core Umbraco services required to run which may be replaced later in the pipeline
|
||||||
|
/// </summary>
|
||||||
|
public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.AddMainDom()
|
||||||
|
.AddLogging();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IUmbracoDatabaseFactory, UmbracoDatabaseFactory>();
|
||||||
|
builder.Services.AddUnique(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().CreateDatabase());
|
||||||
|
builder.Services.AddUnique(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().SqlContext);
|
||||||
|
builder.Services.AddUnique<IRuntimeState, RuntimeState>();
|
||||||
|
builder.Services.AddUnique<IRuntime, CoreRuntime>();
|
||||||
|
|
||||||
|
// composers
|
||||||
|
builder
|
||||||
|
.AddRepositories()
|
||||||
|
.AddServices()
|
||||||
|
.AddCoreMappingProfiles()
|
||||||
|
.AddFileSystems();
|
||||||
|
|
||||||
|
// register persistence mappers - required by database factory so needs to be done here
|
||||||
|
// means the only place the collection can be modified is in a runtime - afterwards it
|
||||||
|
// has been frozen and it is too late
|
||||||
|
builder.Mappers().AddCoreMappers();
|
||||||
|
|
||||||
|
// register the scope provider
|
||||||
|
builder.Services.AddUnique<ScopeProvider>(); // implements both IScopeProvider and IScopeAccessor
|
||||||
|
builder.Services.AddUnique<IScopeProvider>(f => f.GetRequiredService<ScopeProvider>());
|
||||||
|
builder.Services.AddUnique<IScopeAccessor>(f => f.GetRequiredService<ScopeProvider>());
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IJsonSerializer, JsonNetSerializer>();
|
||||||
|
builder.Services.AddUnique<IConfigurationEditorJsonSerializer, ConfigurationEditorJsonSerializer>();
|
||||||
|
builder.Services.AddUnique<IMenuItemCollectionFactory, MenuItemCollectionFactory>();
|
||||||
|
|
||||||
|
// register database builder
|
||||||
|
// *not* a singleton, don't want to keep it around
|
||||||
|
builder.Services.AddTransient<DatabaseBuilder>();
|
||||||
|
|
||||||
|
// register manifest parser, will be injected in collection builders where needed
|
||||||
|
builder.Services.AddUnique<IManifestParser, ManifestParser>();
|
||||||
|
|
||||||
|
// register the manifest filter collection builder (collection is empty by default)
|
||||||
|
builder.ManifestFilters();
|
||||||
|
|
||||||
|
builder.MediaUrlGenerators()
|
||||||
|
.Add<FileUploadPropertyEditor>()
|
||||||
|
.Add<ImageCropperPropertyEditor>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IShortStringHelper>(factory
|
||||||
|
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService<IOptions<RequestHandlerSettings>>().Value)));
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IMigrationBuilder>(factory => new MigrationBuilder(factory));
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
|
||||||
|
|
||||||
|
// register the published snapshot accessor - the "current" published snapshot is in the umbraco context
|
||||||
|
builder.Services.AddUnique<IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IVariationContextAccessor, HybridVariationContextAccessor>();
|
||||||
|
|
||||||
|
// Config manipulator
|
||||||
|
builder.Services.AddUnique<IConfigManipulator, JsonConfigManipulator>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<RichTextEditorPastedImages>();
|
||||||
|
builder.Services.AddUnique<BlockEditorConverter>();
|
||||||
|
|
||||||
|
// both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be
|
||||||
|
// discovered when CoreBootManager configures the converters. We will remove the basic one defined
|
||||||
|
// in core so that the more enhanced version is active.
|
||||||
|
builder.PropertyValueConverters()
|
||||||
|
.Remove<SimpleTinyMceValueConverter>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
|
||||||
|
|
||||||
|
// register *all* checks, except those marked [HideFromTypeFinder] of course
|
||||||
|
builder.Services.AddUnique<IMarkdownToHtmlConverter, MarkdownToHtmlConverter>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IContentLastChanceFinder, ContentFinderByConfigured404>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<UmbracoTreeSearcher>();
|
||||||
|
|
||||||
|
// replace
|
||||||
|
builder.Services.AddUnique<IEmailSender, EmailSender>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IExamineManager, ExamineManager>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<ITagQuery, TagQuery>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IUmbracoTreeSearcherFields, UmbracoTreeSearcherFields>();
|
||||||
|
builder.Services.AddScoped<IPublishedContentQuery>(factory =>
|
||||||
|
{
|
||||||
|
var umbCtx = factory.GetRequiredService<IUmbracoContextAccessor>();
|
||||||
|
return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService<IVariationContextAccessor>(), factory.GetRequiredService<IExamineManager>());
|
||||||
|
});
|
||||||
|
|
||||||
|
// register accessors for cultures
|
||||||
|
builder.Services.AddUnique<IDefaultCultureAccessor, DefaultCultureAccessor>();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<IFilePermissionHelper, FilePermissionHelper>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IUmbracoComponentRenderer, UmbracoComponentRenderer>();
|
||||||
|
|
||||||
|
// Register noop versions for examine to be overridden by examine
|
||||||
|
builder.Services.AddUnique<IUmbracoIndexesCreator, NoopUmbracoIndexesCreator>();
|
||||||
|
builder.Services.AddUnique<IBackOfficeExamineSearcher, NoopBackOfficeExamineSearcher>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<UploadAutoFillProperties>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<ICronTabParser, NCronTabParser>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IImageDimensionExtractor, ImageDimensionExtractor>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<PackageDataInstallation>();
|
||||||
|
|
||||||
|
builder.AddInstaller();
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds logging requirements for Umbraco
|
||||||
|
/// </summary>
|
||||||
|
private static IUmbracoBuilder AddLogging(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique<ThreadAbortExceptionEnricher>();
|
||||||
|
builder.Services.AddUnique<HttpSessionIdEnricher>();
|
||||||
|
builder.Services.AddUnique<HttpRequestNumberEnricher>();
|
||||||
|
builder.Services.AddUnique<HttpRequestIdEnricher>();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IUmbracoBuilder AddMainDom(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique<IMainDomLock>(factory =>
|
||||||
|
{
|
||||||
|
var globalSettings = factory.GetRequiredService<IOptions<GlobalSettings>>().Value;
|
||||||
|
var connectionStrings = factory.GetRequiredService<IOptions<ConnectionStrings>>().Value;
|
||||||
|
var hostingEnvironment = factory.GetRequiredService<IHostingEnvironment>();
|
||||||
|
|
||||||
|
var dbCreator = factory.GetRequiredService<IDbProviderFactoryCreator>();
|
||||||
|
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
var loggerFactory = factory.GetRequiredService<ILoggerFactory>();
|
||||||
|
|
||||||
|
return globalSettings.MainDomLock.Equals("SqlMainDomLock") || isWindows == false
|
||||||
|
? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger<SqlMainDomLock>(), loggerFactory, globalSettings, connectionStrings, dbCreator, hostingEnvironment)
|
||||||
|
: new MainDomSemaphoreLock(loggerFactory.CreateLogger<MainDomSemaphoreLock>(), hostingEnvironment);
|
||||||
|
});
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
using Umbraco.Core.Events;
|
||||||
|
using Umbraco.Core.Services.Changes;
|
||||||
|
using Umbraco.Core.Sync;
|
||||||
|
using Umbraco.Infrastructure.Cache;
|
||||||
|
using Umbraco.Web.Cache;
|
||||||
|
using Umbraco.Web.PublishedCache;
|
||||||
|
using Umbraco.Web.Search;
|
||||||
|
|
||||||
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods to the <see cref="IUmbracoBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds distributed cache support
|
||||||
|
/// </summary>
|
||||||
|
public static IUmbracoBuilder AddDistributedCache(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
builder.SetDatabaseServerMessengerCallbacks(GetCallbacks);
|
||||||
|
builder.SetServerMessenger<BatchedDatabaseServerMessenger>();
|
||||||
|
builder.AddNotificationHandler<UmbracoApplicationStarting, DatabaseServerMessengerNotificationHandler>();
|
||||||
|
|
||||||
|
builder.Services.AddUnique<IDistributedCacheBinder, DistributedCacheBinder>();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the server registrar.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the server registrar.</typeparam>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static void SetServerRegistrar<T>(this IUmbracoBuilder builder)
|
||||||
|
where T : class, IServerRoleAccessor
|
||||||
|
=> builder.Services.AddUnique<IServerRoleAccessor, T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the server registrar.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating a server registrar.</param>
|
||||||
|
public static void SetServerRegistrar(this IUmbracoBuilder builder, Func<IServiceProvider, IServerRoleAccessor> factory)
|
||||||
|
=> builder.Services.AddUnique(factory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the server registrar.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="registrar">A server registrar.</param>
|
||||||
|
public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor registrar)
|
||||||
|
=> builder.Services.AddUnique(registrar);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the database server messenger options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating the options.</param>
|
||||||
|
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
|
||||||
|
public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func<IServiceProvider, DatabaseServerMessengerCallbacks> factory)
|
||||||
|
=> builder.Services.AddUnique(factory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the database server messenger options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="options">Options.</param>
|
||||||
|
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
|
||||||
|
public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options)
|
||||||
|
=> builder.Services.AddUnique(options);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the server messenger.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the server registrar.</typeparam>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static void SetServerMessenger<T>(this IUmbracoBuilder builder)
|
||||||
|
where T : class, IServerMessenger
|
||||||
|
=> builder.Services.AddUnique<IServerMessenger, T>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the server messenger.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating a server messenger.</param>
|
||||||
|
public static void SetServerMessenger(this IUmbracoBuilder builder, Func<IServiceProvider, IServerMessenger> factory)
|
||||||
|
=> builder.Services.AddUnique(factory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the server messenger.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="registrar">A server messenger.</param>
|
||||||
|
public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar)
|
||||||
|
=> builder.Services.AddUnique(registrar);
|
||||||
|
|
||||||
|
private static DatabaseServerMessengerCallbacks GetCallbacks(IServiceProvider factory) => new DatabaseServerMessengerCallbacks
|
||||||
|
{
|
||||||
|
// These callbacks will be executed if the server has not been synced
|
||||||
|
// (i.e. it is a new server or the lastsynced.txt file has been removed)
|
||||||
|
InitializingCallbacks = new Action[]
|
||||||
|
{
|
||||||
|
// rebuild the xml cache file if the server is not synced
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
IPublishedSnapshotService publishedSnapshotService = factory.GetRequiredService<IPublishedSnapshotService>();
|
||||||
|
|
||||||
|
// rebuild the published snapshot caches entirely, if the server is not synced
|
||||||
|
// this is equivalent to DistributedCache RefreshAll... but local only
|
||||||
|
// (we really should have a way to reuse RefreshAll... locally)
|
||||||
|
// note: refresh all content & media caches does refresh content types too
|
||||||
|
publishedSnapshotService.Notify(new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) });
|
||||||
|
publishedSnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _);
|
||||||
|
publishedSnapshotService.Notify(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _);
|
||||||
|
},
|
||||||
|
|
||||||
|
// rebuild indexes if the server is not synced
|
||||||
|
// NOTE: This will rebuild ALL indexes including the members, if developers want to target specific
|
||||||
|
// indexes then they can adjust this logic themselves.
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var indexRebuilder = factory.GetRequiredService<BackgroundIndexRebuilder>();
|
||||||
|
indexRebuilder.RebuildIndexes(false, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.Hosting;
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.IO;
|
using Umbraco.Core.IO;
|
||||||
using Umbraco.Core.IO.MediaPathSchemes;
|
using Umbraco.Core.IO.MediaPathSchemes;
|
||||||
using Umbraco.Core.Strings;
|
|
||||||
|
|
||||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
{
|
{
|
||||||
internal static class FileSystems
|
public static partial class UmbracoBuilderExtensions
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* HOW TO REPLACE THE MEDIA UNDERLYING FILESYSTEM
|
* HOW TO REPLACE THE MEDIA UNDERLYING FILESYSTEM
|
||||||
@@ -34,16 +33,16 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static IUmbracoBuilder ComposeFileSystems(this IUmbracoBuilder builder)
|
internal static IUmbracoBuilder AddFileSystems(this IUmbracoBuilder builder)
|
||||||
{
|
{
|
||||||
// register FileSystems, which manages all filesystems
|
// register FileSystems, which manages all filesystems
|
||||||
// it needs to be registered (not only the interface) because it provides additional
|
// it needs to be registered (not only the interface) because it provides additional
|
||||||
// functionality eg for scoping, and is injected in the scope provider - whereas the
|
// functionality eg for scoping, and is injected in the scope provider - whereas the
|
||||||
// interface is really for end-users to get access to filesystems.
|
// interface is really for end-users to get access to filesystems.
|
||||||
builder.Services.AddUnique(factory => factory.CreateInstance<Core.IO.FileSystems>(factory));
|
builder.Services.AddUnique(factory => factory.CreateInstance<FileSystems>(factory));
|
||||||
|
|
||||||
// register IFileSystems, which gives access too all filesystems
|
// register IFileSystems, which gives access too all filesystems
|
||||||
builder.Services.AddUnique<IFileSystems>(factory => factory.GetRequiredService<Core.IO.FileSystems>());
|
builder.Services.AddUnique<IFileSystems>(factory => factory.GetRequiredService<FileSystems>());
|
||||||
|
|
||||||
// register the scheme for media paths
|
// register the scheme for media paths
|
||||||
builder.Services.AddUnique<IMediaPathScheme, UniqueMediaPathScheme>();
|
builder.Services.AddUnique<IMediaPathScheme, UniqueMediaPathScheme>();
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
using Umbraco.Web.Install;
|
||||||
|
using Umbraco.Web.Install.InstallSteps;
|
||||||
|
using Umbraco.Web.Install.Models;
|
||||||
|
|
||||||
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
|
{
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the services for the Umbraco installer
|
||||||
|
/// </summary>
|
||||||
|
internal static IUmbracoBuilder AddInstaller(this IUmbracoBuilder builder)
|
||||||
|
{
|
||||||
|
// register the installer steps
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, NewInstallStep>();
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, UpgradeStep>();
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, FilePermissionsStep>();
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, DatabaseConfigureStep>();
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, DatabaseInstallStep>();
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, DatabaseUpgradeStep>();
|
||||||
|
|
||||||
|
// TODO: Add these back once we have a compatible Starter kit
|
||||||
|
// composition.Services.AddScoped<InstallSetupStep,StarterKitDownloadStep>();
|
||||||
|
// composition.Services.AddScoped<InstallSetupStep,StarterKitInstallStep>();
|
||||||
|
// composition.Services.AddScoped<InstallSetupStep,StarterKitCleanupStep>();
|
||||||
|
builder.Services.AddScoped<InstallSetupStep, CompleteInstallStep>();
|
||||||
|
|
||||||
|
builder.Services.AddTransient<InstallStepCollection>();
|
||||||
|
builder.Services.AddUnique<InstallHelper>();
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,17 +4,14 @@ using Umbraco.Core.Mapping;
|
|||||||
using Umbraco.Core.Security;
|
using Umbraco.Core.Security;
|
||||||
using Umbraco.Web.Models.Mapping;
|
using Umbraco.Web.Models.Mapping;
|
||||||
|
|
||||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
|
|
||||||
{
|
{
|
||||||
public static class CoreMappingProfiles
|
public static partial class UmbracoBuilderExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the core Umbraco mapper definitions
|
/// Registers the core Umbraco mapper definitions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="builder"></param>
|
public static IUmbracoBuilder AddCoreMappingProfiles(this IUmbracoBuilder builder)
|
||||||
/// <returns></returns>
|
|
||||||
public static IUmbracoBuilder ComposeCoreMappingProfiles(this IUmbracoBuilder builder)
|
|
||||||
{
|
{
|
||||||
builder.Services.AddUnique<UmbracoMapper>();
|
builder.Services.AddUnique<UmbracoMapper>();
|
||||||
|
|
||||||
@@ -34,8 +31,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
|||||||
.Add<TemplateMapDefinition>()
|
.Add<TemplateMapDefinition>()
|
||||||
.Add<UserMapDefinition>()
|
.Add<UserMapDefinition>()
|
||||||
.Add<LanguageMapDefinition>()
|
.Add<LanguageMapDefinition>()
|
||||||
.Add<IdentityMapDefinition>()
|
.Add<IdentityMapDefinition>();
|
||||||
;
|
|
||||||
|
|
||||||
builder.Services.AddTransient<CommonMapper>();
|
builder.Services.AddTransient<CommonMapper>();
|
||||||
builder.Services.AddTransient<MemberTabsAndPropertiesMapper>();
|
builder.Services.AddTransient<MemberTabsAndPropertiesMapper>();
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
using Umbraco.Core.DependencyInjection;
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.Persistence.Repositories;
|
using Umbraco.Core.Persistence.Repositories;
|
||||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||||
|
|
||||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Composes repositories.
|
/// Composes repositories.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class Repositories
|
public static partial class UmbracoBuilderExtensions
|
||||||
{
|
{
|
||||||
public static IUmbracoBuilder ComposeRepositories(this IUmbracoBuilder builder)
|
/// <summary>
|
||||||
|
/// Adds the Umbraco repositories
|
||||||
|
/// </summary>
|
||||||
|
internal static IUmbracoBuilder AddRepositories(this IUmbracoBuilder builder)
|
||||||
{
|
{
|
||||||
// repositories
|
// repositories
|
||||||
builder.Services.AddUnique<IAuditRepository, AuditRepository>();
|
builder.Services.AddUnique<IAuditRepository, AuditRepository>();
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Umbraco.Core;
|
||||||
using Umbraco.Core.Cache;
|
using Umbraco.Core.Cache;
|
||||||
using Umbraco.Core.Configuration;
|
using Umbraco.Core.Configuration;
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
@@ -15,16 +16,15 @@ using Umbraco.Core.Routing;
|
|||||||
using Umbraco.Core.Services;
|
using Umbraco.Core.Services;
|
||||||
using Umbraco.Core.Services.Implement;
|
using Umbraco.Core.Services.Implement;
|
||||||
|
|
||||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
{
|
{
|
||||||
internal static class Services
|
public static partial class UmbracoBuilderExtensions
|
||||||
{
|
{
|
||||||
public static IUmbracoBuilder ComposeServices(this IUmbracoBuilder builder)
|
/// <summary>
|
||||||
|
/// Adds Umbraco services
|
||||||
|
/// </summary>
|
||||||
|
internal static IUmbracoBuilder AddServices(this IUmbracoBuilder builder)
|
||||||
{
|
{
|
||||||
// register a transient messages factory, which will be replaced by the web
|
|
||||||
// boot manager when running in a web context
|
|
||||||
builder.Services.AddUnique<IEventMessagesFactory, TransientEventMessagesFactory>();
|
|
||||||
|
|
||||||
// register the service context
|
// register the service context
|
||||||
builder.Services.AddUnique<ServiceContext>();
|
builder.Services.AddUnique<ServiceContext>();
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
|||||||
builder.Services.AddUnique<IExternalLoginService, ExternalLoginService>();
|
builder.Services.AddUnique<IExternalLoginService, ExternalLoginService>();
|
||||||
builder.Services.AddUnique<IRedirectUrlService, RedirectUrlService>();
|
builder.Services.AddUnique<IRedirectUrlService, RedirectUrlService>();
|
||||||
builder.Services.AddUnique<IConsentService, ConsentService>();
|
builder.Services.AddUnique<IConsentService, ConsentService>();
|
||||||
builder.Services.AddTransient<LocalizedTextServiceFileSources>(SourcesFactory);
|
builder.Services.AddTransient(SourcesFactory);
|
||||||
builder.Services.AddUnique<ILocalizedTextService>(factory => new LocalizedTextService(
|
builder.Services.AddUnique<ILocalizedTextService>(factory => new LocalizedTextService(
|
||||||
factory.GetRequiredService<Lazy<LocalizedTextServiceFileSources>>(),
|
factory.GetRequiredService<Lazy<LocalizedTextServiceFileSources>>(),
|
||||||
factory.GetRequiredService<ILogger<LocalizedTextService>>()));
|
factory.GetRequiredService<ILogger<LocalizedTextService>>()));
|
||||||
@@ -82,9 +82,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instance of PackagesRepository for either the ICreatedPackagesRepository or the IInstalledPackagesRepository
|
/// Creates an instance of PackagesRepository for either the ICreatedPackagesRepository or the IInstalledPackagesRepository
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="factory"></param>
|
|
||||||
/// <param name="packageRepoFileName"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static PackagesRepository CreatePackageRepository(IServiceProvider factory, string packageRepoFileName)
|
private static PackagesRepository CreatePackageRepository(IServiceProvider factory, string packageRepoFileName)
|
||||||
=> new PackagesRepository(
|
=> new PackagesRepository(
|
||||||
factory.GetRequiredService<IContentService>(),
|
factory.GetRequiredService<IContentService>(),
|
||||||
@@ -106,9 +103,9 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
|||||||
{
|
{
|
||||||
var hostingEnvironment = container.GetRequiredService<IHostingEnvironment>();
|
var hostingEnvironment = container.GetRequiredService<IHostingEnvironment>();
|
||||||
var globalSettings = container.GetRequiredService<IOptions<GlobalSettings>>().Value;
|
var globalSettings = container.GetRequiredService<IOptions<GlobalSettings>>().Value;
|
||||||
var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath , "config","lang")));
|
var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath, "config", "lang")));
|
||||||
var appPlugins = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins));
|
var appPlugins = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins));
|
||||||
var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config ,"lang")));
|
var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config, "lang")));
|
||||||
|
|
||||||
var pluginLangFolders = appPlugins.Exists == false
|
var pluginLangFolders = appPlugins.Exists == false
|
||||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||||
@@ -117,7 +114,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
|||||||
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
|
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
|
||||||
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
|
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
|
||||||
|
|
||||||
//user defined langs that overwrite the default, these should not be used by plugin creators
|
// user defined langs that overwrite the default, these should not be used by plugin creators
|
||||||
var userLangFolders = configLangFolder.Exists == false
|
var userLangFolders = configLangFolder.Exists == false
|
||||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||||
: configLangFolder
|
: configLangFolder
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
using Umbraco.Core.Dictionary;
|
||||||
|
using Umbraco.Core.IO;
|
||||||
|
using Umbraco.Core.Logging.Viewer;
|
||||||
|
using Umbraco.Core.Models.PublishedContent;
|
||||||
|
using Umbraco.Core.Strings;
|
||||||
|
using Umbraco.Core.Sync;
|
||||||
|
|
||||||
|
namespace Umbraco.Infrastructure.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods to the <see cref="IUmbracoBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public static partial class UmbracoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the culture dictionary factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the factory.</typeparam>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static void SetCultureDictionaryFactory<T>(this IUmbracoBuilder builder)
|
||||||
|
where T : class, ICultureDictionaryFactory
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique<ICultureDictionaryFactory, T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the culture dictionary factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating a culture dictionary factory.</param>
|
||||||
|
public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func<IServiceProvider, ICultureDictionaryFactory> factory)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the culture dictionary factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A factory.</param>
|
||||||
|
public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the published content model factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the factory.</typeparam>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static void SetPublishedContentModelFactory<T>(this IUmbracoBuilder builder)
|
||||||
|
where T : class, IPublishedModelFactory
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique<IPublishedModelFactory, T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the published content model factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating a published content model factory.</param>
|
||||||
|
public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func<IServiceProvider, IPublishedModelFactory> factory)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the published content model factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A published content model factory.</param>
|
||||||
|
public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the short string helper.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the short string helper.</typeparam>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static void SetShortStringHelper<T>(this IUmbracoBuilder builder)
|
||||||
|
where T : class, IShortStringHelper
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique<IShortStringHelper, T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the short string helper.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating a short string helper.</param>
|
||||||
|
public static void SetShortStringHelper(this IUmbracoBuilder builder, Func<IServiceProvider, IShortStringHelper> factory)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the short string helper.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">A builder.</param>
|
||||||
|
/// <param name="helper">A short string helper.</param>
|
||||||
|
public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the underlying media filesystem.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">A builder.</param>
|
||||||
|
/// <param name="filesystemFactory">A filesystem factory.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper
|
||||||
|
/// </remarks>
|
||||||
|
public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func<IServiceProvider, IFileSystem> filesystemFactory)
|
||||||
|
=> builder.Services.AddUnique<IMediaFileSystem>(factory =>
|
||||||
|
{
|
||||||
|
var fileSystems = factory.GetRequiredService<FileSystems>();
|
||||||
|
return fileSystems.GetFileSystem<MediaFileSystem>(filesystemFactory(factory));
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the log viewer.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the log viewer.</typeparam>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
public static void SetLogViewer<T>(this IUmbracoBuilder builder)
|
||||||
|
where T : class, ILogViewer
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique<ILogViewer, T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the log viewer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder.</param>
|
||||||
|
/// <param name="factory">A function creating a log viewer.</param>
|
||||||
|
public static void SetLogViewer(this IUmbracoBuilder builder, Func<IServiceProvider, ILogViewer> factory)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the log viewer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">A builder.</param>
|
||||||
|
/// <param name="helper">A log viewer.</param>
|
||||||
|
public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer)
|
||||||
|
{
|
||||||
|
builder.Services.AddUnique(viewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ using MimeKit;
|
|||||||
using MimeKit.Text;
|
using MimeKit.Text;
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
|
using Umbraco.Core.Mail;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
|
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
private readonly HealthCheckCollection _healthChecks;
|
private readonly HealthCheckCollection _healthChecks;
|
||||||
private readonly HealthCheckNotificationMethodCollection _notifications;
|
private readonly HealthCheckNotificationMethodCollection _notifications;
|
||||||
private readonly IRuntimeState _runtimeState;
|
private readonly IRuntimeState _runtimeState;
|
||||||
private readonly IServerRegistrar _serverRegistrar;
|
private readonly IServerRoleAccessor _serverRegistrar;
|
||||||
private readonly IMainDom _mainDom;
|
private readonly IMainDom _mainDom;
|
||||||
private readonly IScopeProvider _scopeProvider;
|
private readonly IScopeProvider _scopeProvider;
|
||||||
private readonly ILogger<HealthCheckNotifier> _logger;
|
private readonly ILogger<HealthCheckNotifier> _logger;
|
||||||
@@ -54,7 +54,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
HealthCheckCollection healthChecks,
|
HealthCheckCollection healthChecks,
|
||||||
HealthCheckNotificationMethodCollection notifications,
|
HealthCheckNotificationMethodCollection notifications,
|
||||||
IRuntimeState runtimeState,
|
IRuntimeState runtimeState,
|
||||||
IServerRegistrar serverRegistrar,
|
IServerRoleAccessor serverRegistrar,
|
||||||
IMainDom mainDom,
|
IMainDom mainDom,
|
||||||
IScopeProvider scopeProvider,
|
IScopeProvider scopeProvider,
|
||||||
ILogger<HealthCheckNotifier> logger,
|
ILogger<HealthCheckNotifier> logger,
|
||||||
@@ -87,7 +87,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_serverRegistrar.GetCurrentServerRole())
|
switch (_serverRegistrar.CurrentServerRole)
|
||||||
{
|
{
|
||||||
case ServerRole.Replica:
|
case ServerRole.Replica:
|
||||||
_logger.LogDebug("Does not run on replica servers.");
|
_logger.LogDebug("Does not run on replica servers.");
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
private readonly KeepAliveSettings _keepAliveSettings;
|
private readonly KeepAliveSettings _keepAliveSettings;
|
||||||
private readonly ILogger<KeepAlive> _logger;
|
private readonly ILogger<KeepAlive> _logger;
|
||||||
private readonly IProfilingLogger _profilingLogger;
|
private readonly IProfilingLogger _profilingLogger;
|
||||||
private readonly IServerRegistrar _serverRegistrar;
|
private readonly IServerRoleAccessor _serverRegistrar;
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -43,7 +43,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
IOptions<KeepAliveSettings> keepAliveSettings,
|
IOptions<KeepAliveSettings> keepAliveSettings,
|
||||||
ILogger<KeepAlive> logger,
|
ILogger<KeepAlive> logger,
|
||||||
IProfilingLogger profilingLogger,
|
IProfilingLogger profilingLogger,
|
||||||
IServerRegistrar serverRegistrar,
|
IServerRoleAccessor serverRegistrar,
|
||||||
IHttpClientFactory httpClientFactory)
|
IHttpClientFactory httpClientFactory)
|
||||||
: base(TimeSpan.FromMinutes(5), DefaultDelay)
|
: base(TimeSpan.FromMinutes(5), DefaultDelay)
|
||||||
{
|
{
|
||||||
@@ -64,7 +64,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't run on replicas nor unknown role servers
|
// Don't run on replicas nor unknown role servers
|
||||||
switch (_serverRegistrar.GetCurrentServerRole())
|
switch (_serverRegistrar.CurrentServerRole)
|
||||||
{
|
{
|
||||||
case ServerRole.Replica:
|
case ServerRole.Replica:
|
||||||
_logger.LogDebug("Does not run on replica servers.");
|
_logger.LogDebug("Does not run on replica servers.");
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
public class LogScrubber : RecurringHostedServiceBase
|
public class LogScrubber : RecurringHostedServiceBase
|
||||||
{
|
{
|
||||||
private readonly IMainDom _mainDom;
|
private readonly IMainDom _mainDom;
|
||||||
private readonly IServerRegistrar _serverRegistrar;
|
private readonly IServerRoleAccessor _serverRegistrar;
|
||||||
private readonly IAuditService _auditService;
|
private readonly IAuditService _auditService;
|
||||||
private readonly LoggingSettings _settings;
|
private readonly LoggingSettings _settings;
|
||||||
private readonly IProfilingLogger _profilingLogger;
|
private readonly IProfilingLogger _profilingLogger;
|
||||||
@@ -42,7 +42,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
/// <param name="profilingLogger">The profiling logger.</param>
|
/// <param name="profilingLogger">The profiling logger.</param>
|
||||||
public LogScrubber(
|
public LogScrubber(
|
||||||
IMainDom mainDom,
|
IMainDom mainDom,
|
||||||
IServerRegistrar serverRegistrar,
|
IServerRoleAccessor serverRegistrar,
|
||||||
IAuditService auditService,
|
IAuditService auditService,
|
||||||
IOptions<LoggingSettings> settings,
|
IOptions<LoggingSettings> settings,
|
||||||
IScopeProvider scopeProvider,
|
IScopeProvider scopeProvider,
|
||||||
@@ -61,7 +61,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
|
|
||||||
internal override Task PerformExecuteAsync(object state)
|
internal override Task PerformExecuteAsync(object state)
|
||||||
{
|
{
|
||||||
switch (_serverRegistrar.GetCurrentServerRole())
|
switch (_serverRegistrar.CurrentServerRole)
|
||||||
{
|
{
|
||||||
case ServerRole.Replica:
|
case ServerRole.Replica:
|
||||||
_logger.LogDebug("Does not run on replica servers.");
|
_logger.LogDebug("Does not run on replica servers.");
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
private readonly IRuntimeState _runtimeState;
|
private readonly IRuntimeState _runtimeState;
|
||||||
private readonly IServerMessenger _serverMessenger;
|
private readonly IServerMessenger _serverMessenger;
|
||||||
private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory;
|
private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory;
|
||||||
private readonly IServerRegistrar _serverRegistrar;
|
private readonly IServerRoleAccessor _serverRegistrar;
|
||||||
private readonly IUmbracoContextFactory _umbracoContextFactory;
|
private readonly IUmbracoContextFactory _umbracoContextFactory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -44,7 +44,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
public ScheduledPublishing(
|
public ScheduledPublishing(
|
||||||
IRuntimeState runtimeState,
|
IRuntimeState runtimeState,
|
||||||
IMainDom mainDom,
|
IMainDom mainDom,
|
||||||
IServerRegistrar serverRegistrar,
|
IServerRoleAccessor serverRegistrar,
|
||||||
IContentService contentService,
|
IContentService contentService,
|
||||||
IUmbracoContextFactory umbracoContextFactory,
|
IUmbracoContextFactory umbracoContextFactory,
|
||||||
ILogger<ScheduledPublishing> logger,
|
ILogger<ScheduledPublishing> logger,
|
||||||
@@ -69,7 +69,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_serverRegistrar.GetCurrentServerRole())
|
switch (_serverRegistrar.CurrentServerRole)
|
||||||
{
|
{
|
||||||
case ServerRole.Replica:
|
case ServerRole.Replica:
|
||||||
_logger.LogDebug("Does not run on replica servers.");
|
_logger.LogDebug("Does not run on replica servers.");
|
||||||
@@ -123,9 +123,9 @@ namespace Umbraco.Infrastructure.HostedServices
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// If running on a temp context, we have to flush the messenger
|
// If running on a temp context, we have to flush the messenger
|
||||||
if (contextReference.IsRoot && _serverMessenger is IBatchedDatabaseServerMessenger m)
|
if (contextReference.IsRoot)
|
||||||
{
|
{
|
||||||
m.FlushBatch();
|
_serverMessenger.SendMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
|
|||||||
public class InstructionProcessTask : RecurringHostedServiceBase
|
public class InstructionProcessTask : RecurringHostedServiceBase
|
||||||
{
|
{
|
||||||
private readonly IRuntimeState _runtimeState;
|
private readonly IRuntimeState _runtimeState;
|
||||||
private readonly IDatabaseServerMessenger _messenger;
|
private readonly IServerMessenger _messenger;
|
||||||
private readonly ILogger<InstructionProcessTask> _logger;
|
private readonly ILogger<InstructionProcessTask> _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -31,7 +31,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
|
|||||||
: base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1))
|
: base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1))
|
||||||
{
|
{
|
||||||
_runtimeState = runtimeState;
|
_runtimeState = runtimeState;
|
||||||
_messenger = messenger as IDatabaseServerMessenger ?? throw new ArgumentNullException(nameof(messenger));
|
_messenger = messenger;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,9 +57,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TouchServer uses a proper unit of work etc underneath so even in a
|
_serverRegistrationService.TouchServer(serverAddress, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout);
|
||||||
// background task it is safe to call it without dealing with any scope.
|
|
||||||
_serverRegistrationService.TouchServer(serverAddress, _serverRegistrationService.CurrentServerIdentity, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ using Umbraco.Core.Services;
|
|||||||
using Umbraco.Core.Configuration;
|
using Umbraco.Core.Configuration;
|
||||||
using Umbraco.Core.Models.Packaging;
|
using Umbraco.Core.Models.Packaging;
|
||||||
using Umbraco.Core.Security;
|
using Umbraco.Core.Security;
|
||||||
using Umbraco.Net;
|
|
||||||
using Umbraco.Web.Install.Models;
|
using Umbraco.Web.Install.Models;
|
||||||
using Umbraco.Web.Security;
|
using Umbraco.Web.Security;
|
||||||
|
using Umbraco.Core.Hosting;
|
||||||
|
|
||||||
namespace Umbraco.Web.Install.InstallSteps
|
namespace Umbraco.Web.Install.InstallSteps
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
@@ -55,6 +55,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers
|
|||||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message));
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dumped = MiniDump.Dump(_marchal, _hostingEnvironment, withException: true);
|
var dumped = MiniDump.Dump(_marchal, _hostingEnvironment, withException: true);
|
||||||
@@ -68,6 +69,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers
|
|||||||
message = "Failed to create a minidump. " + ex;
|
message = "Failed to create a minidump. " + ex;
|
||||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message));
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsTimeoutThreadAbortException(Exception exception)
|
private static bool IsTimeoutThreadAbortException(Exception exception)
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
using Umbraco.Core.Logging.Serilog.Enrichers;
|
|
||||||
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
|
|
||||||
|
|
||||||
namespace Umbraco.Infrastructure.Logging.Serilog
|
|
||||||
{
|
|
||||||
public class SerilogComposer : ICoreComposer
|
|
||||||
{
|
|
||||||
public void Compose(IUmbracoBuilder builder)
|
|
||||||
{
|
|
||||||
builder.Services.AddUnique<ThreadAbortExceptionEnricher>();
|
|
||||||
builder.Services.AddUnique<HttpSessionIdEnricher>();
|
|
||||||
builder.Services.AddUnique<HttpRequestNumberEnricher>();
|
|
||||||
builder.Services.AddUnique<HttpRequestIdEnricher>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using Umbraco.Core.DependencyInjection;
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
|
using Umbraco.Infrastructure.DependencyInjection;
|
||||||
|
|
||||||
namespace Umbraco.Core.Logging.Viewer
|
namespace Umbraco.Core.Logging.Viewer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Umbraco.Core;
|
using Umbraco.Core;
|
||||||
@@ -18,7 +18,7 @@ namespace Umbraco.Web.Media
|
|||||||
/// use potentially large amounts of memory.</remarks>
|
/// use potentially large amounts of memory.</remarks>
|
||||||
public ImageSize GetDimensions(Stream stream)
|
public ImageSize GetDimensions(Stream stream)
|
||||||
{
|
{
|
||||||
//Try to load with exif
|
// Try to load with exif
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height))
|
if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height))
|
||||||
@@ -28,12 +28,13 @@ namespace Umbraco.Web.Media
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
//We will just swallow, just means we can't read exif data, we don't want to log an error either
|
// We will just swallow, just means we can't read exif data, we don't want to log an error either
|
||||||
}
|
}
|
||||||
|
|
||||||
//we have no choice but to try to read in via GDI
|
// we have no choice but to try to read in via GDI
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// TODO: We should be using ImageSharp for this
|
||||||
using (var image = Image.FromStream(stream))
|
using (var image = Image.FromStream(stream))
|
||||||
{
|
{
|
||||||
var fileWidth = image.Width;
|
var fileWidth = image.Width;
|
||||||
@@ -43,7 +44,7 @@ namespace Umbraco.Web.Media
|
|||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
//We will just swallow, just means we can't read via GDI, we don't want to log an error either
|
// We will just swallow, just means we can't read via GDI, we don't want to log an error either
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ImageSize(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
|
return new ImageSize(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
|
using Umbraco.Core.DependencyInjection;
|
||||||
|
|
||||||
namespace Umbraco.Core.Migrations
|
namespace Umbraco.Core.Migrations
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Umbraco.Core.Migrations.PostMigrations
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements <see cref="IPublishedSnapshotRebuilder"/> in Umbraco.Core (doing nothing).
|
|
||||||
/// </summary>
|
|
||||||
public class NoopPublishedSnapshotRebuilder : IPublishedSnapshotRebuilder
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Rebuild()
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -17,16 +17,11 @@ namespace Umbraco.Core.Packaging
|
|||||||
private readonly IPackageActionRunner _packageActionRunner;
|
private readonly IPackageActionRunner _packageActionRunner;
|
||||||
private readonly DirectoryInfo _applicationRootFolder;
|
private readonly DirectoryInfo _applicationRootFolder;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Initializes a new instance of the <see cref="PackageInstallation"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="packageDataInstallation"></param>
|
public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, IHostingEnvironment hostingEnvironment)
|
||||||
/// <param name="packageFileInstallation"></param>
|
|
||||||
/// <param name="parser"></param>
|
|
||||||
/// <param name="packageActionRunner"></param>
|
|
||||||
/// <param name="hostingEnvironment"></param>
|
|
||||||
public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner,
|
|
||||||
IHostingEnvironment hostingEnvironment)
|
|
||||||
{
|
{
|
||||||
_packageExtraction = new PackageExtraction();
|
_packageExtraction = new PackageExtraction();
|
||||||
_packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation));
|
_packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using HtmlAgilityPack;
|
using HtmlAgilityPack;
|
||||||
using Umbraco.Core;
|
using Umbraco.Core;
|
||||||
@@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
|||||||
/// used dynamically.
|
/// used dynamically.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultPropertyValueConverter]
|
[DefaultPropertyValueConverter]
|
||||||
public class RteMacroRenderingValueConverter : TinyMceValueConverter
|
public class RteMacroRenderingValueConverter : SimpleTinyMceValueConverter
|
||||||
{
|
{
|
||||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||||
private readonly IMacroRenderer _macroRenderer;
|
private readonly IMacroRenderer _macroRenderer;
|
||||||
|
|||||||
@@ -1,392 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Examine;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.Cache;
|
|
||||||
using Umbraco.Core.Composing.CompositionExtensions;
|
|
||||||
using Umbraco.Core.Configuration;
|
|
||||||
using Umbraco.Core.Configuration.Grid;
|
|
||||||
using Umbraco.Core.Configuration.Models;
|
|
||||||
using Umbraco.Core.Dashboards;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
|
||||||
using Umbraco.Core.Dictionary;
|
|
||||||
using Umbraco.Core.Events;
|
|
||||||
using Umbraco.Core.Hosting;
|
|
||||||
using Umbraco.Core.Install;
|
|
||||||
using Umbraco.Core.Logging;
|
|
||||||
using Umbraco.Core.Manifest;
|
|
||||||
using Umbraco.Core.Media;
|
|
||||||
using Umbraco.Core.Migrations;
|
|
||||||
using Umbraco.Core.Migrations.Install;
|
|
||||||
using Umbraco.Core.Migrations.PostMigrations;
|
|
||||||
using Umbraco.Core.Models.PublishedContent;
|
|
||||||
using Umbraco.Core.Packaging;
|
|
||||||
using Umbraco.Core.Persistence;
|
|
||||||
using Umbraco.Core.PropertyEditors;
|
|
||||||
using Umbraco.Core.PropertyEditors.Validators;
|
|
||||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
|
||||||
using Umbraco.Core.Scoping;
|
|
||||||
using Umbraco.Core.Security;
|
|
||||||
using Umbraco.Core.Serialization;
|
|
||||||
using Umbraco.Core.Services;
|
|
||||||
using Umbraco.Core.Services.Implement;
|
|
||||||
using Umbraco.Core.Strings;
|
|
||||||
using Umbraco.Core.Sync;
|
|
||||||
using Umbraco.Core.Templates;
|
|
||||||
using Umbraco.Examine;
|
|
||||||
using Umbraco.Infrastructure.Examine;
|
|
||||||
using Umbraco.Infrastructure.Media;
|
|
||||||
using Umbraco.Web;
|
|
||||||
using Umbraco.Web.Actions;
|
|
||||||
using Umbraco.Web.Cache;
|
|
||||||
using Umbraco.Web.ContentApps;
|
|
||||||
using Umbraco.Web.Editors;
|
|
||||||
using Umbraco.Web.Features;
|
|
||||||
using Umbraco.Web.HealthCheck;
|
|
||||||
using Umbraco.Web.HealthCheck.NotificationMethods;
|
|
||||||
using Umbraco.Web.Install;
|
|
||||||
using Umbraco.Web.Media;
|
|
||||||
using Umbraco.Web.Media.EmbedProviders;
|
|
||||||
using Umbraco.Web.Migrations.PostMigrations;
|
|
||||||
using Umbraco.Web.Models.PublishedContent;
|
|
||||||
using Umbraco.Web.PropertyEditors;
|
|
||||||
using Umbraco.Web.PropertyEditors.ValueConverters;
|
|
||||||
using Umbraco.Web.PublishedCache;
|
|
||||||
using Umbraco.Web.Routing;
|
|
||||||
using Umbraco.Web.Search;
|
|
||||||
using Umbraco.Web.Sections;
|
|
||||||
using Umbraco.Web.Services;
|
|
||||||
using Umbraco.Web.Templates;
|
|
||||||
using Umbraco.Web.Trees;
|
|
||||||
using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter;
|
|
||||||
|
|
||||||
namespace Umbraco.Infrastructure.Runtime
|
|
||||||
{
|
|
||||||
public static class CoreInitialServices
|
|
||||||
{
|
|
||||||
public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder)
|
|
||||||
{
|
|
||||||
builder.AddNotificationHandler<UmbracoApplicationStarting, EssentialDirectoryCreator>();
|
|
||||||
|
|
||||||
builder.Services.AddSingleton<ManifestWatcher>();
|
|
||||||
builder.AddNotificationHandler<UmbracoApplicationStarting, AppPluginsManifestWatcherNotificationHandler>();
|
|
||||||
|
|
||||||
// composers
|
|
||||||
builder
|
|
||||||
.ComposeRepositories()
|
|
||||||
.ComposeServices()
|
|
||||||
.ComposeCoreMappingProfiles()
|
|
||||||
.ComposeFileSystems();
|
|
||||||
|
|
||||||
// register persistence mappers - required by database factory so needs to be done here
|
|
||||||
// means the only place the collection can be modified is in a runtime - afterwards it
|
|
||||||
// has been frozen and it is too late
|
|
||||||
builder.Mappers().AddCoreMappers();
|
|
||||||
|
|
||||||
// register the scope provider
|
|
||||||
builder.Services.AddUnique<ScopeProvider>(); // implements both IScopeProvider and IScopeAccessor
|
|
||||||
builder.Services.AddUnique<IScopeProvider>(f => f.GetRequiredService<ScopeProvider>());
|
|
||||||
builder.Services.AddUnique<IScopeAccessor>(f => f.GetRequiredService<ScopeProvider>());
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IJsonSerializer, JsonNetSerializer>();
|
|
||||||
builder.Services.AddUnique<IConfigurationEditorJsonSerializer, ConfigurationEditorJsonSerializer>();
|
|
||||||
builder.Services.AddUnique<IMenuItemCollectionFactory, MenuItemCollectionFactory>();
|
|
||||||
builder.Services.AddUnique<InstallStatusTracker>();
|
|
||||||
|
|
||||||
// register database builder
|
|
||||||
// *not* a singleton, don't want to keep it around
|
|
||||||
builder.Services.AddTransient<DatabaseBuilder>();
|
|
||||||
|
|
||||||
// register manifest parser, will be injected in collection builders where needed
|
|
||||||
builder.Services.AddUnique<IManifestParser, ManifestParser>();
|
|
||||||
|
|
||||||
// register our predefined validators
|
|
||||||
builder.ManifestValueValidators()
|
|
||||||
.Add<RequiredValidator>()
|
|
||||||
.Add<RegexValidator>()
|
|
||||||
.Add<DelimitedValueValidator>()
|
|
||||||
.Add<EmailValidator>()
|
|
||||||
.Add<IntegerValidator>()
|
|
||||||
.Add<DecimalValidator>();
|
|
||||||
|
|
||||||
// register the manifest filter collection builder (collection is empty by default)
|
|
||||||
builder.ManifestFilters();
|
|
||||||
|
|
||||||
// properties and parameters derive from data editors
|
|
||||||
builder.DataEditors()
|
|
||||||
.Add(() => builder.TypeLoader.GetDataEditors());
|
|
||||||
|
|
||||||
builder.MediaUrlGenerators()
|
|
||||||
.Add<FileUploadPropertyEditor>()
|
|
||||||
.Add<ImageCropperPropertyEditor>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<PropertyEditorCollection>();
|
|
||||||
builder.Services.AddUnique<ParameterEditorCollection>();
|
|
||||||
|
|
||||||
// Used to determine if a datatype/editor should be storing/tracking
|
|
||||||
// references to media item/s
|
|
||||||
builder.DataValueReferenceFactories();
|
|
||||||
|
|
||||||
// register a server registrar, by default it's the db registrar
|
|
||||||
builder.Services.AddUnique<IServerRegistrar>(f =>
|
|
||||||
{
|
|
||||||
var globalSettings = f.GetRequiredService<IOptions<GlobalSettings>>().Value;
|
|
||||||
|
|
||||||
// TODO: we still register the full IServerMessenger because
|
|
||||||
// even on 1 single server we can have 2 concurrent app domains
|
|
||||||
var singleServer = globalSettings.DisableElectionForSingleServer;
|
|
||||||
return singleServer
|
|
||||||
? (IServerRegistrar) new SingleServerRegistrar(f.GetRequiredService<IRequestAccessor>())
|
|
||||||
: new DatabaseServerRegistrar(
|
|
||||||
new Lazy<IServerRegistrationService>(f.GetRequiredService<IServerRegistrationService>));
|
|
||||||
});
|
|
||||||
|
|
||||||
// by default we'll use the database server messenger with default options (no callbacks),
|
|
||||||
// this will be overridden by the db thing in the corresponding components in the web
|
|
||||||
// project
|
|
||||||
builder.Services.AddUnique<IServerMessenger>(factory
|
|
||||||
=> new DatabaseServerMessenger(
|
|
||||||
factory.GetRequiredService<IMainDom>(),
|
|
||||||
factory.GetRequiredService<IScopeProvider>(),
|
|
||||||
factory.GetRequiredService<IUmbracoDatabaseFactory>(),
|
|
||||||
factory.GetRequiredService<IProfilingLogger>(),
|
|
||||||
factory.GetRequiredService<ILogger<DatabaseServerMessenger>>(),
|
|
||||||
factory.GetRequiredService<IServerRegistrar>(),
|
|
||||||
true,
|
|
||||||
new DatabaseServerMessengerCallbacks(),
|
|
||||||
factory.GetRequiredService<IHostingEnvironment>(),
|
|
||||||
factory.GetRequiredService<CacheRefresherCollection>(),
|
|
||||||
factory.GetRequiredService<IOptions<GlobalSettings>>()
|
|
||||||
));
|
|
||||||
|
|
||||||
builder.CacheRefreshers()
|
|
||||||
.Add(() => builder.TypeLoader.GetCacheRefreshers());
|
|
||||||
|
|
||||||
builder.PackageActions()
|
|
||||||
.Add(() => builder.TypeLoader.GetPackageActions());
|
|
||||||
|
|
||||||
builder.PropertyValueConverters()
|
|
||||||
.Append(builder.TypeLoader.GetTypes<IPropertyValueConverter>());
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IShortStringHelper>(factory
|
|
||||||
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService<IOptions<RequestHandlerSettings>>().Value)));
|
|
||||||
|
|
||||||
builder.UrlSegmentProviders()
|
|
||||||
.Append<DefaultUrlSegmentProvider>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IMigrationBuilder>(factory => new MigrationBuilder(factory));
|
|
||||||
|
|
||||||
// by default, register a noop factory
|
|
||||||
builder.Services.AddUnique<IPublishedModelFactory, NoopPublishedModelFactory>();
|
|
||||||
|
|
||||||
// by default
|
|
||||||
builder.Services.AddUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
|
|
||||||
|
|
||||||
builder.SetCultureDictionaryFactory<DefaultCultureDictionaryFactory>();
|
|
||||||
builder.Services.AddSingleton(f => f.GetRequiredService<ICultureDictionaryFactory>().CreateDictionary());
|
|
||||||
builder.Services.AddUnique<UriUtility>();
|
|
||||||
|
|
||||||
// register the published snapshot accessor - the "current" published snapshot is in the umbraco context
|
|
||||||
builder.Services.AddUnique<IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IVariationContextAccessor, HybridVariationContextAccessor>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IDashboardService, DashboardService>();
|
|
||||||
|
|
||||||
// register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards
|
|
||||||
builder.Dashboards()
|
|
||||||
.Add(builder.TypeLoader.GetTypes<IDashboard>());
|
|
||||||
|
|
||||||
// will be injected in controllers when needed to invoke rest endpoints on Our
|
|
||||||
builder.Services.AddUnique<IInstallationService, InstallationService>();
|
|
||||||
builder.Services.AddUnique<IUpgradeService, UpgradeService>();
|
|
||||||
|
|
||||||
// Grid config is not a real config file as we know them
|
|
||||||
builder.Services.AddUnique<IGridConfig, GridConfig>();
|
|
||||||
|
|
||||||
// Config manipulator
|
|
||||||
builder.Services.AddUnique<IConfigManipulator, JsonConfigManipulator>();
|
|
||||||
|
|
||||||
// register the umbraco context factory
|
|
||||||
// composition.Services.AddUnique<IUmbracoContextFactory, UmbracoContextFactory>();
|
|
||||||
builder.Services.AddUnique<IPublishedUrlProvider, UrlProvider>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<HtmlLocalLinkParser>();
|
|
||||||
builder.Services.AddUnique<HtmlImageSourceParser>();
|
|
||||||
builder.Services.AddUnique<HtmlUrlParser>();
|
|
||||||
builder.Services.AddUnique<RichTextEditorPastedImages>();
|
|
||||||
builder.Services.AddUnique<BlockEditorConverter>();
|
|
||||||
|
|
||||||
// both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be
|
|
||||||
// discovered when CoreBootManager configures the converters. We HAVE to remove one of them
|
|
||||||
// here because there cannot be two converters for one property editor - and we want the full
|
|
||||||
// RteMacroRenderingValueConverter that converts macros, etc. So remove TinyMceValueConverter.
|
|
||||||
// (the limited one, defined in Core, is there for tests) - same for others
|
|
||||||
builder.PropertyValueConverters()
|
|
||||||
.Remove<TinyMceValueConverter>()
|
|
||||||
.Remove<TextStringValueConverter>()
|
|
||||||
.Remove<MarkdownEditorValueConverter>();
|
|
||||||
|
|
||||||
builder.UrlProviders()
|
|
||||||
.Append<AliasUrlProvider>()
|
|
||||||
.Append<DefaultUrlProvider>();
|
|
||||||
|
|
||||||
builder.MediaUrlProviders()
|
|
||||||
.Append<DefaultMediaUrlProvider>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<ISiteDomainHelper, SiteDomainHelper>();
|
|
||||||
|
|
||||||
// register properties fallback
|
|
||||||
builder.Services.AddUnique<IPublishedValueFallback, PublishedValueFallback>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<UmbracoFeatures>();
|
|
||||||
|
|
||||||
builder.Actions()
|
|
||||||
.Add(() => builder.TypeLoader.GetTypes<IAction>());
|
|
||||||
|
|
||||||
builder.EditorValidators()
|
|
||||||
.Add(() => builder.TypeLoader.GetTypes<IEditorValidator>());
|
|
||||||
|
|
||||||
|
|
||||||
builder.TourFilters();
|
|
||||||
|
|
||||||
// replace with web implementation
|
|
||||||
builder.Services.AddUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
|
|
||||||
|
|
||||||
// register OEmbed providers - no type scanning - all explicit opt-in of adding types
|
|
||||||
// note: IEmbedProvider is not IDiscoverable - think about it if going for type scanning
|
|
||||||
builder.OEmbedProviders()
|
|
||||||
.Append<YouTube>()
|
|
||||||
.Append<Twitter>()
|
|
||||||
.Append<Vimeo>()
|
|
||||||
.Append<DailyMotion>()
|
|
||||||
.Append<Flickr>()
|
|
||||||
.Append<Slideshare>()
|
|
||||||
.Append<Kickstarter>()
|
|
||||||
.Append<GettyImages>()
|
|
||||||
.Append<Ted>()
|
|
||||||
.Append<Soundcloud>()
|
|
||||||
.Append<Issuu>()
|
|
||||||
.Append<Hulu>()
|
|
||||||
.Append<Giphy>();
|
|
||||||
|
|
||||||
// register back office sections in the order we want them rendered
|
|
||||||
builder.Sections()
|
|
||||||
.Append<ContentSection>()
|
|
||||||
.Append<MediaSection>()
|
|
||||||
.Append<SettingsSection>()
|
|
||||||
.Append<PackagesSection>()
|
|
||||||
.Append<UsersSection>()
|
|
||||||
.Append<MembersSection>()
|
|
||||||
.Append<FormsSection>()
|
|
||||||
.Append<TranslationSection>();
|
|
||||||
|
|
||||||
// register known content apps
|
|
||||||
builder.ContentApps()
|
|
||||||
.Append<ListViewContentAppFactory>()
|
|
||||||
.Append<ContentEditorContentAppFactory>()
|
|
||||||
.Append<ContentInfoContentAppFactory>()
|
|
||||||
.Append<ContentTypeDesignContentAppFactory>()
|
|
||||||
.Append<ContentTypeListViewContentAppFactory>()
|
|
||||||
.Append<ContentTypePermissionsContentAppFactory>()
|
|
||||||
.Append<ContentTypeTemplatesContentAppFactory>();
|
|
||||||
|
|
||||||
// register published router
|
|
||||||
builder.Services.AddUnique<IPublishedRouter, PublishedRouter>();
|
|
||||||
|
|
||||||
// register *all* checks, except those marked [HideFromTypeFinder] of course
|
|
||||||
builder.Services.AddUnique<IMarkdownToHtmlConverter, MarkdownToHtmlConverter>();
|
|
||||||
builder.HealthChecks()
|
|
||||||
.Add(() => builder.TypeLoader.GetTypes<Core.HealthCheck.HealthCheck>());
|
|
||||||
|
|
||||||
builder.WithCollectionBuilder<HealthCheckNotificationMethodCollectionBuilder>()
|
|
||||||
.Add(() => builder.TypeLoader.GetTypes<IHealthCheckNotificationMethod>());
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IContentLastChanceFinder, ContentFinderByConfigured404>();
|
|
||||||
|
|
||||||
builder.ContentFinders()
|
|
||||||
// all built-in finders in the correct order,
|
|
||||||
// devs can then modify this list on application startup
|
|
||||||
.Append<ContentFinderByPageIdQuery>()
|
|
||||||
.Append<ContentFinderByUrl>()
|
|
||||||
.Append<ContentFinderByIdPath>()
|
|
||||||
//.Append<ContentFinderByUrlAndTemplate>() // disabled, this is an odd finder
|
|
||||||
.Append<ContentFinderByUrlAlias>()
|
|
||||||
.Append<ContentFinderByRedirectUrl>();
|
|
||||||
|
|
||||||
builder.Services.AddScoped<UmbracoTreeSearcher>();
|
|
||||||
|
|
||||||
builder.SearchableTrees()
|
|
||||||
.Add(() => builder.TypeLoader.GetTypes<ISearchableTree>());
|
|
||||||
|
|
||||||
// replace some services
|
|
||||||
builder.Services.AddUnique<IEventMessagesFactory, DefaultEventMessagesFactory>();
|
|
||||||
builder.Services.AddUnique<IEventMessagesAccessor, HybridEventMessagesAccessor>();
|
|
||||||
builder.Services.AddUnique<ITreeService, TreeService>();
|
|
||||||
builder.Services.AddUnique<ISectionService, SectionService>();
|
|
||||||
builder.Services.AddUnique<IEmailSender, EmailSender>();
|
|
||||||
builder.Services.AddUnique<ISmsSender, NotImplementedSmsSender>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IExamineManager, ExamineManager>();
|
|
||||||
|
|
||||||
// register distributed cache
|
|
||||||
builder.Services.AddUnique(f => new DistributedCache(f.GetRequiredService<IServerMessenger>(), f.GetRequiredService<CacheRefresherCollection>()));
|
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddScoped<ITagQuery, TagQuery>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<HtmlLocalLinkParser>();
|
|
||||||
builder.Services.AddUnique<HtmlUrlParser>();
|
|
||||||
builder.Services.AddUnique<HtmlImageSourceParser>();
|
|
||||||
builder.Services.AddUnique<RichTextEditorPastedImages>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IUmbracoTreeSearcherFields, UmbracoTreeSearcherFields>();
|
|
||||||
builder.Services.AddScoped<IPublishedContentQuery>(factory =>
|
|
||||||
{
|
|
||||||
var umbCtx = factory.GetRequiredService<IUmbracoContextAccessor>();
|
|
||||||
return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService<IVariationContextAccessor>(), factory.GetRequiredService<IExamineManager>());
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IPublishedUrlProvider, UrlProvider>();
|
|
||||||
|
|
||||||
// register the http context and umbraco context accessors
|
|
||||||
// we *should* use the HttpContextUmbracoContextAccessor, however there are cases when
|
|
||||||
// we have no http context, eg when booting Umbraco or in background threads, so instead
|
|
||||||
// let's use an hybrid accessor that can fall back to a ThreadStatic context.
|
|
||||||
builder.Services.AddUnique<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
|
|
||||||
|
|
||||||
// register accessors for cultures
|
|
||||||
builder.Services.AddUnique<IDefaultCultureAccessor, DefaultCultureAccessor>();
|
|
||||||
|
|
||||||
builder.Services.AddSingleton<IFilePermissionHelper, FilePermissionHelper>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<IUmbracoComponentRenderer, UmbracoComponentRenderer>();
|
|
||||||
|
|
||||||
// Register noop versions for examine to be overridden by examine
|
|
||||||
builder.Services.AddUnique<IUmbracoIndexesCreator, NoopUmbracoIndexesCreator>();
|
|
||||||
builder.Services.AddUnique<IBackOfficeExamineSearcher, NoopBackOfficeExamineSearcher>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<UploadAutoFillProperties>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<ICronTabParser, NCronTabParser>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique(factory => new LegacyPasswordSecurity());
|
|
||||||
builder.Services.AddUnique<UserEditorAuthorizationHelper>();
|
|
||||||
builder.Services.AddUnique<ContentPermissions>();
|
|
||||||
|
|
||||||
builder.Services.AddUnique<MediaPermissions>();
|
|
||||||
builder.Services.AddUnique<IImageDimensionExtractor, ImageDimensionExtractor>();
|
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddUnique<PackageDataInstallation>();
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
using Umbraco.Core.Persistence;
|
using Umbraco.Core.Persistence;
|
||||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Scoping
|
|||||||
/// Provides scopes.
|
/// Provides scopes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IScopeProvider
|
public interface IScopeProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an ambient scope.
|
/// Creates an ambient scope.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.DependencyInjection;
|
using Umbraco.Core.DependencyInjection;
|
||||||
using Umbraco.Core.Composing;
|
using Umbraco.Core.Composing;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ using Umbraco.Core.Models;
|
|||||||
using Umbraco.Core.Models.Entities;
|
using Umbraco.Core.Models.Entities;
|
||||||
using Umbraco.Core.Persistence;
|
using Umbraco.Core.Persistence;
|
||||||
using Umbraco.Core.Services;
|
using Umbraco.Core.Services;
|
||||||
|
using Umbraco.Core.Trees;
|
||||||
using Umbraco.Examine;
|
using Umbraco.Examine;
|
||||||
using Umbraco.Web.Models.ContentEditing;
|
using Umbraco.Web.Models.ContentEditing;
|
||||||
using Umbraco.Web.Models.Mapping;
|
using Umbraco.Web.Models.Mapping;
|
||||||
using Umbraco.Web.Routing;
|
using Umbraco.Web.Routing;
|
||||||
using Umbraco.Web.Trees;
|
|
||||||
|
|
||||||
namespace Umbraco.Web.Search
|
namespace Umbraco.Web.Search
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Umbraco.Core.Models.Entities;
|
|||||||
using Umbraco.Core.Models.Membership;
|
using Umbraco.Core.Models.Membership;
|
||||||
using Umbraco.Core.Persistence.Repositories;
|
using Umbraco.Core.Persistence.Repositories;
|
||||||
using Umbraco.Core.Scoping;
|
using Umbraco.Core.Scoping;
|
||||||
|
using Umbraco.Core.Mail;
|
||||||
|
|
||||||
namespace Umbraco.Core.Services.Implement
|
namespace Umbraco.Core.Services.Implement
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Umbraco.Core.Composing;
|
|
||||||
using Umbraco.Core.Events;
|
using Umbraco.Core.Events;
|
||||||
using Umbraco.Core.Hosting;
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.Models;
|
using Umbraco.Core.Models;
|
||||||
@@ -26,11 +25,12 @@ namespace Umbraco.Core.Services.Implement
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ServerRegistrationService"/> class.
|
/// Initializes a new instance of the <see cref="ServerRegistrationService"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scopeProvider">A UnitOfWork provider.</param>
|
public ServerRegistrationService(
|
||||||
/// <param name="loggerFactory">A logger factory</param>
|
IScopeProvider scopeProvider,
|
||||||
/// <param name="eventMessagesFactory"></param>
|
ILoggerFactory loggerFactory,
|
||||||
public ServerRegistrationService(IScopeProvider scopeProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory,
|
IEventMessagesFactory eventMessagesFactory,
|
||||||
IServerRegistrationRepository serverRegistrationRepository, IHostingEnvironment hostingEnvironment)
|
IServerRegistrationRepository serverRegistrationRepository,
|
||||||
|
IHostingEnvironment hostingEnvironment)
|
||||||
: base(scopeProvider, loggerFactory, eventMessagesFactory)
|
: base(scopeProvider, loggerFactory, eventMessagesFactory)
|
||||||
{
|
{
|
||||||
_serverRegistrationRepository = serverRegistrationRepository;
|
_serverRegistrationRepository = serverRegistrationRepository;
|
||||||
@@ -41,10 +41,10 @@ namespace Umbraco.Core.Services.Implement
|
|||||||
/// Touches a server to mark it as active; deactivate stale servers.
|
/// Touches a server to mark it as active; deactivate stale servers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serverAddress">The server URL.</param>
|
/// <param name="serverAddress">The server URL.</param>
|
||||||
/// <param name="serverIdentity">The server unique identity.</param>
|
|
||||||
/// <param name="staleTimeout">The time after which a server is considered stale.</param>
|
/// <param name="staleTimeout">The time after which a server is considered stale.</param>
|
||||||
public void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout)
|
public void TouchServer(string serverAddress, TimeSpan staleTimeout)
|
||||||
{
|
{
|
||||||
|
var serverIdentity = GetCurrentServerIdentity();
|
||||||
using (var scope = ScopeProvider.CreateScope())
|
using (var scope = ScopeProvider.CreateScope())
|
||||||
{
|
{
|
||||||
scope.WriteLock(Constants.Locks.Servers);
|
scope.WriteLock(Constants.Locks.Servers);
|
||||||
@@ -144,19 +144,16 @@ namespace Umbraco.Core.Services.Implement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the local server identity.
|
|
||||||
/// </summary>
|
|
||||||
public string CurrentServerIdentity => NetworkHelper.MachineName // eg DOMAIN\SERVER
|
|
||||||
+ "/" + _hostingEnvironment.ApplicationId; // eg /LM/S3SVC/11/ROOT;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the role of the current server.
|
/// Gets the role of the current server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The role of the current server.</returns>
|
/// <returns>The role of the current server.</returns>
|
||||||
public ServerRole GetCurrentServerRole()
|
public ServerRole GetCurrentServerRole() => _currentServerRole;
|
||||||
{
|
|
||||||
return _currentServerRole;
|
/// <summary>
|
||||||
}
|
/// Gets the local server identity.
|
||||||
|
/// </summary>
|
||||||
|
private string GetCurrentServerIdentity() => NetworkHelper.MachineName // eg DOMAIN\SERVER
|
||||||
|
+ "/" + _hostingEnvironment.ApplicationId; // eg /LM/S3SVC/11/ROOT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,104 +1,83 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Umbraco.Core;
|
|
||||||
using Umbraco.Core.Cache;
|
using Umbraco.Core.Cache;
|
||||||
using Umbraco.Core.Configuration.Models;
|
using Umbraco.Core.Configuration.Models;
|
||||||
using Umbraco.Core.Hosting;
|
using Umbraco.Core.Hosting;
|
||||||
using Umbraco.Core.Logging;
|
using Umbraco.Core.Logging;
|
||||||
using Umbraco.Core.Persistence;
|
|
||||||
using Umbraco.Core.Persistence.Dtos;
|
using Umbraco.Core.Persistence.Dtos;
|
||||||
using Umbraco.Core.Scoping;
|
using Umbraco.Core.Scoping;
|
||||||
using Umbraco.Core.Sync;
|
using Umbraco.Web;
|
||||||
using Umbraco.Web.Routing;
|
|
||||||
|
|
||||||
namespace Umbraco.Web
|
namespace Umbraco.Core.Sync
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IServerMessenger"/> implementation that works by storing messages in the database.
|
/// An <see cref="IServerMessenger"/> implementation that works by storing messages in the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
|
||||||
/// This binds to appropriate umbraco events in order to trigger the Boot(), Sync() & FlushBatch() calls
|
|
||||||
/// </remarks>
|
|
||||||
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger, IBatchedDatabaseServerMessenger
|
|
||||||
{
|
{
|
||||||
private readonly IUmbracoDatabaseFactory _databaseFactory;
|
|
||||||
private readonly IRequestCache _requestCache;
|
private readonly IRequestCache _requestCache;
|
||||||
private readonly IRequestAccessor _requestAccessor;
|
private readonly IRequestAccessor _requestAccessor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BatchedDatabaseServerMessenger"/> class.
|
||||||
|
/// </summary>
|
||||||
public BatchedDatabaseServerMessenger(
|
public BatchedDatabaseServerMessenger(
|
||||||
IMainDom mainDom,
|
IMainDom mainDom,
|
||||||
IUmbracoDatabaseFactory databaseFactory,
|
|
||||||
IScopeProvider scopeProvider,
|
IScopeProvider scopeProvider,
|
||||||
IProfilingLogger proflog,
|
IProfilingLogger proflog,
|
||||||
ILogger<BatchedDatabaseServerMessenger> logger,
|
ILogger<BatchedDatabaseServerMessenger> logger,
|
||||||
IServerRegistrar serverRegistrar,
|
IServerRoleAccessor serverRegistrar,
|
||||||
DatabaseServerMessengerCallbacks callbacks,
|
DatabaseServerMessengerCallbacks callbacks,
|
||||||
IHostingEnvironment hostingEnvironment,
|
IHostingEnvironment hostingEnvironment,
|
||||||
CacheRefresherCollection cacheRefreshers,
|
CacheRefresherCollection cacheRefreshers,
|
||||||
IRequestCache requestCache,
|
IRequestCache requestCache,
|
||||||
IRequestAccessor requestAccessor,
|
IRequestAccessor requestAccessor,
|
||||||
IOptions<GlobalSettings> globalSettings)
|
IOptions<GlobalSettings> globalSettings)
|
||||||
: base(mainDom, scopeProvider, databaseFactory, proflog, logger, serverRegistrar, true, callbacks, hostingEnvironment, cacheRefreshers, globalSettings)
|
: base(mainDom, scopeProvider, proflog, logger, serverRegistrar, true, callbacks, hostingEnvironment, cacheRefreshers, globalSettings)
|
||||||
{
|
{
|
||||||
_databaseFactory = databaseFactory;
|
|
||||||
_requestCache = requestCache;
|
_requestCache = requestCache;
|
||||||
_requestAccessor = requestAccessor;
|
_requestAccessor = requestAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invoked by DatabaseServerRegistrarAndMessengerComponent
|
/// <inheritdoc/>
|
||||||
public void Startup()
|
|
||||||
{
|
|
||||||
_requestAccessor.EndRequest += UmbracoModule_EndRequest;
|
|
||||||
|
|
||||||
if (_databaseFactory.CanConnect == false)
|
|
||||||
{
|
|
||||||
Logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Boot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UmbracoModule_EndRequest(object sender, UmbracoRequestEventArgs e)
|
|
||||||
{
|
|
||||||
// will clear the batch - will remain in HttpContext though - that's ok
|
|
||||||
FlushBatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable<object> ids = null, string json = null)
|
protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable<object> ids = null, string json = null)
|
||||||
{
|
{
|
||||||
var idsA = ids?.ToArray();
|
var idsA = ids?.ToArray();
|
||||||
|
|
||||||
Type arrayType;
|
if (GetArrayType(idsA, out Type arrayType) == false)
|
||||||
if (GetArrayType(idsA, out arrayType) == false)
|
{
|
||||||
throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids));
|
throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids));
|
||||||
|
}
|
||||||
|
|
||||||
BatchMessage(refresher, messageType, idsA, arrayType, json);
|
BatchMessage(refresher, messageType, idsA, arrayType, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FlushBatch()
|
/// <inheritdoc/>
|
||||||
|
public override void SendMessages()
|
||||||
{
|
{
|
||||||
var batch = GetBatch(false);
|
ICollection<RefreshInstructionEnvelope> batch = GetBatch(false);
|
||||||
if (batch == null) return;
|
if (batch == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var instructions = batch.SelectMany(x => x.Instructions).ToArray();
|
RefreshInstruction[] instructions = batch.SelectMany(x => x.Instructions).ToArray();
|
||||||
batch.Clear();
|
batch.Clear();
|
||||||
|
|
||||||
//Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
|
// Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
|
||||||
using (var scope = ScopeProvider.CreateScope())
|
using (IScope scope = ScopeProvider.CreateScope())
|
||||||
{
|
{
|
||||||
foreach (var instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount))
|
foreach (IEnumerable<RefreshInstruction> instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount))
|
||||||
{
|
{
|
||||||
WriteInstructions(scope, instructionsBatch);
|
WriteInstructions(scope, instructionsBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Complete();
|
scope.Complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
|
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
|
||||||
@@ -113,11 +92,14 @@ namespace Umbraco.Web
|
|||||||
scope.Database.Insert(dto);
|
scope.Database.Insert(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
|
private ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
|
||||||
{
|
{
|
||||||
var key = nameof(BatchedDatabaseServerMessenger);
|
var key = nameof(BatchedDatabaseServerMessenger);
|
||||||
|
|
||||||
if (!_requestCache.IsAvailable) return null;
|
if (!_requestCache.IsAvailable)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// no thread-safety here because it'll run in only 1 thread (request) at a time
|
// no thread-safety here because it'll run in only 1 thread (request) at a time
|
||||||
var batch = (ICollection<RefreshInstructionEnvelope>)_requestCache.Get(key);
|
var batch = (ICollection<RefreshInstructionEnvelope>)_requestCache.Get(key);
|
||||||
@@ -130,26 +112,27 @@ namespace Umbraco.Web
|
|||||||
return batch;
|
return batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void BatchMessage(
|
private void BatchMessage(
|
||||||
ICacheRefresher refresher,
|
ICacheRefresher refresher,
|
||||||
MessageType messageType,
|
MessageType messageType,
|
||||||
IEnumerable<object> ids = null,
|
IEnumerable<object> ids = null,
|
||||||
Type idType = null,
|
Type idType = null,
|
||||||
string json = null)
|
string json = null)
|
||||||
{
|
{
|
||||||
var batch = GetBatch(true);
|
ICollection<RefreshInstructionEnvelope> batch = GetBatch(true);
|
||||||
var instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json);
|
IEnumerable<RefreshInstruction> instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json);
|
||||||
|
|
||||||
// batch if we can, else write to DB immediately
|
// batch if we can, else write to DB immediately
|
||||||
if (batch == null)
|
if (batch == null)
|
||||||
{
|
{
|
||||||
//only write the json blob with a maximum count of the MaxProcessingInstructionCount
|
// only write the json blob with a maximum count of the MaxProcessingInstructionCount
|
||||||
using (var scope = ScopeProvider.CreateScope())
|
using (IScope scope = ScopeProvider.CreateScope())
|
||||||
{
|
{
|
||||||
foreach (var maxBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount))
|
foreach (IEnumerable<RefreshInstruction> maxBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount))
|
||||||
{
|
{
|
||||||
WriteInstructions(scope, maxBatch);
|
WriteInstructions(scope, maxBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Complete();
|
scope.Complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,19 +23,21 @@ namespace Umbraco.Core.Sync
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IServerMessenger"/> that works by storing messages in the database.
|
/// An <see cref="IServerMessenger"/> that works by storing messages in the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//
|
public abstract class DatabaseServerMessenger : ServerMessengerBase
|
||||||
// this messenger writes ALL instructions to the database,
|
|
||||||
// but only processes instructions coming from remote servers,
|
|
||||||
// thus ensuring that instructions run only once
|
|
||||||
//
|
|
||||||
public class DatabaseServerMessenger : ServerMessengerBase, IDatabaseServerMessenger
|
|
||||||
{
|
{
|
||||||
|
// TODO: This class needs to be split into a service/repo for DB access
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this messenger writes ALL instructions to the database,
|
||||||
|
* but only processes instructions coming from remote servers,
|
||||||
|
* thus ensuring that instructions run only once
|
||||||
|
*/
|
||||||
|
|
||||||
private readonly IMainDom _mainDom;
|
private readonly IMainDom _mainDom;
|
||||||
private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory;
|
|
||||||
private readonly ManualResetEvent _syncIdle;
|
private readonly ManualResetEvent _syncIdle;
|
||||||
private readonly object _locko = new object();
|
private readonly object _locko = new object();
|
||||||
private readonly IProfilingLogger _profilingLogger;
|
private readonly IProfilingLogger _profilingLogger;
|
||||||
private readonly IServerRegistrar _serverRegistrar;
|
private readonly IServerRoleAccessor _serverRegistrar;
|
||||||
private readonly IHostingEnvironment _hostingEnvironment;
|
private readonly IHostingEnvironment _hostingEnvironment;
|
||||||
private readonly CacheRefresherCollection _cacheRefreshers;
|
private readonly CacheRefresherCollection _cacheRefreshers;
|
||||||
|
|
||||||
@@ -43,22 +45,28 @@ namespace Umbraco.Core.Sync
|
|||||||
private int _lastId = -1;
|
private int _lastId = -1;
|
||||||
private DateTime _lastSync;
|
private DateTime _lastSync;
|
||||||
private DateTime _lastPruned;
|
private DateTime _lastPruned;
|
||||||
private bool _initialized;
|
private readonly Lazy<bool> _initialized;
|
||||||
private bool _syncing;
|
private bool _syncing;
|
||||||
private bool _released;
|
private bool _released;
|
||||||
|
|
||||||
public DatabaseServerMessengerCallbacks Callbacks { get; }
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DatabaseServerMessenger"/> class.
|
||||||
public GlobalSettings GlobalSettings { get; }
|
/// </summary>
|
||||||
|
protected DatabaseServerMessenger(
|
||||||
public DatabaseServerMessenger(
|
IMainDom mainDom,
|
||||||
IMainDom mainDom, IScopeProvider scopeProvider, IUmbracoDatabaseFactory umbracoDatabaseFactory, IProfilingLogger proflog, ILogger<DatabaseServerMessenger> logger, IServerRegistrar serverRegistrar,
|
IScopeProvider scopeProvider,
|
||||||
bool distributedEnabled, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IOptions<GlobalSettings> globalSettings)
|
IProfilingLogger proflog,
|
||||||
|
ILogger<DatabaseServerMessenger> logger,
|
||||||
|
IServerRoleAccessor serverRegistrar,
|
||||||
|
bool distributedEnabled,
|
||||||
|
DatabaseServerMessengerCallbacks callbacks,
|
||||||
|
IHostingEnvironment hostingEnvironment,
|
||||||
|
CacheRefresherCollection cacheRefreshers,
|
||||||
|
IOptions<GlobalSettings> globalSettings)
|
||||||
: base(distributedEnabled)
|
: base(distributedEnabled)
|
||||||
{
|
{
|
||||||
ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider));
|
ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider));
|
||||||
_mainDom = mainDom;
|
_mainDom = mainDom;
|
||||||
_umbracoDatabaseFactory = umbracoDatabaseFactory;
|
|
||||||
_profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog));
|
_profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog));
|
||||||
_serverRegistrar = serverRegistrar;
|
_serverRegistrar = serverRegistrar;
|
||||||
_hostingEnvironment = hostingEnvironment;
|
_hostingEnvironment = hostingEnvironment;
|
||||||
@@ -76,24 +84,28 @@ namespace Umbraco.Core.Sync
|
|||||||
+ " [P" + Process.GetCurrentProcess().Id // eg 1234
|
+ " [P" + Process.GetCurrentProcess().Id // eg 1234
|
||||||
+ "/D" + AppDomain.CurrentDomain.Id // eg 22
|
+ "/D" + AppDomain.CurrentDomain.Id // eg 22
|
||||||
+ "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique
|
+ "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique
|
||||||
|
|
||||||
|
_initialized = new Lazy<bool>(EnsureInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DatabaseServerMessengerCallbacks Callbacks { get; }
|
||||||
|
|
||||||
|
public GlobalSettings GlobalSettings { get; }
|
||||||
|
|
||||||
protected ILogger<DatabaseServerMessenger> Logger { get; }
|
protected ILogger<DatabaseServerMessenger> Logger { get; }
|
||||||
|
|
||||||
protected IScopeProvider ScopeProvider { get; }
|
protected IScopeProvider ScopeProvider { get; }
|
||||||
|
|
||||||
protected Sql<ISqlContext> Sql() => _umbracoDatabaseFactory.SqlContext.Sql();
|
protected Sql<ISqlContext> Sql() => ScopeProvider.SqlContext.Sql();
|
||||||
|
|
||||||
private string DistCacheFilePath => _distCacheFilePath.Value;
|
private string DistCacheFilePath => _distCacheFilePath.Value;
|
||||||
|
|
||||||
#region Messenger
|
#region Messenger
|
||||||
|
|
||||||
|
// we don't care if there's servers listed or not,
|
||||||
|
// if distributed call is enabled we will make the call
|
||||||
protected override bool RequiresDistributed(ICacheRefresher refresher, MessageType dispatchType)
|
protected override bool RequiresDistributed(ICacheRefresher refresher, MessageType dispatchType)
|
||||||
{
|
=> _initialized.Value && DistributedEnabled;
|
||||||
// we don't care if there's servers listed or not,
|
|
||||||
// if distributed call is enabled we will make the call
|
|
||||||
return _initialized && DistributedEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DeliverRemote(
|
protected override void DeliverRemote(
|
||||||
ICacheRefresher refresher,
|
ICacheRefresher refresher,
|
||||||
@@ -104,7 +116,9 @@ namespace Umbraco.Core.Sync
|
|||||||
var idsA = ids?.ToArray();
|
var idsA = ids?.ToArray();
|
||||||
|
|
||||||
if (GetArrayType(idsA, out var idType) == false)
|
if (GetArrayType(idsA, out var idType) == false)
|
||||||
|
{
|
||||||
throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids));
|
throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids));
|
||||||
|
}
|
||||||
|
|
||||||
var instructions = RefreshInstruction.GetInstructions(refresher, messageType, idsA, idType, json);
|
var instructions = RefreshInstruction.GetInstructions(refresher, messageType, idsA, idType, json);
|
||||||
|
|
||||||
@@ -130,17 +144,12 @@ namespace Umbraco.Core.Sync
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Boots the messenger.
|
/// Boots the messenger.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
private bool EnsureInitialized()
|
||||||
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
|
||||||
/// Callers MUST ensure thread-safety.
|
|
||||||
/// </remarks>
|
|
||||||
protected void Boot()
|
|
||||||
{
|
{
|
||||||
// weight:10, must release *before* the published snapshot service, because once released
|
// weight:10, must release *before* the published snapshot service, because once released
|
||||||
// the service will *not* be able to properly handle our notifications anymore
|
// the service will *not* be able to properly handle our notifications anymore
|
||||||
const int weight = 10;
|
const int weight = 10;
|
||||||
|
|
||||||
|
|
||||||
var registered = _mainDom.Register(
|
var registered = _mainDom.Register(
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
@@ -154,7 +163,7 @@ namespace Umbraco.Core.Sync
|
|||||||
// properly releasing MainDom - a timeout here means that one refresher
|
// properly releasing MainDom - a timeout here means that one refresher
|
||||||
// is taking too much time processing, however when it's done we will
|
// is taking too much time processing, however when it's done we will
|
||||||
// not update lastId and stop everything
|
// not update lastId and stop everything
|
||||||
var idle =_syncIdle.WaitOne(5000);
|
var idle = _syncIdle.WaitOne(5000);
|
||||||
if (idle == false)
|
if (idle == false)
|
||||||
{
|
{
|
||||||
Logger.LogWarning("The wait lock timed out, application is shutting down. The current instruction batch will be re-processed.");
|
Logger.LogWarning("The wait lock timed out, application is shutting down. The current instruction batch will be re-processed.");
|
||||||
@@ -163,15 +172,16 @@ namespace Umbraco.Core.Sync
|
|||||||
weight);
|
weight);
|
||||||
|
|
||||||
if (registered == false)
|
if (registered == false)
|
||||||
return;
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ReadLastSynced(); // get _lastId
|
ReadLastSynced(); // get _lastId
|
||||||
using (var scope = ScopeProvider.CreateScope())
|
|
||||||
|
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||||
{
|
{
|
||||||
EnsureInstructions(scope.Database); // reset _lastId if instructions are missing
|
EnsureInstructions(scope.Database); // reset _lastId if instructions are missing
|
||||||
Initialize(scope.Database); // boot
|
return Initialize(scope.Database); // boot
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,14 +192,19 @@ namespace Umbraco.Core.Sync
|
|||||||
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
||||||
/// Callers MUST ensure thread-safety.
|
/// Callers MUST ensure thread-safety.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void Initialize(IUmbracoDatabase database)
|
private bool Initialize(IUmbracoDatabase database)
|
||||||
{
|
{
|
||||||
lock (_locko)
|
lock (_locko)
|
||||||
{
|
{
|
||||||
if (_released) return;
|
if (_released)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var coldboot = false;
|
var coldboot = false;
|
||||||
if (_lastId < 0) // never synced before
|
|
||||||
|
// never synced before
|
||||||
|
if (_lastId < 0)
|
||||||
{
|
{
|
||||||
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
|
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
|
||||||
// server and it will need to rebuild it's own caches, eg Lucene or the xml cache file.
|
// server and it will need to rebuild it's own caches, eg Lucene or the xml cache file.
|
||||||
@@ -201,12 +216,12 @@ namespace Umbraco.Core.Sync
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//check for how many instructions there are to process, each row contains a count of the number of instructions contained in each
|
// check for how many instructions there are to process, each row contains a count of the number of instructions contained in each
|
||||||
//row so we will sum these numbers to get the actual count.
|
// row so we will sum these numbers to get the actual count.
|
||||||
var count = database.ExecuteScalar<int>("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId});
|
var count = database.ExecuteScalar<int>("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new { lastId = _lastId });
|
||||||
if (count > GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)
|
if (count > GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)
|
||||||
{
|
{
|
||||||
//too many instructions, proceed to cold boot
|
// too many instructions, proceed to cold boot
|
||||||
Logger.LogWarning(
|
Logger.LogWarning(
|
||||||
"The instruction count ({InstructionCount}) exceeds the specified MaxProcessingInstructionCount ({MaxProcessingInstructionCount})."
|
"The instruction count ({InstructionCount}) exceeds the specified MaxProcessingInstructionCount ({MaxProcessingInstructionCount})."
|
||||||
+ " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id"
|
+ " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id"
|
||||||
@@ -224,38 +239,55 @@ namespace Umbraco.Core.Sync
|
|||||||
// when doing it before, some instructions might run twice - not an issue
|
// when doing it before, some instructions might run twice - not an issue
|
||||||
var maxId = database.ExecuteScalar<int>("SELECT MAX(id) FROM umbracoCacheInstruction");
|
var maxId = database.ExecuteScalar<int>("SELECT MAX(id) FROM umbracoCacheInstruction");
|
||||||
|
|
||||||
//if there is a max currently, or if we've never synced
|
// if there is a max currently, or if we've never synced
|
||||||
if (maxId > 0 || _lastId < 0)
|
if (maxId > 0 || _lastId < 0)
|
||||||
|
{
|
||||||
SaveLastSynced(maxId);
|
SaveLastSynced(maxId);
|
||||||
|
}
|
||||||
|
|
||||||
// execute initializing callbacks
|
// execute initializing callbacks
|
||||||
if (Callbacks.InitializingCallbacks != null)
|
if (Callbacks.InitializingCallbacks != null)
|
||||||
|
{
|
||||||
foreach (var callback in Callbacks.InitializingCallbacks)
|
foreach (var callback in Callbacks.InitializingCallbacks)
|
||||||
|
{
|
||||||
callback();
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_initialized = true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Synchronize the server (throttled).
|
/// Synchronize the server (throttled).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Sync()
|
public override void Sync()
|
||||||
{
|
{
|
||||||
|
if (!_initialized.Value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lock (_locko)
|
lock (_locko)
|
||||||
{
|
{
|
||||||
if (_syncing)
|
if (_syncing)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Don't continue if we are released
|
// Don't continue if we are released
|
||||||
if (_released)
|
if (_released)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((DateTime.UtcNow - _lastSync) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenSyncOperations)
|
if ((DateTime.UtcNow - _lastSync) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenSyncOperations)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Set our flag and the lock to be in it's original state (i.e. it can be awaited)
|
// Set our flag and the lock to be in it's original state (i.e. it can be awaited)
|
||||||
_syncing = true;
|
_syncing = true;
|
||||||
_syncIdle.Reset();
|
_syncIdle.Reset();
|
||||||
_lastSync = DateTime.UtcNow;
|
_lastSync = DateTime.UtcNow;
|
||||||
@@ -268,7 +300,7 @@ namespace Umbraco.Core.Sync
|
|||||||
{
|
{
|
||||||
ProcessDatabaseInstructions(scope.Database);
|
ProcessDatabaseInstructions(scope.Database);
|
||||||
|
|
||||||
//Check for pruning throttling
|
// Check for pruning throttling
|
||||||
if (_released || (DateTime.UtcNow - _lastPruned) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenPruneOperations)
|
if (_released || (DateTime.UtcNow - _lastPruned) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenPruneOperations)
|
||||||
{
|
{
|
||||||
scope.Complete();
|
scope.Complete();
|
||||||
@@ -277,7 +309,7 @@ namespace Umbraco.Core.Sync
|
|||||||
|
|
||||||
_lastPruned = _lastSync;
|
_lastPruned = _lastSync;
|
||||||
|
|
||||||
switch (_serverRegistrar.GetCurrentServerRole())
|
switch (_serverRegistrar.CurrentServerRole)
|
||||||
{
|
{
|
||||||
case ServerRole.Single:
|
case ServerRole.Single:
|
||||||
case ServerRole.Master:
|
case ServerRole.Master:
|
||||||
@@ -292,7 +324,7 @@ namespace Umbraco.Core.Sync
|
|||||||
{
|
{
|
||||||
lock (_locko)
|
lock (_locko)
|
||||||
{
|
{
|
||||||
//We must reset our flag and signal any waiting locks
|
// We must reset our flag and signal any waiting locks
|
||||||
_syncing = false;
|
_syncing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,9 +338,6 @@ namespace Umbraco.Core.Sync
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>
|
|
||||||
/// Returns the number of processed instructions
|
|
||||||
/// </returns>
|
|
||||||
private void ProcessDatabaseInstructions(IUmbracoDatabase database)
|
private void ProcessDatabaseInstructions(IUmbracoDatabase database)
|
||||||
{
|
{
|
||||||
// NOTE
|
// NOTE
|
||||||
@@ -324,7 +353,7 @@ namespace Umbraco.Core.Sync
|
|||||||
.Where<CacheInstructionDto>(dto => dto.Id > _lastId)
|
.Where<CacheInstructionDto>(dto => dto.Id > _lastId)
|
||||||
.OrderBy<CacheInstructionDto>(dto => dto.Id);
|
.OrderBy<CacheInstructionDto>(dto => dto.Id);
|
||||||
|
|
||||||
//only retrieve the top 100 (just in case there's tons)
|
// only retrieve the top 100 (just in case there's tons)
|
||||||
// even though MaxProcessingInstructionCount is by default 1000 we still don't want to process that many
|
// even though MaxProcessingInstructionCount is by default 1000 we still don't want to process that many
|
||||||
// rows in one request thread since each row can contain a ton of instructions (until 7.5.5 in which case
|
// rows in one request thread since each row can contain a ton of instructions (until 7.5.5 in which case
|
||||||
// a row can only contain MaxProcessingInstructionCount)
|
// a row can only contain MaxProcessingInstructionCount)
|
||||||
@@ -337,15 +366,15 @@ namespace Umbraco.Core.Sync
|
|||||||
|
|
||||||
var lastId = 0;
|
var lastId = 0;
|
||||||
|
|
||||||
//tracks which ones have already been processed to avoid duplicates
|
// tracks which ones have already been processed to avoid duplicates
|
||||||
var processed = new HashSet<RefreshInstruction>();
|
var processed = new HashSet<RefreshInstruction>();
|
||||||
|
|
||||||
//It would have been nice to do this in a Query instead of Fetch using a data reader to save
|
// It would have been nice to do this in a Query instead of Fetch using a data reader to save
|
||||||
// some memory however we cannot do that because inside of this loop the cache refreshers are also
|
// some memory however we cannot do that because inside of this loop the cache refreshers are also
|
||||||
// performing some lookups which cannot be done with an active reader open
|
// performing some lookups which cannot be done with an active reader open
|
||||||
foreach (var dto in database.Fetch<CacheInstructionDto>(topSql))
|
foreach (var dto in database.Fetch<CacheInstructionDto>(topSql))
|
||||||
{
|
{
|
||||||
//If this flag gets set it means we're shutting down! In this case, we need to exit asap and cannot
|
// If this flag gets set it means we're shutting down! In this case, we need to exit asap and cannot
|
||||||
// continue processing anything otherwise we'll hold up the app domain shutdown
|
// continue processing anything otherwise we'll hold up the app domain shutdown
|
||||||
if (_released)
|
if (_released)
|
||||||
{
|
{
|
||||||
@@ -377,10 +406,10 @@ namespace Umbraco.Core.Sync
|
|||||||
|
|
||||||
var instructionBatch = GetAllInstructions(jsonA);
|
var instructionBatch = GetAllInstructions(jsonA);
|
||||||
|
|
||||||
//process as per-normal
|
// process as per-normal
|
||||||
var success = ProcessDatabaseInstructions(instructionBatch, dto, processed, ref lastId);
|
var success = ProcessDatabaseInstructions(instructionBatch, dto, processed, ref lastId);
|
||||||
|
|
||||||
//if they couldn't be all processed (i.e. we're shutting down) then exit
|
// if they couldn't be all processed (i.e. we're shutting down) then exit
|
||||||
if (success == false)
|
if (success == false)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("The current batch of instructions was not processed, app is shutting down");
|
Logger.LogInformation("The current batch of instructions was not processed, app is shutting down");
|
||||||
@@ -425,11 +454,11 @@ namespace Umbraco.Core.Sync
|
|||||||
//}
|
//}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(
|
Logger.LogError(
|
||||||
ex,
|
ex,
|
||||||
"DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored",
|
"DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored",
|
||||||
dto.Id,
|
dto.Id,
|
||||||
dto.Instructions);
|
dto.Instructions);
|
||||||
|
|
||||||
//we cannot throw here because this invalid instruction will just keep getting processed over and over and errors
|
//we cannot throw here because this invalid instruction will just keep getting processed over and over and errors
|
||||||
// will be thrown over and over. The only thing we can do is ignore and move on.
|
// will be thrown over and over. The only thing we can do is ignore and move on.
|
||||||
@@ -509,7 +538,8 @@ namespace Umbraco.Core.Sync
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void ReadLastSynced()
|
private void ReadLastSynced()
|
||||||
{
|
{
|
||||||
if (File.Exists(DistCacheFilePath) == false) return;
|
if (File.Exists(DistCacheFilePath) == false)
|
||||||
|
return;
|
||||||
|
|
||||||
var content = File.ReadAllText(DistCacheFilePath);
|
var content = File.ReadAllText(DistCacheFilePath);
|
||||||
if (int.TryParse(content, out var last))
|
if (int.TryParse(content, out var last))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user