using System; using Examine; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Composing; 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.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.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Scoping; 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 IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.HealthCheck; using Umbraco.Core.HealthCheck.Checks; namespace Umbraco.Core.Runtime { // core's initial composer composes before all core composers [ComposeBefore(typeof(ICoreComposer))] public class CoreInitialComposer : ComponentComposer { public override void Compose(Composition composition) { base.Compose(composition); // composers composition .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 composition.Mappers().AddCoreMappers(); // register the scope provider composition.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor composition.Services.AddUnique(f => f.GetRequiredService()); composition.Services.AddUnique(f => f.GetRequiredService()); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); // register database builder // *not* a singleton, don't want to keep it around composition.Services.AddTransient(); // register manifest parser, will be injected in collection builders where needed composition.Services.AddUnique(); // register our predefined validators composition.ManifestValueValidators() .Add() .Add() .Add() .Add() .Add() .Add(); // register the manifest filter collection builder (collection is empty by default) composition.ManifestFilters(); // properties and parameters derive from data editors composition.DataEditors() .Add(() => composition.TypeLoader.GetDataEditors()); composition.MediaUrlGenerators() .Add() .Add(); composition.Services.AddUnique(); composition.Services.AddUnique(); // Used to determine if a datatype/editor should be storing/tracking // references to media item/s composition.DataValueReferenceFactories(); // register a server registrar, by default it's the db registrar composition.Services.AddUnique(f => { var globalSettings = f.GetRequiredService>().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()) : new DatabaseServerRegistrar( new Lazy(f.GetRequiredService), new DatabaseServerRegistrarOptions()); }); // 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 composition.Services.AddUnique(factory => new DatabaseServerMessenger( factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService>(), factory.GetRequiredService(), true, new DatabaseServerMessengerOptions(), factory.GetRequiredService(), factory.GetRequiredService() )); composition.CacheRefreshers() .Add(() => composition.TypeLoader.GetCacheRefreshers()); composition.PackageActions() .Add(() => composition.TypeLoader.GetPackageActions()); composition.PropertyValueConverters() .Append(composition.TypeLoader.GetTypes()); composition.Services.AddUnique(); composition.Services.AddUnique(factory => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().Value))); composition.UrlSegmentProviders() .Append(); composition.Services.AddUnique(factory => new MigrationBuilder(factory)); // by default, register a noop factory composition.Services.AddUnique(); // by default composition.Services.AddUnique(); composition.SetCultureDictionaryFactory(); composition.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); composition.Services.AddUnique(); // register the published snapshot accessor - the "current" published snapshot is in the umbraco context composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards composition.Dashboards() .Add(composition.TypeLoader.GetTypes()); // will be injected in controllers when needed to invoke rest endpoints on Our composition.Services.AddUnique(); composition.Services.AddUnique(); // Grid config is not a real config file as we know them composition.Services.AddUnique(); // Config manipulator composition.Services.AddUnique(); // register the umbraco context factory // composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); // 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 composition.PropertyValueConverters() .Remove() .Remove() .Remove(); composition.UrlProviders() .Append() .Append(); composition.MediaUrlProviders() .Append(); composition.Services.AddUnique(); // register properties fallback composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Actions() .Add(() => composition.TypeLoader.GetTypes()); composition.EditorValidators() .Add(() => composition.TypeLoader.GetTypes()); composition.TourFilters(); // replace with web implementation composition.Services.AddUnique(); // 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 composition.OEmbedProviders() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append(); // register back office sections in the order we want them rendered composition.Sections() .Append() .Append() .Append() .Append() .Append() .Append() .Append() .Append(); // register known content apps composition.ContentApps() .Append() .Append() .Append() .Append() .Append() .Append() .Append(); // register published router composition.Services.AddUnique(); // register *all* checks, except those marked [HideFromTypeFinder] of course composition.HealthChecks() .Add(() => composition.TypeLoader.GetTypes()); composition.WithCollectionBuilder() .Add(() => composition.TypeLoader.GetTypes()); composition.Services.AddUnique(); composition.ContentFinders() // all built-in finders in the correct order, // devs can then modify this list on application startup .Append() .Append() .Append() //.Append() // disabled, this is an odd finder .Append() .Append(); composition.Services.AddScoped(); composition.SearchableTrees() .Add(() => composition.TypeLoader.GetTypes()); // replace some services composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); // register distributed cache composition.Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); composition.Services.AddScoped(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddScoped(factory => { var umbCtx = factory.GetRequiredService(); return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService(), factory.GetRequiredService()); }); composition.Services.AddUnique(); // 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. composition.Services.AddUnique(); // register accessors for cultures composition.Services.AddUnique(); composition.Services.AddSingleton(); composition.Services.AddUnique(); // Register noop versions for examine to be overridden by examine composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); } } }