using System;
using System.Collections.Generic;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Composing
{
///
/// Represents a composition.
///
/// Although a composition exposes the application's service container, people should use the
/// extension methods (such as PropertyEditors() or SetPublishedContentModelFactory()) and
/// avoid accessing the container. This is because everything needs to be properly registered and with
/// the proper lifecycle. These methods will take care of it. Directly registering into the container
/// may cause issues.
public class Composition : IRegister
{
private readonly Dictionary _builders = new Dictionary();
private readonly Dictionary> _uniques = new Dictionary>();
private readonly IRegister _register;
///
/// Initializes a new instance of the class.
///
/// A register.
/// A type loader.
/// A logger.
/// The runtime state.
/// Optional configs.
/// An IOHelper
public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs, IIOHelper ioHelper, AppCaches appCaches)
{
_register = register;
TypeLoader = typeLoader;
Logger = logger;
RuntimeState = runtimeState;
Configs = configs;
IOHelper = ioHelper;
AppCaches = appCaches;
}
#region Services
///
/// Gets the logger.
///
public IProfilingLogger Logger { get; }
public IIOHelper IOHelper { get; }
public AppCaches AppCaches { get; }
///
/// Gets the type loader.
///
public TypeLoader TypeLoader { get; }
///
/// Gets the runtime state.
///
public IRuntimeState RuntimeState { get; }
///
/// Gets the configurations.
///
public Configs Configs { get; }
#endregion
#region IRegister
///
public object Concrete => _register.Concrete;
///
public void Register(Type serviceType, Lifetime lifetime = Lifetime.Transient)
=> _register.Register(serviceType, lifetime);
///
public void Register(Type serviceType, Type implementingType, Lifetime lifetime = Lifetime.Transient)
=> _register.Register(serviceType, implementingType, lifetime);
///
public void Register(Func factory, Lifetime lifetime = Lifetime.Transient)
where TService : class
=> _register.Register(factory, lifetime);
///
public void Register(Type serviceType, object instance)
=> _register.Register(serviceType, instance);
///
public void RegisterFor(Lifetime lifetime = Lifetime.Transient)
where TService : class
=> _register.RegisterFor(lifetime);
///
public void RegisterFor(Type implementingType, Lifetime lifetime = Lifetime.Transient)
where TService : class
=> _register.RegisterFor(implementingType, lifetime);
///
public void RegisterFor(Func factory, Lifetime lifetime = Lifetime.Transient)
where TService : class
=> _register.RegisterFor(factory, lifetime);
///
public void RegisterFor(TService instance)
where TService : class
=> _register.RegisterFor(instance);
///
public void RegisterAuto(Type serviceBaseType)
=> _register.RegisterAuto(serviceBaseType);
///
public void ConfigureForWeb()
=> _register.ConfigureForWeb();
///
public IFactory CreateFactory()
{
foreach (var onCreating in OnCreatingFactory.Values)
onCreating();
foreach (var unique in _uniques.Values)
unique(_register);
_uniques.Clear(); // no point keep them around
foreach (var builder in _builders.Values)
builder.RegisterWith(_register);
_builders.Clear(); // no point keep them around
IFactory factory = null;
Configs.RegisterWith(_register, () => factory);
// ReSharper disable once AccessToModifiedClosure -- on purpose
_register.Register(_ => factory, Lifetime.Singleton);
factory = _register.CreateFactory();
return factory;
}
///
/// Gets a dictionary of action to execute when creating the factory.
///
public Dictionary OnCreatingFactory { get; } = new Dictionary();
#endregion
#region Unique
private string GetUniqueName()
=> GetUniqueName(typeof(TService));
private string GetUniqueName(Type serviceType)
=> serviceType.FullName;
private string GetUniqueName()
=> GetUniqueName(typeof(TService), typeof(TTarget));
private string GetUniqueName(Type serviceType, Type targetType)
=> serviceType.FullName + "::" + targetType.FullName;
///
/// Registers a unique service as its own implementation.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUnique(Type serviceType)
=> _uniques[GetUniqueName(serviceType)] = register => register.Register(serviceType, Lifetime.Singleton);
///
/// Registers a unique service with an implementation type.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUnique(Type serviceType, Type implementingType)
=> _uniques[GetUniqueName(serviceType)] = register => register.Register(serviceType, implementingType, Lifetime.Singleton);
///
/// Registers a unique service with an implementation factory.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUnique(Func factory)
where TService : class
=> _uniques[GetUniqueName()] = register => register.Register(factory, Lifetime.Singleton);
///
/// Registers a unique service with an implementing instance.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUnique(Type serviceType, object instance)
=> _uniques[GetUniqueName(serviceType)] = register => register.Register(serviceType, instance);
///
/// Registers a unique service for a target, as its own implementation.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUniqueFor()
where TService : class
=> _uniques[GetUniqueName()] = register => register.RegisterFor(Lifetime.Singleton);
///
/// Registers a unique service for a target, with an implementing type.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUniqueFor(Type implementingType)
where TService : class
=> _uniques[GetUniqueName()] = register => register.RegisterFor(implementingType, Lifetime.Singleton);
///
/// Registers a unique service for a target, with an implementation factory.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUniqueFor(Func factory)
where TService : class
=> _uniques[GetUniqueName()] = register => register.RegisterFor(factory, Lifetime.Singleton);
///
/// Registers a unique service for a target, with an implementing instance.
///
/// Unique services have one single implementation, and a Singleton lifetime.
public void RegisterUniqueFor(TService instance)
where TService : class
=> _uniques[GetUniqueName()] = register => register.RegisterFor(instance);
#endregion
#region Collection Builders
///
/// Gets a collection builder (and registers the collection).
///
/// The type of the collection builder.
/// The collection builder.
public TBuilder WithCollectionBuilder()
where TBuilder: ICollectionBuilder, new()
{
var typeOfBuilder = typeof(TBuilder);
if (_builders.TryGetValue(typeOfBuilder, out var o))
return (TBuilder) o;
var builder = new TBuilder();
_builders[typeOfBuilder] = builder;
return builder;
}
#endregion
}
}