public override void Compose(Composition composition)
        {
            base.Compose(composition);

            composition.Register <UmbracoInjectedModule>();

            composition.RegisterUnique <IHttpContextAccessor, AspNetHttpContextAccessor>(); // 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 <IMemberService>()));
            composition.Register <MembershipHelper>(Lifetime.Request);
            composition.Register <IPublishedMemberCache>(factory => factory.GetInstance <UmbracoContext>().PublishedSnapshot.Members);

            // register accessors for cultures
            composition.RegisterUnique <IDefaultCultureAccessor, DefaultCultureAccessor>();
            composition.RegisterUnique <IVariationContextAccessor, HybridVariationContextAccessor>();

            // 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 <IUmbracoContextAccessor, HybridUmbracoContextAccessor>();

            // register the umbraco context factory
            composition.RegisterUnique <IUmbracoContextFactory, UmbracoContextFactory>();

            // register a per-request HttpContextBase object
            // is per-request so only one wrapper is created per request
            composition.Register <HttpContextBase>(factory => new HttpContextWrapper(factory.GetInstance <IHttpContextAccessor>().HttpContext), Lifetime.Request);

            // register the published snapshot accessor - the "current" published snapshot is in the umbraco context
            composition.RegisterUnique <IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();

            // 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 <IUmbracoContextAccessor>().UmbracoContext);
            composition.RegisterUnique <IUmbracoTreeSearcherFields, UmbracoTreeSearcherFields>();
            composition.Register <IPublishedContentQuery>(factory =>
            {
                var umbCtx = factory.GetInstance <IUmbracoContextAccessor>();
                return(new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetInstance <IVariationContextAccessor>()));
            }, Lifetime.Request);
            composition.Register <ITagQuery, TagQuery>(Lifetime.Request);

            composition.RegisterUnique <ITemplateRenderer, TemplateRenderer>();
            composition.RegisterUnique <IMacroRenderer, MacroRenderer>();
            composition.RegisterUnique <IUmbracoComponentRenderer, UmbracoComponentRenderer>();

            composition.RegisterUnique <HtmlLocalLinkParser>();
            composition.RegisterUnique <HtmlUrlParser>();
            composition.RegisterUnique <HtmlImageSourceParser>();
            composition.RegisterUnique <RichTextEditorPastedImages>();

            // 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 <UmbracoHelper>(factory =>
                {
                    var umbCtx = factory.GetInstance <UmbracoContext>();
                    return(new UmbracoHelper(umbCtx.IsFrontEndUmbracoRequest ? umbCtx.PublishedRequest?.PublishedContent : null,
                                             factory.GetInstance <ITagQuery>(), factory.GetInstance <ICultureDictionaryFactory>(),
                                             factory.GetInstance <IUmbracoComponentRenderer>(), factory.GetInstance <IPublishedContentQuery>(),
                                             factory.GetInstance <MembershipHelper>()));
                });
            }
            else
            {
                composition.Register(_ => new UmbracoHelper());
            }

            // register distributed cache
            composition.RegisterUnique(f => new DistributedCache());

            composition.RegisterUnique <RoutableDocumentFilter>();

            // replace some services
            composition.RegisterUnique <IEventMessagesFactory, DefaultEventMessagesFactory>();
            composition.RegisterUnique <IEventMessagesAccessor, HybridEventMessagesAccessor>();
            composition.RegisterUnique <ITreeService, TreeService>();
            composition.RegisterUnique <ISectionService, SectionService>();

            composition.RegisterUnique <IDashboardService, DashboardService>();

            composition.RegisterUnique <IExamineManager>(factory => ExamineManager.Instance);

            // configure the container for web
            composition.ConfigureForWeb();

            composition
            .ComposeUmbracoControllers(GetType().Assembly)
            .SetDefaultRenderMvcController <RenderMvcController>();    // default controller for template views

            composition.SearchableTrees()
            .Add(() => composition.TypeLoader.GetTypes <ISearchableTree>());

            composition.Register <UmbracoTreeSearcher>(Lifetime.Request);

            composition.EditorValidators()
            .Add(() => composition.TypeLoader.GetTypes <IEditorValidator>());

            composition.TourFilters();

            composition.RegisterUnique <UmbracoFeatures>();

            composition.Actions()
            .Add(() => composition.TypeLoader.GetTypes <IAction>());

            //we need to eagerly scan controller types since they will need to be routed
            composition.WithCollectionBuilder <SurfaceControllerTypeCollectionBuilder>()
            .Add(composition.TypeLoader.GetSurfaceControllers());
            var umbracoApiControllerTypes = composition.TypeLoader.GetUmbracoApiControllers().ToList();

            composition.WithCollectionBuilder <UmbracoApiControllerTypeCollectionBuilder>()
            .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 <TinyMceValueConverter>()
            .Remove <TextStringValueConverter>()
            .Remove <MarkdownEditorValueConverter>();

            // 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 <RenderControllerFactory>();

            composition.UrlProviders()
            .Append <AliasUrlProvider>()
            .Append <DefaultUrlProvider>();

            composition.MediaUrlProviders()
            .Append <DefaultMediaUrlProvider>();

            composition.RegisterUnique <IImageUrlGenerator, ImageProcessorImageUrlGenerator>();

            composition.RegisterUnique <IContentLastChanceFinder, ContentFinderByConfigured404>();

            composition.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>();
            //only append ContentFinderByRedirectUrl if RedirectUrlTracking is not disabled
            if (composition.Configs.Settings().WebRouting.DisableRedirectUrlTracking == false)
            {
                composition.ContentFinders().Append <ContentFinderByRedirectUrl>();
            }

            composition.RegisterUnique <ISiteDomainHelper, SiteDomainHelper>();

            composition.RegisterUnique <ICultureDictionaryFactory, DefaultCultureDictionaryFactory>();

            // register *all* checks, except those marked [HideFromTypeFinder] of course
            composition.HealthChecks()
            .Add(() => composition.TypeLoader.GetTypes <HealthCheck.HealthCheck>());

            composition.WithCollectionBuilder <HealthCheckNotificationMethodCollectionBuilder>()
            .Add(() => composition.TypeLoader.GetTypes <HealthCheck.NotificationMethods.IHealthCheckNotificationMethod>());

            // auto-register views
            composition.RegisterAuto(typeof(UmbracoViewPage <>));

            // register published router
            composition.RegisterUnique <IPublishedRouter, PublishedRouter>();
            composition.Register(_ => Current.Configs.Settings().WebRouting);

            // register preview SignalR hub
            composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext <PreviewHub>());

            // register properties fallback
            composition.RegisterUnique <IPublishedValueFallback, PublishedValueFallback>();

            // register known content apps
            composition.ContentApps()
            .Append <ListViewContentAppFactory>()
            .Append <ContentEditorContentAppFactory>()
            .Append <ContentInfoContentAppFactory>()
            .Append <ContentTypeDesignContentAppFactory>()
            .Append <ContentTypeListViewContentAppFactory>()
            .Append <ContentTypePermissionsContentAppFactory>()
            .Append <ContentTypeTemplatesContentAppFactory>();

            // register back office sections in the order we want them rendered
            composition.Sections()
            .Append <ContentSection>()
            .Append <MediaSection>()
            .Append <SettingsSection>()
            .Append <PackagesSection>()
            .Append <UsersSection>()
            .Append <MembersSection>()
            .Append <FormsSection>()
            .Append <TranslationSection>();

            // 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 <IDashboard>());

            // 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 <YouTube>()
            .Append <Instagram>()
            .Append <Twitter>()
            .Append <Vimeo>()
            .Append <DailyMotion>()
            .Append <Flickr>()
            .Append <Slideshare>()
            .Append <Kickstarter>()
            .Append <GettyImages>()
            .Append <Ted>()
            .Append <Soundcloud>()
            .Append <Issuu>()
            .Append <Hulu>()
            .Append <Giphy>();


            // replace with web implementation
            composition.RegisterUnique <IPublishedSnapshotRebuilder, Migrations.PostMigrations.PublishedSnapshotRebuilder>();
        }