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:
@@ -6,6 +6,8 @@
|
||||
at %APPDATA%\NuGet\NuGet.config
|
||||
-->
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||
<add key="UmbracoCoreMyGet" value="https://www.myget.org/F/umbracocore/api/v3/index.json" />
|
||||
<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" />
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return;
|
||||
|
||||
_serverMessenger.PerformRefresh(
|
||||
_serverMessenger.QueueRefresh(
|
||||
GetRefresherById(refresherGuid),
|
||||
getNumericId,
|
||||
instances);
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty || id == default(int)) return;
|
||||
|
||||
_serverMessenger.PerformRefresh(
|
||||
_serverMessenger.QueueRefresh(
|
||||
GetRefresherById(refresherGuid),
|
||||
id);
|
||||
}
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty || id == Guid.Empty) return;
|
||||
|
||||
_serverMessenger.PerformRefresh(
|
||||
_serverMessenger.QueueRefresh(
|
||||
GetRefresherById(refresherGuid),
|
||||
id);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty || payload == null) return;
|
||||
|
||||
_serverMessenger.PerformRefresh(
|
||||
_serverMessenger.QueueRefresh(
|
||||
GetRefresherById(refresherGuid),
|
||||
payload);
|
||||
}
|
||||
@@ -97,7 +97,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty || payloads == null) return;
|
||||
|
||||
_serverMessenger.PerformRefresh(
|
||||
_serverMessenger.QueueRefresh(
|
||||
GetRefresherById(refresherGuid),
|
||||
payloads.ToArray());
|
||||
}
|
||||
@@ -125,7 +125,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty) return;
|
||||
|
||||
_serverMessenger.PerformRefreshAll(
|
||||
_serverMessenger.QueueRefreshAll(
|
||||
GetRefresherById(refresherGuid));
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
if (refresherGuid == Guid.Empty || id == default(int)) return;
|
||||
|
||||
_serverMessenger.PerformRemove(
|
||||
_serverMessenger.QueueRemove(
|
||||
GetRefresherById(refresherGuid),
|
||||
id);
|
||||
}
|
||||
@@ -155,7 +155,7 @@ namespace Umbraco.Web.Cache
|
||||
/// </remarks>
|
||||
public void Remove<T>(Guid refresherGuid, Func<T, int> getNumericId, params T[] instances)
|
||||
{
|
||||
_serverMessenger.PerformRemove(
|
||||
_serverMessenger.QueueRemove(
|
||||
GetRefresherById(refresherGuid),
|
||||
getNumericId,
|
||||
instances);
|
||||
@@ -166,7 +166,13 @@ namespace Umbraco.Web.Cache
|
||||
// helper method to get an ICacheRefresher by its unique identifier
|
||||
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.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -70,7 +70,6 @@ namespace Umbraco.Core.Composing
|
||||
|
||||
foreach (var composer in composers)
|
||||
{
|
||||
var componentType = composer.GetType();
|
||||
composer.Compose(_builder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
using System;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
|
||||
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.Extensions;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace Umbraco.Core
|
||||
where TImplementing : class, TService1, TService2
|
||||
{
|
||||
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)
|
||||
@@ -48,9 +49,9 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static void AddUnique<TService>(this IServiceCollection services, TService instance)
|
||||
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<>)));
|
||||
return services;
|
||||
@@ -1,11 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Umbraco.Core.Events;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
@@ -23,7 +24,15 @@ namespace Umbraco.Core.DependencyInjection
|
||||
where TNotification : INotification
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,28 +3,65 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Cache;
|
||||
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.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
|
||||
{
|
||||
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>();
|
||||
|
||||
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)
|
||||
: 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)
|
||||
{
|
||||
Services = services;
|
||||
@@ -43,10 +80,12 @@ namespace Umbraco.Core.DependencyInjection
|
||||
public TBuilder WithCollectionBuilder<TBuilder>()
|
||||
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;
|
||||
}
|
||||
|
||||
var builder = new TBuilder();
|
||||
_builders[typeOfBuilder] = builder;
|
||||
@@ -55,8 +94,10 @@ namespace Umbraco.Core.DependencyInjection
|
||||
|
||||
public void Build()
|
||||
{
|
||||
foreach (var builder in _builders.Values)
|
||||
foreach (ICollectionBuilder builder in _builders.Values)
|
||||
{
|
||||
builder.RegisterWith(Services);
|
||||
}
|
||||
|
||||
_builders.Clear();
|
||||
}
|
||||
@@ -66,6 +107,115 @@ namespace Umbraco.Core.DependencyInjection
|
||||
// Register as singleton to allow injection everywhere.
|
||||
Services.AddSingleton<ServiceFactory>(p => p.GetService);
|
||||
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.Configuration.Models;
|
||||
using Umbraco.Core.HealthCheck;
|
||||
using Umbraco.Core.Mail;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Infrastructure.HealthCheck;
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Net
|
||||
namespace Umbraco.Core.Hosting
|
||||
{
|
||||
// TODO: This shouldn't be in this namespace?
|
||||
public interface IUmbracoApplicationLifetime
|
||||
{
|
||||
/// <summary>
|
||||
/// A value indicating whether the application is restarting after the current request.
|
||||
/// </summary>
|
||||
bool IsRestarting { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Terminates the current application. The application restarts the next time a request is received for it.
|
||||
/// </summary>
|
||||
void Restart();
|
||||
|
||||
// TODO: Should be killed and replaced with UmbracoApplicationStarting notifications
|
||||
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.Configuration.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Install.Models;
|
||||
|
||||
namespace Umbraco.Web.Install.InstallSteps
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
public class VoidProfiler : IProfiler
|
||||
public class NoopProfiler : IProfiler
|
||||
{
|
||||
private readonly VoidDisposable _disposable = new VoidDisposable();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core.Mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// 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;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core.Mail
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ISmsSender"/> that throws <see cref="NotImplementedException"/>
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Core.Hosting;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
|
||||
|
||||
public class PropertyEditorCollection : BuilderCollectionBase<IDataEditor>
|
||||
{
|
||||
public PropertyEditorCollection(DataEditorCollection dataEditors, IManifestParser manifestParser)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
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.
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter]
|
||||
public class TinyMceValueConverter : PropertyValueConverterBase
|
||||
public class SimpleTinyMceValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> 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.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Infrastructure.Runtime
|
||||
namespace Umbraco.Core.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Infrastructure.Runtime
|
||||
namespace Umbraco.Core.Runtime
|
||||
{
|
||||
public class EssentialDirectoryCreator : INotificationHandler<UmbracoApplicationStarting>
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Runtime
|
||||
_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<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
|
||||
// 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
|
||||
{
|
||||
_lockRelease = _systemLock.Lock(millisecondsTimeout);
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Sync;
|
||||
@@ -11,9 +11,8 @@ namespace Umbraco.Core.Services
|
||||
/// Touches a server to mark it as active; deactivate stale servers.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout);
|
||||
void TouchServer(string serverAddress, TimeSpan staleTimeout);
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates a server.
|
||||
@@ -38,11 +37,6 @@ namespace Umbraco.Core.Services
|
||||
/// from the database.</remarks>
|
||||
IEnumerable<IServerRegistration> GetActiveServers(bool refresh = false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current server identity.
|
||||
/// </summary>
|
||||
string CurrentServerIdentity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role of the current server.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public class InstallationService : IInstallationService
|
||||
{
|
||||
@@ -1,10 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Semver;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public class UpgradeService : IUpgradeService
|
||||
{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <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>
|
||||
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.Collections.Generic;
|
||||
using System;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <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>
|
||||
/// <remarks>Also ensures that the notification is processed on the local environment.</remarks>
|
||||
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>
|
||||
/// Notifies the distributed cache, for a specified <see cref="ICacheRefresher"/>.
|
||||
/// </summary>
|
||||
/// <param name="refresher">The ICacheRefresher.</param>
|
||||
/// <param name="payload">The notification content.</param>
|
||||
void PerformRefresh<TPayload>(ICacheRefresher refresher, TPayload[] payload);
|
||||
void QueueRefresh<TPayload>(ICacheRefresher refresher, TPayload[] payload);
|
||||
|
||||
/// <summary>
|
||||
/// 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="getNumericId">A function returning the unique identifier of 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>
|
||||
/// 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="getGuidId">A function returning the unique identifier of 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>
|
||||
/// 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="getNumericId">A function returning the unique identifier of 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>
|
||||
/// Notifies all servers of specified items removal, for a specified <see cref="ICacheRefresher"/>.
|
||||
/// </summary>
|
||||
/// <param name="refresher">The ICacheRefresher.</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>
|
||||
/// Notifies all servers of specified items invalidation, for a specified <see cref="ICacheRefresher"/>.
|
||||
/// </summary>
|
||||
/// <param name="refresher">The ICacheRefresher.</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>
|
||||
/// Notifies all servers of specified items invalidation, for a specified <see cref="ICacheRefresher"/>.
|
||||
/// </summary>
|
||||
/// <param name="refresher">The ICacheRefresher.</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>
|
||||
/// Notifies all servers of a global invalidation for a specified <see cref="ICacheRefresher"/>.
|
||||
/// </summary>
|
||||
/// <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.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
namespace Umbraco.Core.Trees
|
||||
{
|
||||
public interface ISearchableTree : IDiscoverable
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
namespace Umbraco.Core.Trees
|
||||
{
|
||||
public class SearchableApplicationTree
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.Services;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
namespace Umbraco.Core.Trees
|
||||
{
|
||||
public class SearchableTreeCollection : BuilderCollectionBase<ISearchableTree>
|
||||
{
|
||||
@@ -1,8 +1,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
namespace Umbraco.Core.Trees
|
||||
{
|
||||
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.Logging" 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.Configuration.ConfigurationManager" Version="4.7.0" />
|
||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
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;
|
||||
|
||||
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.Options;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
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
|
||||
@@ -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
|
||||
// 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
|
||||
// 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
|
||||
builder.Services.AddUnique<IFileSystems>(factory => factory.GetRequiredService<Core.IO.FileSystems>());
|
||||
builder.Services.AddUnique<IFileSystems>(factory => factory.GetRequiredService<FileSystems>());
|
||||
|
||||
// register the scheme for media paths
|
||||
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.Web.Models.Mapping;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
|
||||
namespace Umbraco.Infrastructure.DependencyInjection
|
||||
{
|
||||
public static class CoreMappingProfiles
|
||||
public static partial class UmbracoBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the core Umbraco mapper definitions
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IUmbracoBuilder ComposeCoreMappingProfiles(this IUmbracoBuilder builder)
|
||||
public static IUmbracoBuilder AddCoreMappingProfiles(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddUnique<UmbracoMapper>();
|
||||
|
||||
@@ -34,8 +31,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
.Add<TemplateMapDefinition>()
|
||||
.Add<UserMapDefinition>()
|
||||
.Add<LanguageMapDefinition>()
|
||||
.Add<IdentityMapDefinition>()
|
||||
;
|
||||
.Add<IdentityMapDefinition>();
|
||||
|
||||
builder.Services.AddTransient<CommonMapper>();
|
||||
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.Implement;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
namespace Umbraco.Infrastructure.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Composes repositories.
|
||||
/// </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
|
||||
builder.Services.AddUnique<IAuditRepository, AuditRepository>();
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
@@ -15,16 +16,15 @@ using Umbraco.Core.Routing;
|
||||
using Umbraco.Core.Services;
|
||||
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
|
||||
builder.Services.AddUnique<ServiceContext>();
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
builder.Services.AddUnique<IExternalLoginService, ExternalLoginService>();
|
||||
builder.Services.AddUnique<IRedirectUrlService, RedirectUrlService>();
|
||||
builder.Services.AddUnique<IConsentService, ConsentService>();
|
||||
builder.Services.AddTransient<LocalizedTextServiceFileSources>(SourcesFactory);
|
||||
builder.Services.AddTransient(SourcesFactory);
|
||||
builder.Services.AddUnique<ILocalizedTextService>(factory => new LocalizedTextService(
|
||||
factory.GetRequiredService<Lazy<LocalizedTextServiceFileSources>>(),
|
||||
factory.GetRequiredService<ILogger<LocalizedTextService>>()));
|
||||
@@ -82,9 +82,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
/// <summary>
|
||||
/// Creates an instance of PackagesRepository for either the ICreatedPackagesRepository or the IInstalledPackagesRepository
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="packageRepoFileName"></param>
|
||||
/// <returns></returns>
|
||||
private static PackagesRepository CreatePackageRepository(IServiceProvider factory, string packageRepoFileName)
|
||||
=> new PackagesRepository(
|
||||
factory.GetRequiredService<IContentService>(),
|
||||
@@ -106,9 +103,9 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
{
|
||||
var hostingEnvironment = container.GetRequiredService<IHostingEnvironment>();
|
||||
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 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
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
@@ -117,7 +114,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
|
||||
.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
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
: 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 Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Mail;
|
||||
using Umbraco.Core.Models;
|
||||
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
private readonly HealthCheckCollection _healthChecks;
|
||||
private readonly HealthCheckNotificationMethodCollection _notifications;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IServerRegistrar _serverRegistrar;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
private readonly ILogger<HealthCheckNotifier> _logger;
|
||||
@@ -54,7 +54,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
HealthCheckCollection healthChecks,
|
||||
HealthCheckNotificationMethodCollection notifications,
|
||||
IRuntimeState runtimeState,
|
||||
IServerRegistrar serverRegistrar,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IMainDom mainDom,
|
||||
IScopeProvider scopeProvider,
|
||||
ILogger<HealthCheckNotifier> logger,
|
||||
@@ -87,7 +87,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_serverRegistrar.GetCurrentServerRole())
|
||||
switch (_serverRegistrar.CurrentServerRole)
|
||||
{
|
||||
case ServerRole.Replica:
|
||||
_logger.LogDebug("Does not run on replica servers.");
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
private readonly KeepAliveSettings _keepAliveSettings;
|
||||
private readonly ILogger<KeepAlive> _logger;
|
||||
private readonly IProfilingLogger _profilingLogger;
|
||||
private readonly IServerRegistrar _serverRegistrar;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +43,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
IOptions<KeepAliveSettings> keepAliveSettings,
|
||||
ILogger<KeepAlive> logger,
|
||||
IProfilingLogger profilingLogger,
|
||||
IServerRegistrar serverRegistrar,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IHttpClientFactory httpClientFactory)
|
||||
: base(TimeSpan.FromMinutes(5), DefaultDelay)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
}
|
||||
|
||||
// Don't run on replicas nor unknown role servers
|
||||
switch (_serverRegistrar.GetCurrentServerRole())
|
||||
switch (_serverRegistrar.CurrentServerRole)
|
||||
{
|
||||
case ServerRole.Replica:
|
||||
_logger.LogDebug("Does not run on replica servers.");
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
public class LogScrubber : RecurringHostedServiceBase
|
||||
{
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IServerRegistrar _serverRegistrar;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly LoggingSettings _settings;
|
||||
private readonly IProfilingLogger _profilingLogger;
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
/// <param name="profilingLogger">The profiling logger.</param>
|
||||
public LogScrubber(
|
||||
IMainDom mainDom,
|
||||
IServerRegistrar serverRegistrar,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IAuditService auditService,
|
||||
IOptions<LoggingSettings> settings,
|
||||
IScopeProvider scopeProvider,
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
|
||||
internal override Task PerformExecuteAsync(object state)
|
||||
{
|
||||
switch (_serverRegistrar.GetCurrentServerRole())
|
||||
switch (_serverRegistrar.CurrentServerRole)
|
||||
{
|
||||
case ServerRole.Replica:
|
||||
_logger.LogDebug("Does not run on replica servers.");
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IServerMessenger _serverMessenger;
|
||||
private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory;
|
||||
private readonly IServerRegistrar _serverRegistrar;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private readonly IUmbracoContextFactory _umbracoContextFactory;
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
public ScheduledPublishing(
|
||||
IRuntimeState runtimeState,
|
||||
IMainDom mainDom,
|
||||
IServerRegistrar serverRegistrar,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IContentService contentService,
|
||||
IUmbracoContextFactory umbracoContextFactory,
|
||||
ILogger<ScheduledPublishing> logger,
|
||||
@@ -69,7 +69,7 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
switch (_serverRegistrar.GetCurrentServerRole())
|
||||
switch (_serverRegistrar.CurrentServerRole)
|
||||
{
|
||||
case ServerRole.Replica:
|
||||
_logger.LogDebug("Does not run on replica servers.");
|
||||
@@ -123,9 +123,9 @@ namespace Umbraco.Infrastructure.HostedServices
|
||||
finally
|
||||
{
|
||||
// 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
|
||||
{
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IDatabaseServerMessenger _messenger;
|
||||
private readonly IServerMessenger _messenger;
|
||||
private readonly ILogger<InstructionProcessTask> _logger;
|
||||
|
||||
/// <summary>
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
|
||||
: base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1))
|
||||
{
|
||||
_runtimeState = runtimeState;
|
||||
_messenger = messenger as IDatabaseServerMessenger ?? throw new ArgumentNullException(nameof(messenger));
|
||||
_messenger = messenger;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
|
||||
|
||||
try
|
||||
{
|
||||
// TouchServer uses a proper unit of work etc underneath so even in a
|
||||
// background task it is safe to call it without dealing with any scope.
|
||||
_serverRegistrationService.TouchServer(serverAddress, _serverRegistrationService.CurrentServerIdentity, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout);
|
||||
_serverRegistrationService.TouchServer(serverAddress, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -6,9 +6,9 @@ using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Packaging;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Install.Models;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Core.Hosting;
|
||||
|
||||
namespace Umbraco.Web.Install.InstallSteps
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -55,6 +55,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers
|
||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message));
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var dumped = MiniDump.Dump(_marchal, _hostingEnvironment, withException: true);
|
||||
@@ -69,6 +70,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers
|
||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Infrastructure.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Core.Logging.Viewer
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Umbraco.Core;
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Web.Media
|
||||
/// use potentially large amounts of memory.</remarks>
|
||||
public ImageSize GetDimensions(Stream stream)
|
||||
{
|
||||
//Try to load with exif
|
||||
// Try to load with exif
|
||||
try
|
||||
{
|
||||
if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height))
|
||||
@@ -28,12 +28,13 @@ namespace Umbraco.Web.Media
|
||||
}
|
||||
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
|
||||
{
|
||||
// TODO: We should be using ImageSharp for this
|
||||
using (var image = Image.FromStream(stream))
|
||||
{
|
||||
var fileWidth = image.Width;
|
||||
@@ -43,7 +44,7 @@ namespace Umbraco.Web.Media
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
|
||||
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.IO;
|
||||
using System.Linq;
|
||||
@@ -17,16 +17,11 @@ namespace Umbraco.Core.Packaging
|
||||
private readonly IPackageActionRunner _packageActionRunner;
|
||||
private readonly DirectoryInfo _applicationRootFolder;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// Initializes a new instance of the <see cref="PackageInstallation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="packageDataInstallation"></param>
|
||||
/// <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)
|
||||
public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, IHostingEnvironment hostingEnvironment)
|
||||
{
|
||||
_packageExtraction = new PackageExtraction();
|
||||
_packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using HtmlAgilityPack;
|
||||
using Umbraco.Core;
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
/// used dynamically.
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter]
|
||||
public class RteMacroRenderingValueConverter : TinyMceValueConverter
|
||||
public class RteMacroRenderingValueConverter : SimpleTinyMceValueConverter
|
||||
{
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
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 Umbraco.Core.Events;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -8,11 +8,11 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Trees;
|
||||
using Umbraco.Examine;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Models.Mapping;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Mail;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -26,11 +25,12 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerRegistrationService"/> class.
|
||||
/// </summary>
|
||||
/// <param name="scopeProvider">A UnitOfWork provider.</param>
|
||||
/// <param name="loggerFactory">A logger factory</param>
|
||||
/// <param name="eventMessagesFactory"></param>
|
||||
public ServerRegistrationService(IScopeProvider scopeProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory,
|
||||
IServerRegistrationRepository serverRegistrationRepository, IHostingEnvironment hostingEnvironment)
|
||||
public ServerRegistrationService(
|
||||
IScopeProvider scopeProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IServerRegistrationRepository serverRegistrationRepository,
|
||||
IHostingEnvironment hostingEnvironment)
|
||||
: base(scopeProvider, loggerFactory, eventMessagesFactory)
|
||||
{
|
||||
_serverRegistrationRepository = serverRegistrationRepository;
|
||||
@@ -41,10 +41,10 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// Touches a server to mark it as active; deactivate stale servers.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout)
|
||||
public void TouchServer(string serverAddress, TimeSpan staleTimeout)
|
||||
{
|
||||
var serverIdentity = GetCurrentServerIdentity();
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
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>
|
||||
/// Gets the role of the current server.
|
||||
/// </summary>
|
||||
/// <returns>The role of the current server.</returns>
|
||||
public ServerRole GetCurrentServerRole()
|
||||
{
|
||||
return _currentServerRole;
|
||||
}
|
||||
public ServerRole GetCurrentServerRole() => _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.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web;
|
||||
|
||||
namespace Umbraco.Web
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IServerMessenger"/> implementation that works by storing messages in the database.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This binds to appropriate umbraco events in order to trigger the Boot(), Sync() & FlushBatch() calls
|
||||
/// </remarks>
|
||||
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger, IBatchedDatabaseServerMessenger
|
||||
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
|
||||
{
|
||||
private readonly IUmbracoDatabaseFactory _databaseFactory;
|
||||
private readonly IRequestCache _requestCache;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BatchedDatabaseServerMessenger"/> class.
|
||||
/// </summary>
|
||||
public BatchedDatabaseServerMessenger(
|
||||
IMainDom mainDom,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
IScopeProvider scopeProvider,
|
||||
IProfilingLogger proflog,
|
||||
ILogger<BatchedDatabaseServerMessenger> logger,
|
||||
IServerRegistrar serverRegistrar,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
DatabaseServerMessengerCallbacks callbacks,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
CacheRefresherCollection cacheRefreshers,
|
||||
IRequestCache requestCache,
|
||||
IRequestAccessor requestAccessor,
|
||||
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;
|
||||
_requestAccessor = requestAccessor;
|
||||
}
|
||||
|
||||
// invoked by DatabaseServerRegistrarAndMessengerComponent
|
||||
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();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable<object> ids = null, string json = null)
|
||||
{
|
||||
var idsA = ids?.ToArray();
|
||||
|
||||
Type arrayType;
|
||||
if (GetArrayType(idsA, out arrayType) == false)
|
||||
if (GetArrayType(idsA, out Type arrayType) == false)
|
||||
{
|
||||
throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids));
|
||||
}
|
||||
|
||||
BatchMessage(refresher, messageType, idsA, arrayType, json);
|
||||
}
|
||||
|
||||
public void FlushBatch()
|
||||
/// <inheritdoc/>
|
||||
public override void SendMessages()
|
||||
{
|
||||
var batch = GetBatch(false);
|
||||
if (batch == null) return;
|
||||
ICollection<RefreshInstructionEnvelope> batch = GetBatch(false);
|
||||
if (batch == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var instructions = batch.SelectMany(x => x.Instructions).ToArray();
|
||||
RefreshInstruction[] instructions = batch.SelectMany(x => x.Instructions).ToArray();
|
||||
batch.Clear();
|
||||
|
||||
//Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
// Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
|
||||
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);
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
|
||||
@@ -113,11 +92,14 @@ namespace Umbraco.Web
|
||||
scope.Database.Insert(dto);
|
||||
}
|
||||
|
||||
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
|
||||
private ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
|
||||
{
|
||||
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
|
||||
var batch = (ICollection<RefreshInstructionEnvelope>)_requestCache.Get(key);
|
||||
@@ -130,26 +112,27 @@ namespace Umbraco.Web
|
||||
return batch;
|
||||
}
|
||||
|
||||
protected void BatchMessage(
|
||||
private void BatchMessage(
|
||||
ICacheRefresher refresher,
|
||||
MessageType messageType,
|
||||
IEnumerable<object> ids = null,
|
||||
Type idType = null,
|
||||
string json = null)
|
||||
{
|
||||
var batch = GetBatch(true);
|
||||
var instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json);
|
||||
ICollection<RefreshInstructionEnvelope> batch = GetBatch(true);
|
||||
IEnumerable<RefreshInstruction> instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json);
|
||||
|
||||
// batch if we can, else write to DB immediately
|
||||
if (batch == null)
|
||||
{
|
||||
//only write the json blob with a maximum count of the MaxProcessingInstructionCount
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
// only write the json blob with a maximum count of the MaxProcessingInstructionCount
|
||||
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);
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
}
|
||||
@@ -23,19 +23,21 @@ namespace Umbraco.Core.Sync
|
||||
/// <summary>
|
||||
/// An <see cref="IServerMessenger"/> that works by storing messages in the database.
|
||||
/// </summary>
|
||||
//
|
||||
// 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
|
||||
public abstract class DatabaseServerMessenger : ServerMessengerBase
|
||||
{
|
||||
// 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 IUmbracoDatabaseFactory _umbracoDatabaseFactory;
|
||||
private readonly ManualResetEvent _syncIdle;
|
||||
private readonly object _locko = new object();
|
||||
private readonly IProfilingLogger _profilingLogger;
|
||||
private readonly IServerRegistrar _serverRegistrar;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly CacheRefresherCollection _cacheRefreshers;
|
||||
|
||||
@@ -43,22 +45,28 @@ namespace Umbraco.Core.Sync
|
||||
private int _lastId = -1;
|
||||
private DateTime _lastSync;
|
||||
private DateTime _lastPruned;
|
||||
private bool _initialized;
|
||||
private readonly Lazy<bool> _initialized;
|
||||
private bool _syncing;
|
||||
private bool _released;
|
||||
|
||||
public DatabaseServerMessengerCallbacks Callbacks { get; }
|
||||
|
||||
public GlobalSettings GlobalSettings { get; }
|
||||
|
||||
public DatabaseServerMessenger(
|
||||
IMainDom mainDom, IScopeProvider scopeProvider, IUmbracoDatabaseFactory umbracoDatabaseFactory, IProfilingLogger proflog, ILogger<DatabaseServerMessenger> logger, IServerRegistrar serverRegistrar,
|
||||
bool distributedEnabled, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IOptions<GlobalSettings> globalSettings)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DatabaseServerMessenger"/> class.
|
||||
/// </summary>
|
||||
protected DatabaseServerMessenger(
|
||||
IMainDom mainDom,
|
||||
IScopeProvider scopeProvider,
|
||||
IProfilingLogger proflog,
|
||||
ILogger<DatabaseServerMessenger> logger,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
bool distributedEnabled,
|
||||
DatabaseServerMessengerCallbacks callbacks,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
CacheRefresherCollection cacheRefreshers,
|
||||
IOptions<GlobalSettings> globalSettings)
|
||||
: base(distributedEnabled)
|
||||
{
|
||||
ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider));
|
||||
_mainDom = mainDom;
|
||||
_umbracoDatabaseFactory = umbracoDatabaseFactory;
|
||||
_profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog));
|
||||
_serverRegistrar = serverRegistrar;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
@@ -76,24 +84,28 @@ namespace Umbraco.Core.Sync
|
||||
+ " [P" + Process.GetCurrentProcess().Id // eg 1234
|
||||
+ "/D" + AppDomain.CurrentDomain.Id // eg 22
|
||||
+ "] " + 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 IScopeProvider ScopeProvider { get; }
|
||||
|
||||
protected Sql<ISqlContext> Sql() => _umbracoDatabaseFactory.SqlContext.Sql();
|
||||
protected Sql<ISqlContext> Sql() => ScopeProvider.SqlContext.Sql();
|
||||
|
||||
private string DistCacheFilePath => _distCacheFilePath.Value;
|
||||
|
||||
#region Messenger
|
||||
|
||||
protected override bool RequiresDistributed(ICacheRefresher refresher, MessageType dispatchType)
|
||||
{
|
||||
// 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 bool RequiresDistributed(ICacheRefresher refresher, MessageType dispatchType)
|
||||
=> _initialized.Value && DistributedEnabled;
|
||||
|
||||
protected override void DeliverRemote(
|
||||
ICacheRefresher refresher,
|
||||
@@ -104,7 +116,9 @@ namespace Umbraco.Core.Sync
|
||||
var idsA = ids?.ToArray();
|
||||
|
||||
if (GetArrayType(idsA, out var idType) == false)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -130,17 +144,12 @@ namespace Umbraco.Core.Sync
|
||||
/// <summary>
|
||||
/// Boots the messenger.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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()
|
||||
private bool EnsureInitialized()
|
||||
{
|
||||
// weight:10, must release *before* the published snapshot service, because once released
|
||||
// the service will *not* be able to properly handle our notifications anymore
|
||||
const int weight = 10;
|
||||
|
||||
|
||||
var registered = _mainDom.Register(
|
||||
() =>
|
||||
{
|
||||
@@ -154,7 +163,7 @@ namespace Umbraco.Core.Sync
|
||||
// properly releasing MainDom - a timeout here means that one refresher
|
||||
// is taking too much time processing, however when it's done we will
|
||||
// not update lastId and stop everything
|
||||
var idle =_syncIdle.WaitOne(5000);
|
||||
var idle = _syncIdle.WaitOne(5000);
|
||||
if (idle == false)
|
||||
{
|
||||
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);
|
||||
|
||||
if (registered == false)
|
||||
return;
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadLastSynced(); // get _lastId
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
EnsureInstructions(scope.Database); // reset _lastId if instructions are missing
|
||||
Initialize(scope.Database); // boot
|
||||
|
||||
scope.Complete();
|
||||
return Initialize(scope.Database); // boot
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,14 +192,19 @@ namespace Umbraco.Core.Sync
|
||||
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
||||
/// Callers MUST ensure thread-safety.
|
||||
/// </remarks>
|
||||
private void Initialize(IUmbracoDatabase database)
|
||||
private bool Initialize(IUmbracoDatabase database)
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_released) return;
|
||||
if (_released)
|
||||
{
|
||||
return 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
|
||||
// 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
|
||||
{
|
||||
//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.
|
||||
var count = database.ExecuteScalar<int>("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId});
|
||||
// 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.
|
||||
var count = database.ExecuteScalar<int>("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new { lastId = _lastId });
|
||||
if (count > GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)
|
||||
{
|
||||
//too many instructions, proceed to cold boot
|
||||
// too many instructions, proceed to cold boot
|
||||
Logger.LogWarning(
|
||||
"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"
|
||||
@@ -224,38 +239,55 @@ namespace Umbraco.Core.Sync
|
||||
// when doing it before, some instructions might run twice - not an issue
|
||||
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)
|
||||
{
|
||||
SaveLastSynced(maxId);
|
||||
}
|
||||
|
||||
// execute initializing callbacks
|
||||
if (Callbacks.InitializingCallbacks != null)
|
||||
{
|
||||
foreach (var callback in Callbacks.InitializingCallbacks)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize the server (throttled).
|
||||
/// </summary>
|
||||
public void Sync()
|
||||
public override void Sync()
|
||||
{
|
||||
if (!_initialized.Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_locko)
|
||||
{
|
||||
if (_syncing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Don't continue if we are released
|
||||
// Don't continue if we are released
|
||||
if (_released)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((DateTime.UtcNow - _lastSync) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenSyncOperations)
|
||||
{
|
||||
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;
|
||||
_syncIdle.Reset();
|
||||
_lastSync = DateTime.UtcNow;
|
||||
@@ -268,7 +300,7 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
ProcessDatabaseInstructions(scope.Database);
|
||||
|
||||
//Check for pruning throttling
|
||||
// Check for pruning throttling
|
||||
if (_released || (DateTime.UtcNow - _lastPruned) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenPruneOperations)
|
||||
{
|
||||
scope.Complete();
|
||||
@@ -277,7 +309,7 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
_lastPruned = _lastSync;
|
||||
|
||||
switch (_serverRegistrar.GetCurrentServerRole())
|
||||
switch (_serverRegistrar.CurrentServerRole)
|
||||
{
|
||||
case ServerRole.Single:
|
||||
case ServerRole.Master:
|
||||
@@ -292,7 +324,7 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
//We must reset our flag and signal any waiting locks
|
||||
// We must reset our flag and signal any waiting locks
|
||||
_syncing = false;
|
||||
}
|
||||
|
||||
@@ -306,9 +338,6 @@ namespace Umbraco.Core.Sync
|
||||
/// <remarks>
|
||||
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// Returns the number of processed instructions
|
||||
/// </returns>
|
||||
private void ProcessDatabaseInstructions(IUmbracoDatabase database)
|
||||
{
|
||||
// NOTE
|
||||
@@ -324,7 +353,7 @@ namespace Umbraco.Core.Sync
|
||||
.Where<CacheInstructionDto>(dto => dto.Id > _lastId)
|
||||
.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
|
||||
// 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)
|
||||
@@ -337,15 +366,15 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
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>();
|
||||
|
||||
//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
|
||||
// performing some lookups which cannot be done with an active reader open
|
||||
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
|
||||
if (_released)
|
||||
{
|
||||
@@ -377,10 +406,10 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
var instructionBatch = GetAllInstructions(jsonA);
|
||||
|
||||
//process as per-normal
|
||||
// process as per-normal
|
||||
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)
|
||||
{
|
||||
Logger.LogInformation("The current batch of instructions was not processed, app is shutting down");
|
||||
@@ -509,7 +538,8 @@ namespace Umbraco.Core.Sync
|
||||
/// </remarks>
|
||||
private void ReadLastSynced()
|
||||
{
|
||||
if (File.Exists(DistCacheFilePath) == false) return;
|
||||
if (File.Exists(DistCacheFilePath) == false)
|
||||
return;
|
||||
|
||||
var content = File.ReadAllText(DistCacheFilePath);
|
||||
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