using System.Linq; using System.Web; using System.Web.Security; using Examine; using Microsoft.AspNet.SignalR; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Dashboards; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Runtime; using Umbraco.Core.Services; using Umbraco.Web.Actions; using Umbraco.Web.Cache; using Umbraco.Web.Composing.CompositionExtensions; using Umbraco.Web.ContentApps; using Umbraco.Web.Dictionary; using Umbraco.Web.Editors; using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; using Umbraco.Web.Macros; using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Search; using Umbraco.Web.Sections; using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; using Umbraco.Web.Services; using Umbraco.Web.SignalR; using Umbraco.Web.Templates; using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Current = Umbraco.Web.Composing.Current; using Umbraco.Web.PropertyEditors; namespace Umbraco.Web.Runtime { // web's initial composer composes after core's, and before all core composers [ComposeAfter(typeof(CoreInitialComposer))] [ComposeBefore(typeof(ICoreComposer))] public sealed class WebInitialComposer : ComponentComposer { public override void Compose(Composition composition) { base.Compose(composition); composition.Register(); composition.RegisterUnique(); // required for hybrid accessors composition.ComposeWebMappingProfiles(); //register the install components //NOTE: i tried to not have these registered if we weren't installing or upgrading but post install when the site restarts //it still needs to use the install controller so we can't do that composition.ComposeInstaller(); // register membership stuff composition.Register(factory => Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider()); composition.Register(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetInstance())); composition.Register(Lifetime.Request); composition.Register(factory => factory.GetInstance().PublishedSnapshot.Members); // register accessors for cultures composition.RegisterUnique(); composition.RegisterUnique(); // 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.RegisterUnique(); // register the umbraco context factory composition.RegisterUnique(); // register a per-request HttpContextBase object // is per-request so only one wrapper is created per request composition.Register(factory => new HttpContextWrapper(factory.GetInstance().HttpContext), Lifetime.Request); // register the published snapshot accessor - the "current" published snapshot is in the umbraco context composition.RegisterUnique(); // we should stop injecting UmbracoContext and always inject IUmbracoContextAccessor, however at the moment // there are tons of places (controllers...) which require UmbracoContext in their ctor - so let's register // a way to inject the UmbracoContext - DO NOT register this as Lifetime.Request since LI will dispose the context // in it's own way but we don't want that to happen, we manage its lifetime ourselves. composition.Register(factory => factory.GetInstance().UmbracoContext); composition.Register(factory => { var umbCtx = factory.GetInstance(); return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetInstance()); }, Lifetime.Request); composition.Register(Lifetime.Request); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); // register the umbraco helper - this is Transient! very important! // also, if not level.Run, we cannot really use the helper (during upgrade...) // so inject a "void" helper (not exactly pretty but...) if (composition.RuntimeState.Level == RuntimeLevel.Run) composition.Register(factory => { var umbCtx = factory.GetInstance(); return new UmbracoHelper(umbCtx.IsFrontEndUmbracoRequest ? umbCtx.PublishedRequest?.PublishedContent : null, factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance()); }); else composition.Register(_ => new UmbracoHelper()); // register distributed cache composition.RegisterUnique(f => new DistributedCache()); composition.RegisterUnique(); // replace some services composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(factory => ExamineManager.Instance); // configure the container for web composition.ConfigureForWeb(); composition .ComposeUmbracoControllers(GetType().Assembly) .SetDefaultRenderMvcController(); // default controller for template views composition.SearchableTrees() .Add(() => composition.TypeLoader.GetTypes()); composition.Register(Lifetime.Request); composition.EditorValidators() .Add(() => composition.TypeLoader.GetTypes()); composition.TourFilters(); composition.RegisterUnique(); composition.Actions() .Add(() => composition.TypeLoader.GetTypes()); //we need to eagerly scan controller types since they will need to be routed composition.WithCollectionBuilder() .Add(composition.TypeLoader.GetSurfaceControllers()); var umbracoApiControllerTypes = composition.TypeLoader.GetUmbracoApiControllers().ToList(); composition.WithCollectionBuilder() .Add(umbracoApiControllerTypes); // 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(); // add all known factories, devs can then modify this list on application // startup either by binding to events or in their own global.asax composition.FilteredControllerFactory() .Append(); composition.UrlProviders() .Append() .Append(); composition.MediaUrlProviders() .Append(); composition.RegisterUnique(); 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.RegisterUnique(); composition.RegisterUnique(); // register *all* checks, except those marked [HideFromTypeFinder] of course composition.HealthChecks() .Add(() => composition.TypeLoader.GetTypes()); composition.WithCollectionBuilder() .Add(() => composition.TypeLoader.GetTypes()); // auto-register views composition.RegisterAuto(typeof(UmbracoViewPage<>)); // register published router composition.RegisterUnique(); composition.Register(_ => Current.Configs.Settings().WebRouting); // register preview SignalR hub composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext()); // register properties fallback composition.RegisterUnique(); // register known content apps composition.ContentApps() .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 core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards composition.Dashboards() .Add(composition.TypeLoader.GetTypes()); // register back office trees // the collection builder only accepts types inheriting from TreeControllerBase // and will filter out those that are not attributed with TreeAttribute composition.Trees() .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); // 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(); // replace with web implementation composition.RegisterUnique(); } } }