diff --git a/src/Umbraco.Core/Composing/CompositionRoots/RepositoryCompositionRoot.cs b/src/Umbraco.Core/Composing/CompositionRoots/RepositoryCompositionRoot.cs index 2323da165a..42693f119d 100644 --- a/src/Umbraco.Core/Composing/CompositionRoots/RepositoryCompositionRoot.cs +++ b/src/Umbraco.Core/Composing/CompositionRoots/RepositoryCompositionRoot.cs @@ -22,6 +22,7 @@ namespace Umbraco.Core.Composing.CompositionRoots // register cache helpers // the main cache helper is registered by CoreBootManager and is used by most repositories // the disabled one is used by those repositories that have an annotated ctor parameter + // fixme refactor: use a DisabledCacheHelper class (or interface?) so that injection does not depend on name and we can have simple ctor injection container.RegisterSingleton(factory => CacheHelper.CreateDisabledCacheHelper(), DisabledCache); // resolve ctor dependency from GetInstance() runtimeArguments, if possible - 'factory' is diff --git a/src/Umbraco.Core/Composing/IContainer.cs b/src/Umbraco.Core/Composing/IContainer.cs index 331c1e9141..d31b57f564 100644 --- a/src/Umbraco.Core/Composing/IContainer.cs +++ b/src/Umbraco.Core/Composing/IContainer.cs @@ -6,16 +6,62 @@ using System.Threading.Tasks; namespace Umbraco.Core.Composing { + // fixme - must document! + + /// + /// Defines a container for Umbraco. + /// public interface IContainer { - T TryGetInstance(); + /// + /// Gets an instance. + /// + /// The type of the instance. + /// An instance of the specified type. + /// Throws an exception if the container failed to get an instance of the specified type. T GetInstance(); - object GetInstance(Type parameterType); - object ConcreteContainer { get; } + + /// + /// Gets an instance. + /// + /// The type of the instance. + /// An instance of the specified type. + /// Throws an exception if the container failed to get an instance of the specified type. + object GetInstance(Type type); + + /// + /// Tries to get an instance. + /// + /// The type of the instance. + /// An instance of the specified type, or null. + /// Returns null if the container does not know how to get an instance + /// of the specified type. Throws an exception if the container does know how + /// to get an instance of the specified type, but failed to do so. + T TryGetInstance(); + + // fixme document + T GetInstance(object[] args); + + // fixme register direct type? + // fixme register an instance? void RegisterSingleton(Func factory); void Register(Func factory); void Register(Func factory); + + /// + /// Registers and instanciates a collection builder. + /// + /// The type of the collection builder. + /// A collection builder of the specified type. T RegisterCollectionBuilder(); - T GetInstance(object[] args); + + // fixme move away! + object ConcreteContainer { get; } } + + // fixme would be nicer + //public interface IContainer : IContainer + //{ + // T ConcreteContainer { get; } + //} } diff --git a/src/Umbraco.Core/Composing/LightInject/ContainerAdapter.cs b/src/Umbraco.Core/Composing/LightInject/ContainerAdapter.cs index f7ffa68111..99ffb11ace 100644 --- a/src/Umbraco.Core/Composing/LightInject/ContainerAdapter.cs +++ b/src/Umbraco.Core/Composing/LightInject/ContainerAdapter.cs @@ -1,61 +1,56 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using LightInject; namespace Umbraco.Core.Composing.LightInject { - public class ContainerAdapter : IContainer + /// + /// Implements for LightInject. + /// + public class ContainerAdapter : IContainer // fixme rename LightInjectContainer? { - private readonly IServiceContainer container; - - public object ConcreteContainer => container; - - public void RegisterSingleton(Func factory) - { - container.RegisterSingleton(f => factory(this)); - } - - public void Register(Func factory) - { - container.Register(f => factory(this)); - } - - public void Register(Func factory) - { - container.Register((f, x) => factory(this, x)); - } - - public T RegisterCollectionBuilder() - { - return container.RegisterCollectionBuilder(); - } + private readonly IServiceContainer _container; + /// + /// Initializes a new instance of the with a LightInject container. + /// public ContainerAdapter(IServiceContainer container) { - this.container = container; + _container = container; } + // fixme + public object ConcreteContainer => _container; + + /// + public void RegisterSingleton(Func factory) + => _container.RegisterSingleton(f => factory(this)); + + /// + public void Register(Func factory) + => _container.Register(f => factory(this)); + + /// + public void Register(Func factory) + => _container.Register((f, x) => factory(this, x)); + + /// + public T RegisterCollectionBuilder() + => _container.RegisterCollectionBuilder(); + + /// public T TryGetInstance() - { - return container.TryGetInstance(); - } + => _container.TryGetInstance(); + /// public T GetInstance() - { - return container.GetInstance(); - } + => _container.GetInstance(); + /// public T GetInstance(object[] args) - { - return (T)container.GetInstance(typeof(T), args); - } + => (T) _container.GetInstance(typeof(T), args); + /// public object GetInstance(Type type) - { - return container.GetInstance(type); - } + => _container.GetInstance(type); } } diff --git a/src/Umbraco.Core/Composing/LightInjectExtensions.cs b/src/Umbraco.Core/Composing/LightInjectExtensions.cs index 314e03af84..914af001a8 100644 --- a/src/Umbraco.Core/Composing/LightInjectExtensions.cs +++ b/src/Umbraco.Core/Composing/LightInjectExtensions.cs @@ -44,6 +44,7 @@ namespace Umbraco.Core.Composing container.ScopeManagerProvider = new MixedLightInjectScopeManagerProvider(); // self-register + // fixme - WHERE is this used, and should it be a generic container, not LightInject's? container.Register(_ => container); // configure the current container diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs index a96b034d01..ce249d6b4a 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs @@ -46,7 +46,7 @@ namespace Umbraco.Core.Runtime // register filesystems - composition.Container.Register((f, wrappedFileSystem) => new MediaFileSystem(wrappedFileSystem, f.GetInstance(), f.GetInstance())); + composition.Container.Register((f, wrappedFileSystem) => new MediaFileSystem(wrappedFileSystem, f.GetInstance(), f.GetInstance(), f.GetInstance())); composition.Container.RegisterConstructorDependency((factory, parameterInfo) => factory.GetInstance().MediaFileSystem); composition.Container.RegisterSingleton(); diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index c0f13c6e1b..02d3d0a003 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -33,7 +33,7 @@ namespace Umbraco.Tests.IO _container.Register(_ => Mock.Of()); _container.Register(_ => Mock.Of()); - _container.Register((f, x) => new MediaFileSystem(x, f.GetInstance(), f.GetInstance())); + _container.Register((f, x) => new MediaFileSystem(x, f.GetInstance(), f.GetInstance(), f.GetInstance())); _container.Register((f, x) => new NonConfiguredTypeFileSystem(x)); // make sure we start clean diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 41228eb89e..2d842cf741 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -39,7 +39,7 @@ namespace Umbraco.Tests.Models base.Compose(); Container.Register(_ => Mock.Of()); - Container.Register((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance(), factory.GetInstance())); + Container.Register((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance(), factory.GetInstance(), factory.GetInstance())); Container.Register(); Container.Register(_ => Mock.Of()); Container.Register(_ => Mock.Of()); diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 1f4eaf9d8a..f97d6d1ada 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Models // reference, so static ctor runs, so event handlers register // and then, this will reset the width, height... because the file does not exist, of course ;-( - var ignored = new FileUploadPropertyEditor(Mock.Of(), new MediaFileSystem(Mock.Of(), Mock.Of(), Mock.Of())); + var ignored = new FileUploadPropertyEditor(Mock.Of(), new MediaFileSystem(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); var media = MockedMedia.CreateMediaImage(mediaType, -1); media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs index 8df585fb25..a1cf0ba281 100644 --- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs +++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs @@ -72,7 +72,7 @@ namespace Umbraco.Tests.PropertyEditors container.Register(f => Mock.Of()); container.Register(f => Mock.Of()); - var mediaFileSystem = new MediaFileSystem(Mock.Of(), Mock.Of(), Mock.Of()); + var mediaFileSystem = new MediaFileSystem(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of())) { Id = 1 }); diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 7e3d887d77..e091cc8d49 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -117,7 +117,7 @@ namespace Umbraco.Tests.TestHelpers if (logger == null) throw new ArgumentNullException(nameof(logger)); if (eventMessagesFactory == null) throw new ArgumentNullException(nameof(eventMessagesFactory)); - var mediaFileSystem = new MediaFileSystem(Mock.Of(), Mock.Of(), Mock.Of()); + var mediaFileSystem = new MediaFileSystem(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); var externalLoginService = GetLazyService(container, c => new ExternalLoginService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var publicAccessService = GetLazyService(container, c => new PublicAccessService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index d2a9481251..a457b76449 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -270,7 +270,7 @@ namespace Umbraco.Tests.Testing Container.RegisterSingleton(factory => umbracoSettings.Templates); // fixme - The whole MediaFileSystem coupling thing seems broken. - Container.Register((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance(), factory.GetInstance())); + Container.Register((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance(), factory.GetInstance(), factory.GetInstance())); Container.RegisterConstructorDependency((factory, parameterInfo) => factory.GetInstance().MediaFileSystem); Container.RegisterSingleton(factory => ExamineManager.Instance); diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 7a12fd1130..e16e865ab9 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -4,10 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Web; -using System.Web.Mvc; using System.Web.Routing; -using LightInject; -using Microsoft.Web.Infrastructure.DynamicModuleHelper; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.IO; @@ -23,36 +20,76 @@ using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; + + +// fixme +// need an UmbracoInjectedModules that is declared in web.config +// need a web.config configuration section w/ modules = umbraco.webServer/modules +// so it's all explicit [assembly: PreApplicationStartMethod(typeof(Umbraco.Web.ContainerUmbracoModule), "Start")] namespace Umbraco.Web -{ +{ + // fixme + // name that one UmbracoModule, and the nested one UmbracoRequestModule - deals with front-end requests + public class UmbracoModules : IHttpModule + { + private readonly List _modules = new List(); + + /// + public void Init(HttpApplication context) + { + // fixme - need to get moduleTypes from some sort of Umbraco configuration + + foreach (var moduleType in moduleTypes) + { + var module = (IHttpModule) Current.Container.GetInstance(moduleType); + _modules.Add(module); + module.Init(context); + } + } + + /// + public void Dispose() + { + foreach (var module in _modules) + module.Dispose(); + } + } + public class ContainerUmbracoModule : IHttpModule { - private UmbracoModule umbracoModule; + private static readonly Type[] ModuleTypes = + { + typeof(UmbracoModule) + }; + + private readonly List _modules = new List(); public static void Start() - { - DynamicModuleUtility.RegisterModule(typeof(ContainerUmbracoModule)); + { + // registers the ContainerUmbracoModule (without having to have it in web.config) + // fixme - in which order? is it going to be first or last? + // fixme - do we need to remove the original UmbracoModule from web.config then? + HttpApplication.RegisterModule(typeof(ContainerUmbracoModule)); } - public ContainerUmbracoModule() - { - - } - public void Init(HttpApplication context) { - // Should be extended with lazy list of modules from registry - // Example here: https://haacked.com/archive/2011/06/03/dependency-injection-with-asp-net-httpmodules.aspx/ + // see: https://haacked.com/archive/2011/06/03/dependency-injection-with-asp-net-httpmodules.aspx/ - umbracoModule = Current.Container.GetInstance(); - umbracoModule.Init(context); + foreach (var moduleType in ModuleTypes) + { + var module = (IHttpModule) Current.Container.GetInstance(moduleType); + _modules.Add(module); + module.Init(context); + } } public void Dispose() { - umbracoModule.Dispose(); + foreach (var module in _modules) + module.Dispose(); } } @@ -65,32 +102,30 @@ namespace Umbraco.Web public class UmbracoModule : IHttpModule { #region Dependencies - - // modules are *not* instanciated by the container so we have to - // get our dependencies injected manually, through properties, in - // Init(). works for dependencies that are singletons. - - public IUmbracoSettingsSection UmbracoSettings { get; set; } - - public IGlobalSettings GlobalSettings { get; set; } - - public IUmbracoContextAccessor UmbracoContextAccessor { get; set; } - - public IPublishedSnapshotService PublishedSnapshotService { get; set; } - - public IUserService UserService { get; set; } - public UrlProviderCollection UrlProviders { get; set; } + // fixme these dont need to be publish and properties anymore?! - public IRuntimeState Runtime { get; set; } + public IUmbracoSettingsSection UmbracoSettings { get; } - public ILogger Logger { get; set; } + public IGlobalSettings GlobalSettings { get; } - internal PublishedRouter PublishedRouter { get; set; } + public IUmbracoContextAccessor UmbracoContextAccessor { get; } - internal IUmbracoDatabaseFactory DatabaseFactory { get; set; } + public IPublishedSnapshotService PublishedSnapshotService { get; } + + public IUserService UserService { get; } - internal IVariationContextAccessor VariationContextAccessor { get; set; } + public UrlProviderCollection UrlProviders { get; } + + public IRuntimeState Runtime { get; } + + public ILogger Logger { get; } + + internal PublishedRouter PublishedRouter { get; } + + internal IUmbracoDatabaseFactory DatabaseFactory { get; } + + internal IVariationContextAccessor VariationContextAccessor { get; } #endregion @@ -105,8 +140,7 @@ namespace Umbraco.Web ILogger logger, PublishedRouter publishedRouter, IUmbracoDatabaseFactory databaseFactory, - IVariationContextAccessor variationContextAccessor - ) + IVariationContextAccessor variationContextAccessor) { _combinedRouteCollection = new Lazy(CreateRouteCollection); @@ -558,7 +592,7 @@ namespace Umbraco.Web /// public void Init(HttpApplication app) { - if (Core.Composing.Current.RuntimeState.Level == RuntimeLevel.BootFailed) + if (Core.Composing.Current.RuntimeState.Level == RuntimeLevel.BootFailed) // fixme inject the runtimeState! { // there's nothing we can do really app.BeginRequest += (sender, args) => @@ -589,6 +623,7 @@ namespace Umbraco.Web return; } + // fixme // modules **are** instanciated by the container so we **don't** have to // get our dependencies injected manually, through properties. //Core.Composing.Current.Container.InjectProperties(this);