using System; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PackageActions; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Sync; namespace Umbraco.Core.Composing { /// /// Provides a static service locator for most singletons. /// /// /// This class is initialized with the container in UmbracoApplicationBase, /// right after the container is created in UmbracoApplicationBase.HandleApplicationStart. /// Obviously, this is a service locator, which some may consider an anti-pattern. And yet, /// practically, it works. /// public static class Current { private static IFactory _factory; // TODO: get rid of these oddities // we don't want Umbraco tests to die because the container has not been properly initialized, // for some too-important things such as IShortStringHelper or loggers, so if it's not // registered we setup a default one. We should really refactor our tests so that it does // not happen. private static IShortStringHelper _shortStringHelper; private static ILogger _logger; private static IProfiler _profiler; private static IProfilingLogger _profilingLogger; private static IPublishedValueFallback _publishedValueFallback; private static Configs _configs; /// /// Gets or sets the factory. /// public static IFactory Factory { get { if (_factory == null) throw new InvalidOperationException("No factory has been set."); return _factory; } set { if (_factory != null) throw new InvalidOperationException("A factory has already been set."); if (_configs != null) throw new InvalidOperationException("Configs are unlocked."); _factory = value; } } internal static bool HasFactory => _factory != null; /// /// Resets . Indented for testing only, and not supported in production code. /// /// /// For UNIT TESTS exclusively. /// Resets everything that is 'current'. /// public static void Reset() { _factory.DisposeIfDisposable(); _factory = null; _configs = null; _shortStringHelper = null; _logger = null; _profiler = null; _profilingLogger = null; _publishedValueFallback = null; Resetted?.Invoke(null, EventArgs.Empty); } /// /// Unlocks . Intended for testing only, and not supported in production code. /// /// /// For UNIT TESTS exclusively. /// Unlocks so that it is possible to add configurations /// directly to without having to wire composition. /// public static void UnlockConfigs() { if (_factory != null) throw new InvalidOperationException("Cannot unlock configs when a factory has been set."); _configs = new Configs(); } internal static event EventHandler Resetted; #region Getters public static UmbracoMapper Mapper => _factory.GetInstance(); public static IShortStringHelper ShortStringHelper => _shortStringHelper ?? (_shortStringHelper = _factory?.TryGetInstance() ?? new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(Configs.Settings()))); public static ILogger Logger => _logger ?? (_logger = _factory?.TryGetInstance() ?? new DebugDiagnosticsLogger()); public static IProfiler Profiler => _profiler ?? (_profiler = _factory?.TryGetInstance() ?? new LogProfiler(Logger)); public static IProfilingLogger ProfilingLogger => _profilingLogger ?? (_profilingLogger = _factory?.TryGetInstance()) ?? new ProfilingLogger(Logger, Profiler); public static IRuntimeState RuntimeState => Factory.GetInstance(); public static TypeLoader TypeLoader => Factory.GetInstance(); public static Configs Configs { get { if (_configs != null) return _configs; if (_factory == null) throw new InvalidOperationException("Can not get Current.Config during composition. Use composition.Config."); return _factory.GetInstance(); } } public static IFileSystems FileSystems => Factory.GetInstance(); public static IMediaFileSystem MediaFileSystem => Factory.GetInstance(); public static UrlSegmentProviderCollection UrlSegmentProviders => Factory.GetInstance(); public static CacheRefresherCollection CacheRefreshers => Factory.GetInstance(); public static DataEditorCollection DataEditors => Factory.GetInstance(); public static PropertyEditorCollection PropertyEditors => Factory.GetInstance(); public static ParameterEditorCollection ParameterEditors => Factory.GetInstance(); internal static ManifestValueValidatorCollection ManifestValidators => Factory.GetInstance(); internal static PackageActionCollection PackageActions => Factory.GetInstance(); internal static IPackageActionRunner PackageActionRunner => Factory.GetInstance(); internal static PropertyValueConverterCollection PropertyValueConverters => Factory.GetInstance(); internal static IPublishedModelFactory PublishedModelFactory => Factory.GetInstance(); public static IServerMessenger ServerMessenger => Factory.GetInstance(); public static IServerRegistrar ServerRegistrar => Factory.GetInstance(); public static ICultureDictionaryFactory CultureDictionaryFactory => Factory.GetInstance(); public static AppCaches AppCaches => Factory.GetInstance(); public static ServiceContext Services => Factory.GetInstance(); public static IScopeProvider ScopeProvider => Factory.GetInstance(); public static ISqlContext SqlContext => Factory.GetInstance(); public static IPublishedContentTypeFactory PublishedContentTypeFactory => Factory.GetInstance(); public static IPublishedValueFallback PublishedValueFallback => _publishedValueFallback ?? Factory.GetInstance() ?? new NoopPublishedValueFallback(); public static IVariationContextAccessor VariationContextAccessor => Factory.GetInstance(); #endregion } }