This commit is contained in:
Stephan
2018-06-29 13:17:46 +02:00
parent 3bd7eedf03
commit 9bc8ace8db
12 changed files with 170 additions and 92 deletions

View File

@@ -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

View File

@@ -6,16 +6,62 @@ using System.Threading.Tasks;
namespace Umbraco.Core.Composing
{
// fixme - must document!
/// <summary>
/// Defines a container for Umbraco.
/// </summary>
public interface IContainer
{
T TryGetInstance<T>();
/// <summary>
/// Gets an instance.
/// </summary>
/// <typeparam name="T">The type of the instance.</typeparam>
/// <returns>An instance of the specified type.</returns>
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
T GetInstance<T>();
object GetInstance(Type parameterType);
object ConcreteContainer { get; }
/// <summary>
/// Gets an instance.
/// </summary>
/// <param name="type">The type of the instance.</param>
/// <returns>An instance of the specified type.</returns>
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
object GetInstance(Type type);
/// <summary>
/// Tries to get an instance.
/// </summary>
/// <typeparam name="T">The type of the instance.</typeparam>
/// <returns>An instance of the specified type, or null.</returns>
/// <remarks>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.</remarks>
T TryGetInstance<T>();
// fixme document
T GetInstance<T>(object[] args);
// fixme register direct type?
// fixme register an instance?
void RegisterSingleton<T>(Func<IContainer, T> factory);
void Register<T>(Func<IContainer, T> factory);
void Register<T, TService>(Func<IContainer, T, TService> factory);
/// <summary>
/// Registers and instanciates a collection builder.
/// </summary>
/// <typeparam name="T">The type of the collection builder.</typeparam>
/// <returns>A collection builder of the specified type.</returns>
T RegisterCollectionBuilder<T>();
T GetInstance<T>(object[] args);
// fixme move away!
object ConcreteContainer { get; }
}
// fixme would be nicer
//public interface IContainer<T> : IContainer
//{
// T ConcreteContainer { get; }
//}
}

View File

@@ -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
/// <summary>
/// Implements <see cref="IContainer"/> for LightInject.
/// </summary>
public class ContainerAdapter : IContainer // fixme rename LightInjectContainer?
{
private readonly IServiceContainer container;
public object ConcreteContainer => container;
public void RegisterSingleton<T>(Func<IContainer, T> factory)
{
container.RegisterSingleton(f => factory(this));
}
public void Register<T>(Func<IContainer, T> factory)
{
container.Register(f => factory(this));
}
public void Register<T, TService>(Func<IContainer, T, TService> factory)
{
container.Register<T, TService>((f, x) => factory(this, x));
}
public T RegisterCollectionBuilder<T>()
{
return container.RegisterCollectionBuilder<T>();
}
private readonly IServiceContainer _container;
/// <summary>
/// Initializes a new instance of the <see cref="ContainerAdapter"/> with a LightInject container.
/// </summary>
public ContainerAdapter(IServiceContainer container)
{
this.container = container;
_container = container;
}
// fixme
public object ConcreteContainer => _container;
/// <inheritdoc />
public void RegisterSingleton<T>(Func<IContainer, T> factory)
=> _container.RegisterSingleton(f => factory(this));
/// <inheritdoc />
public void Register<T>(Func<IContainer, T> factory)
=> _container.Register(f => factory(this));
/// <inheritdoc />
public void Register<T, TService>(Func<IContainer, T, TService> factory)
=> _container.Register<T, TService>((f, x) => factory(this, x));
/// <inheritdoc />
public T RegisterCollectionBuilder<T>()
=> _container.RegisterCollectionBuilder<T>();
/// <inheritdoc />
public T TryGetInstance<T>()
{
return container.TryGetInstance<T>();
}
=> _container.TryGetInstance<T>();
/// <inheritdoc />
public T GetInstance<T>()
{
return container.GetInstance<T>();
}
=> _container.GetInstance<T>();
/// <inheritdoc />
public T GetInstance<T>(object[] args)
{
return (T)container.GetInstance(typeof(T), args);
}
=> (T) _container.GetInstance(typeof(T), args);
/// <inheritdoc />
public object GetInstance(Type type)
{
return container.GetInstance(type);
}
=> _container.GetInstance(type);
}
}

View File

@@ -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<IServiceContainer>(_ => container);
// configure the current container

View File

@@ -46,7 +46,7 @@ namespace Umbraco.Core.Runtime
// register filesystems
composition.Container.Register<IFileSystem, MediaFileSystem>((f, wrappedFileSystem) => new MediaFileSystem(wrappedFileSystem, f.GetInstance<IContentSection>(), f.GetInstance<ILogger>()));
composition.Container.Register<IFileSystem, MediaFileSystem>((f, wrappedFileSystem) => new MediaFileSystem(wrappedFileSystem, f.GetInstance<IContentSection>(), f.GetInstance<IMediaPathScheme>(), f.GetInstance<ILogger>()));
composition.Container.RegisterConstructorDependency((factory, parameterInfo) => factory.GetInstance<FileSystems>().MediaFileSystem);
composition.Container.RegisterSingleton<FileSystems>();

View File

@@ -33,7 +33,7 @@ namespace Umbraco.Tests.IO
_container.Register(_ => Mock.Of<IDataTypeService>());
_container.Register(_ => Mock.Of<IContentSection>());
_container.Register<IFileSystem, MediaFileSystem>((f, x) => new MediaFileSystem(x, f.GetInstance<IContentSection>(), f.GetInstance<ILogger>()));
_container.Register<IFileSystem, MediaFileSystem>((f, x) => new MediaFileSystem(x, f.GetInstance<IContentSection>(), f.GetInstance<IMediaPathScheme>(), f.GetInstance<ILogger>()));
_container.Register<IFileSystem, NonConfiguredTypeFileSystem>((f, x) => new NonConfiguredTypeFileSystem(x));
// make sure we start clean

View File

@@ -39,7 +39,7 @@ namespace Umbraco.Tests.Models
base.Compose();
Container.Register(_ => Mock.Of<ILogger>());
Container.Register<IFileSystem, MediaFileSystem>((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance<IContentSection>(), factory.GetInstance<ILogger>()));
Container.Register<IFileSystem, MediaFileSystem>((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance<IContentSection>(), factory.GetInstance<IMediaPathScheme>(), factory.GetInstance<ILogger>()));
Container.Register<FileSystems>();
Container.Register(_ => Mock.Of<IDataTypeService>());
Container.Register(_ => Mock.Of<IContentSection>());

View File

@@ -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<ILogger>(), new MediaFileSystem(Mock.Of<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<ILogger>()));
var ignored = new FileUploadPropertyEditor(Mock.Of<ILogger>(), new MediaFileSystem(Mock.Of<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<IMediaPathScheme>(), Mock.Of<ILogger>()));
var media = MockedMedia.CreateMediaImage(mediaType, -1);
media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Tests.PropertyEditors
container.Register<ILogger, PerContainerLifetime>(f => Mock.Of<ILogger>());
container.Register<IContentSection, PerContainerLifetime>(f => Mock.Of<IContentSection>());
var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<ILogger>());
var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<IMediaPathScheme>(), Mock.Of<ILogger>());
var dataTypeService = new TestObjects.TestDataTypeService(
new DataType(new ImageCropperPropertyEditor(Mock.Of<ILogger>(), mediaFileSystem, Mock.Of<IContentSection>())) { Id = 1 });

View File

@@ -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<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<ILogger>());
var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<IMediaPathScheme>(), Mock.Of<ILogger>());
var externalLoginService = GetLazyService<IExternalLoginService>(container, c => new ExternalLoginService(scopeProvider, logger, eventMessagesFactory, GetRepo<IExternalLoginRepository>(c)));
var publicAccessService = GetLazyService<IPublicAccessService>(container, c => new PublicAccessService(scopeProvider, logger, eventMessagesFactory, GetRepo<IPublicAccessRepository>(c)));

View File

@@ -270,7 +270,7 @@ namespace Umbraco.Tests.Testing
Container.RegisterSingleton(factory => umbracoSettings.Templates);
// fixme - The whole MediaFileSystem coupling thing seems broken.
Container.Register<IFileSystem, MediaFileSystem>((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance<IContentSection>(), factory.GetInstance<ILogger>()));
Container.Register<IFileSystem, MediaFileSystem>((factory, fileSystem) => new MediaFileSystem(fileSystem, factory.GetInstance<IContentSection>(), factory.GetInstance<IMediaPathScheme>(), factory.GetInstance<ILogger>()));
Container.RegisterConstructorDependency((factory, parameterInfo) => factory.GetInstance<FileSystems>().MediaFileSystem);
Container.RegisterSingleton<IExamineManager>(factory => ExamineManager.Instance);

View File

@@ -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<IHttpModule> _modules = new List<IHttpModule>();
/// <inheritdoc />
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);
}
}
/// <inheritdoc />
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<IHttpModule> _modules = new List<IHttpModule>();
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>();
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<RouteCollection>(CreateRouteCollection);
@@ -558,7 +592,7 @@ namespace Umbraco.Web
/// <param name="app"></param>
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);