using System; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services.Changes; using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Infrastructure.Search; using Umbraco.Cms.Infrastructure.Sync; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.DependencyInjection { /// /// Provides extension methods to the class. /// public static partial class UmbracoBuilderExtensions { /// /// Adds distributed cache support /// /// /// This is still required for websites that are not load balancing because this ensures that sites hosted /// with managed hosts like IIS/etc... work correctly when AppDomains are running in parallel. /// public static IUmbracoBuilder AddDistributedCache(this IUmbracoBuilder builder) { var distCacheBinder = new UniqueServiceDescriptor(typeof(IDistributedCacheBinder), typeof(DistributedCacheBinder), ServiceLifetime.Singleton); if (builder.Services.Contains(distCacheBinder)) { // if this is called more than once just exit return builder; } builder.Services.Add(distCacheBinder); builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); builder.SetServerMessenger(); builder.AddNotificationHandler(); builder.AddNotificationHandler(); return builder; } /// /// Sets the server registrar. /// /// The type of the server registrar. /// The builder. public static void SetServerRegistrar(this IUmbracoBuilder builder) where T : class, IServerRoleAccessor => builder.Services.AddUnique(); /// /// Sets the server registrar. /// /// The builder. /// A function creating a server registrar. public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) => builder.Services.AddUnique(factory); /// /// Sets the server registrar. /// /// The builder. /// A server registrar. public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor registrar) => builder.Services.AddUnique(registrar); /// /// Sets the database server messenger options. /// /// The builder. /// A function creating the options. /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func factory) => builder.Services.AddUnique(factory); /// /// Sets the database server messenger options. /// /// The builder. /// Options. /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options) => builder.Services.AddUnique(options); /// /// Sets the server messenger. /// /// The type of the server registrar. /// The builder. public static void SetServerMessenger(this IUmbracoBuilder builder) where T : class, IServerMessenger => builder.Services.AddUnique(); /// /// Sets the server messenger. /// /// The builder. /// A function creating a server messenger. public static void SetServerMessenger(this IUmbracoBuilder builder, Func factory) => builder.Services.AddUnique(factory); /// /// Sets the server messenger. /// /// The builder. /// A server messenger. 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(); // 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(); indexRebuilder.RebuildIndexes(false, TimeSpan.FromSeconds(5)); } } }; } }