diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs
index 4e55bb86a9..58e55b91ae 100644
--- a/src/Umbraco.Core/CoreBootManager.cs
+++ b/src/Umbraco.Core/CoreBootManager.cs
@@ -1,10 +1,12 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Web;
+using System.Threading.Tasks;
using AutoMapper;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.IO;
+using Umbraco.Core.LightInject;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Mapping;
using Umbraco.Core.Models.PublishedContent;
@@ -12,22 +14,20 @@ using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Migrations;
-using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
-using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Profiling;
using Umbraco.Core.PropertyEditors;
-using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Publishing;
using Umbraco.Core.Macros;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Core.Strings;
-using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
+
namespace Umbraco.Core
{
+
///
/// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
///
@@ -36,31 +36,32 @@ namespace Umbraco.Core
///
public class CoreBootManager : IBootManager
{
- private ProfilingLogger _profilingLogger;
+ internal ServiceContainer Container { get; private set; }
+ private ServiceContainer _appStartupEvtContainer;
+ protected ProfilingLogger ProfilingLogger { get; private set; }
private DisposableTimer _timer;
+ protected PluginManager PluginManager { get; private set; }
+ private CacheHelper _cacheHelper;
+
private bool _isInitialized = false;
private bool _isStarted = false;
private bool _isComplete = false;
- private readonly IServiceProvider _serviceProvider = new ActivatorServiceProvider();
private readonly UmbracoApplicationBase _umbracoApplication;
- protected ApplicationContext ApplicationContext { get; set; }
- protected CacheHelper ApplicationCache { get; set; }
- protected PluginManager PluginManager { get; private set; }
+
+ protected ApplicationContext ApplicationContext { get; private set; }
protected UmbracoApplicationBase UmbracoApplication
{
get { return _umbracoApplication; }
}
- protected IServiceProvider ServiceProvider
- {
- get { return _serviceProvider; }
- }
+ protected IServiceProvider ServiceProvider { get; private set; }
public CoreBootManager(UmbracoApplicationBase umbracoApplication)
{
if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication");
_umbracoApplication = umbracoApplication;
+ Container = new ServiceContainer();
}
public virtual IBootManager Initialize()
@@ -68,57 +69,47 @@ namespace Umbraco.Core
if (_isInitialized)
throw new InvalidOperationException("The boot manager has already been initialized");
- InitializeLoggerResolver();
- InitializeProfilerResolver();
+ //Create logger/profiler, and their resolvers, these are special resolvers that can be resolved before frozen so we can start logging
+ var logger = CreateLogger();
+ LoggerResolver.Current = new LoggerResolver(logger) {CanResolveBeforeFrozen = true};
+ var profiler = CreateProfiler();
+ ProfilerResolver.Current = new ProfilerResolver(profiler) {CanResolveBeforeFrozen = true};
+ ProfilingLogger = new ProfilingLogger(logger, profiler);
- _profilingLogger = new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler);
+ _timer = ProfilingLogger.DebugDuration("Umbraco application starting", "Umbraco application startup complete");
- _timer = _profilingLogger.DebugDuration("Umbraco application starting", "Umbraco application startup complete");
+ //create the plugin manager
+ //TODO: this is currently a singleton but it would be better if it weren't. Unfortunately the only way to get
+ // rid of this singleton would be to put it into IoC and then use the ServiceLocator pattern.
+ _cacheHelper = CreateApplicationCache();
+ ServiceProvider = new ActivatorServiceProvider();
+ PluginManager.Current = PluginManager = new PluginManager(ServiceProvider, _cacheHelper.RuntimeCache, ProfilingLogger, true);
- CreateApplicationCache();
+ //build up IoC
+ Container = BuildContainer();
- //create and set the plugin manager (I'd much prefer to not use this singleton anymore but many things are using it unfortunately and
- // the way that it is setup, there must only ever be one per app so without IoC it would be hard to make this not a singleton)
- PluginManager = new PluginManager(ServiceProvider, ApplicationCache.RuntimeCache, _profilingLogger);
- PluginManager.Current = PluginManager;
+ //set the singleton resolved from the core container
+ ApplicationContext.Current = ApplicationContext = Container.GetInstance();
- //Create the legacy prop-eds mapping
+ //TODO: Remove these for v8!
LegacyPropertyEditorIdToAliasConverter.CreateMappingsForCoreEditors();
LegacyParameterEditorAliasConverter.CreateMappingsForCoreEditors();
-
- //create database and service contexts for the app context
- var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, LoggerResolver.Current.Logger);
+ //TODO: Make this as part of the db ctor!
Database.Mapper = new PetaPocoMapper();
-
- var dbContext = new DatabaseContext(
- dbFactory,
- LoggerResolver.Current.Logger,
- SqlSyntaxProviders.CreateDefault(LoggerResolver.Current.Logger));
-
- //initialize the DatabaseContext
- dbContext.Initialize();
- var serviceContext = new ServiceContext(
- new RepositoryFactory(ApplicationCache, LoggerResolver.Current.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
- new PetaPocoUnitOfWorkProvider(dbFactory),
- new FileUnitOfWorkProvider(),
- new PublishingStrategy(),
- ApplicationCache,
- LoggerResolver.Current.Logger);
-
- CreateApplicationContext(dbContext, serviceContext);
-
- InitializeApplicationEventsResolver();
+ //Create a 'child'container which is a copy of all of the current registrations and begin a sub scope for it
+ // this child container will be used to manage the application event handler instances and the scope will be
+ // completed at the end of the boot process to allow garbage collection
+ _appStartupEvtContainer = Container.CreateChildContainer();
+ _appStartupEvtContainer.BeginScope();
+ _appStartupEvtContainer.RegisterCollection(PluginManager.ResolveApplicationStartupHandlers());
+ ConfigureServices(Container);
InitializeResolvers();
-
-
-
InitializeModelMappers();
//now we need to call the initialize methods
- ApplicationEventsResolver.Current.ApplicationEventHandlers
- .ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
+ Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
_isInitialized = true;
@@ -126,28 +117,76 @@ namespace Umbraco.Core
}
///
- /// Creates and assigns the application context singleton
+ /// Build the core container which contains all core things requird to build an app context
///
- ///
- ///
- protected virtual void CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
+ private ServiceContainer BuildContainer()
{
- //create the ApplicationContext
- ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext, ApplicationCache, _profilingLogger);
+ var container = new ServiceContainer();
+ container.Register(factory => UmbracoConfig.For.UmbracoSettings());
+ container.Register(factory => _cacheHelper, new PerContainerLifetime());
+ container.Register(factory => _cacheHelper.RuntimeCache, new PerContainerLifetime());
+ container.Register(factory => ProfilingLogger.Logger, new PerContainerLifetime());
+ container.Register(factory => ProfilingLogger.Profiler, new PerContainerLifetime());
+ container.Register(factory => ProfilingLogger, new PerContainerLifetime());
+ container.Register();
+ container.Register(factory => PluginManager, new PerContainerLifetime());
+ container.Register(factory => new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, factory.GetInstance()));
+ container.Register(factory => GetDbContext(factory), new PerContainerLifetime());
+ container.Register(factory => SqlSyntaxProviders.CreateDefault(factory.GetInstance()));
+ container.Register();
+ container.Register();
+ container.Register();
+ container.Register();
+ container.Register(factory => new ServiceContext(
+ factory.GetInstance(),
+ factory.GetInstance(),
+ factory.GetInstance(),
+ factory.GetInstance(),
+ factory.GetInstance(),
+ factory.GetInstance()));
+ container.Register(new PerContainerLifetime());
+
+ return container;
}
///
- /// Creates and assigns the ApplicationCache based on a new instance of System.Web.Caching.Cache
+ /// Called to customize the IoC container
///
- protected virtual void CreateApplicationCache()
+ ///
+ internal virtual void ConfigureServices(ServiceContainer container)
+ {
+ container.Register(factory => FileSystemProviderManager.Current.GetFileSystemProvider());
+ }
+
+ ///
+ /// Creates and initializes the db context when IoC requests it
+ ///
+ ///
+ ///
+ private DatabaseContext GetDbContext(IServiceFactory container)
+ {
+ var dbCtx = new DatabaseContext(
+ container.GetInstance(),
+ container.GetInstance(),
+ container.GetInstance());
+
+ //when it's first created we need to initialize it
+ dbCtx.Initialize();
+ return dbCtx;
+ }
+
+ ///
+ /// Creates the ApplicationCache based on a new instance of System.Web.Caching.Cache
+ ///
+ protected virtual CacheHelper CreateApplicationCache()
{
var cacheHelper = new CacheHelper(
- new ObjectCacheRuntimeCacheProvider(),
- new StaticCacheProvider(),
+ new ObjectCacheRuntimeCacheProvider(),
+ new StaticCacheProvider(),
//we have no request based cache when not running in web-based context
- new NullCacheProvider());
+ new NullCacheProvider());
- ApplicationCache = cacheHelper;
+ return cacheHelper;
}
///
@@ -161,7 +200,8 @@ namespace Umbraco.Core
{
Mapper.Initialize(configuration =>
{
- foreach (var m in ApplicationEventsResolver.Current.ApplicationEventHandlers.OfType())
+ //foreach (var m in ApplicationEventsResolver.Current.ApplicationEventHandlers.OfType())
+ foreach (var m in _appStartupEvtContainer.GetAllInstances().OfType())
{
m.ConfigureMappings(configuration, ApplicationContext);
}
@@ -169,50 +209,19 @@ namespace Umbraco.Core
}
///
- /// Special method to initialize the LoggerResolver
+ /// Creates the application's ILogger
///
- protected virtual void InitializeLoggerResolver()
+ protected virtual ILogger CreateLogger()
{
- LoggerResolver.Current = new LoggerResolver(Logger.CreateWithDefaultLog4NetConfiguration())
- {
- //This is another special resolver that needs to be resolvable before resolution is frozen
- //since it is used for profiling the application startup
- CanResolveBeforeFrozen = true
- };
+ return Logger.CreateWithDefaultLog4NetConfiguration();
}
///
- /// Special method to initialize the ProfilerResolver
+ /// Creates the application's IProfiler
///
- protected virtual void InitializeProfilerResolver()
+ protected virtual IProfiler CreateProfiler()
{
- //By default we'll initialize the Log profiler (in the web project, we'll override with the web profiler)
- ProfilerResolver.Current = new ProfilerResolver(new LogProfiler(LoggerResolver.Current.Logger))
- {
- //This is another special resolver that needs to be resolvable before resolution is frozen
- //since it is used for profiling the application startup
- CanResolveBeforeFrozen = true
- };
- }
-
- ///
- /// Special method to initialize the ApplicationEventsResolver and any modifications required for it such
- /// as adding custom types to the resolver.
- ///
- protected virtual void InitializeApplicationEventsResolver()
- {
- //find and initialize the application startup handlers, we need to initialize this resolver here because
- //it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to
- //events and to call their events during bootup.
- //ApplicationStartupHandler.RegisterHandlers();
- //... and set the special flag to let us resolve before frozen resolution
- ApplicationEventsResolver.Current = new ApplicationEventsResolver(
- ServiceProvider,
- LoggerResolver.Current.Logger,
- PluginManager.ResolveApplicationStartupHandlers())
- {
- CanResolveBeforeFrozen = true
- };
+ return new LogProfiler(ProfilingLogger.Logger);
}
///
@@ -223,7 +232,7 @@ namespace Umbraco.Core
/// Absolute
protected virtual void InitializeApplicationRootPath(string rootPath)
{
- Umbraco.Core.IO.IOHelper.SetRootDirectory(rootPath);
+ IO.IOHelper.SetRootDirectory(rootPath);
}
///
@@ -238,8 +247,7 @@ namespace Umbraco.Core
throw new InvalidOperationException("The boot manager has already been initialized");
//call OnApplicationStarting of each application events handler
- ApplicationEventsResolver.Current.ApplicationEventHandlers
- .ForEach(x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext));
+ Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext));
if (afterStartup != null)
{
@@ -264,11 +272,10 @@ namespace Umbraco.Core
FreezeResolution();
//call OnApplicationStarting of each application events handler
- ApplicationEventsResolver.Current.ApplicationEventHandlers
- .ForEach(x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
+ Parallel.ForEach(_appStartupEvtContainer.GetAllInstances(), x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
- //Now, startup all of our legacy startup handler
- ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers();
+ //end the current scope which was created to intantiate all of the startup handlers
+ _appStartupEvtContainer.EndCurrentScope();
if (afterComplete != null)
{
@@ -298,12 +305,12 @@ namespace Umbraco.Core
///
protected virtual void InitializeResolvers()
{
- PropertyEditorResolver.Current = new PropertyEditorResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolvePropertyEditors());
- ParameterEditorResolver.Current = new ParameterEditorResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveParameterEditors());
+ PropertyEditorResolver.Current = new PropertyEditorResolver(ServiceProvider, ProfilingLogger.Logger, () => PluginManager.ResolvePropertyEditors());
+ ParameterEditorResolver.Current = new ParameterEditorResolver(ServiceProvider, ProfilingLogger.Logger, () => PluginManager.ResolveParameterEditors());
//setup the validators resolver with our predefined validators
ValidatorsResolver.Current = new ValidatorsResolver(
- ServiceProvider, LoggerResolver.Current.Logger, new[]
+ ServiceProvider, ProfilingLogger.Logger, new[]
{
new Lazy(() => typeof (RequiredManifestValueValidator)),
new Lazy(() => typeof (RegexValidator)),
@@ -313,62 +320,103 @@ namespace Umbraco.Core
});
//by default we'll use the standard configuration based sync
- ServerRegistrarResolver.Current = new ServerRegistrarResolver(
- new ConfigServerRegistrar());
+ ServerRegistrarResolver.Current = new ServerRegistrarResolver(Container, typeof(ConfigServerRegistrar));
//by default (outside of the web) we'll use the default server messenger without
//supplying a username/password, this will automatically disable distributed calls
// .. we'll override this in the WebBootManager
- ServerMessengerResolver.Current = new ServerMessengerResolver(
- new DefaultServerMessenger());
+ ServerMessengerResolver.Current = new ServerMessengerResolver(Container, typeof (DefaultServerMessenger));
MappingResolver.Current = new MappingResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveAssignedMapperTypes());
-
+
//RepositoryResolver.Current = new RepositoryResolver(
// new RepositoryFactory(ApplicationCache));
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveCacheRefreshers());
-
+
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveMacroRenderings());
PackageActionsResolver.Current = new PackageActionsResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolvePackageActions());
ActionsResolver.Current = new ActionsResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveActions());
//the database migration objects
MigrationResolver.Current = new MigrationResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
() => PluginManager.ResolveTypes());
// need to filter out the ones we dont want!!
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ ServiceProvider, ProfilingLogger.Logger,
PluginManager.ResolveTypes());
// use the new DefaultShortStringHelper
- ShortStringHelperResolver.Current = new ShortStringHelperResolver(
- //new LegacyShortStringHelper());
- new DefaultShortStringHelper().WithDefaultConfig());
+ ShortStringHelperResolver.Current = new ShortStringHelperResolver(Container,
+ factory => new DefaultShortStringHelper(factory.GetInstance()).WithDefaultConfig());
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
- ServiceProvider, LoggerResolver.Current.Logger,
+ Container, ProfilingLogger.Logger,
typeof(DefaultUrlSegmentProvider));
// by default, no factory is activated
- PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver();
+ PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver(Container);
}
+
+ /////
+ ///// An IoC lifetime that will dispose instances at the end of the bootup sequence
+ /////
+ //private class BootManagerLifetime : ILifetime
+ //{
+ // public BootManagerLifetime(UmbracoApplicationBase appBase)
+ // {
+ // appBase.ApplicationStarted += appBase_ApplicationStarted;
+ // }
+
+ // void appBase_ApplicationStarted(object sender, EventArgs e)
+ // {
+ // throw new NotImplementedException();
+ // }
+
+ // private object _instance;
+
+ // ///
+ // /// Returns a service instance according to the specific lifetime characteristics.
+ // ///
+ // /// The function delegate used to create a new service instance.
+ // /// The of the current service request.
+ // /// The requested services instance.
+ // public object GetInstance(Func createInstance, Scope scope)
+ // {
+ // if (_instance == null)
+ // {
+ // _instance = createInstance();
+
+ // var disposable = _instance as IDisposable;
+ // if (disposable != null)
+ // {
+ // if (scope == null)
+ // {
+ // throw new InvalidOperationException("Attempt to create an disposable object without a current scope.");
+ // }
+ // scope.TrackInstance(disposable);
+ // }
+
+ // }
+ // return createInstance;
+ // }
+ //}
}
}
diff --git a/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs b/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs
index 80abfb0eaf..8d744c90a6 100644
--- a/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs
+++ b/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs
@@ -1,3 +1,6 @@
+using System;
+using System.Linq.Expressions;
+using Umbraco.Core.LightInject;
using Umbraco.Core.ObjectResolution;
namespace Umbraco.Core.Dictionary
@@ -5,14 +8,34 @@ namespace Umbraco.Core.Dictionary
///
/// Resolves the current CultureDictionaryFactory
///
- public sealed class CultureDictionaryFactoryResolver : SingleObjectResolverBase
+ public sealed class CultureDictionaryFactoryResolver : ContainerSingleObjectResolver
{
- internal CultureDictionaryFactoryResolver(ICultureDictionaryFactory factory)
+ ///
+ /// Initializes the resolver to use IoC
+ ///
+ ///
+ ///
+ internal CultureDictionaryFactoryResolver(IServiceContainer container, Type implementationType)
+ : base(container, implementationType)
+ {
+ }
+
+ internal CultureDictionaryFactoryResolver(ICultureDictionaryFactory factory)
: base(factory)
{
}
- ///
+ ///
+ /// Initializes the resolver to use IoC
+ ///
+ ///
+ ///
+ internal CultureDictionaryFactoryResolver(IServiceContainer container, Expression> implementationType)
+ : base(container, implementationType)
+ {
+ }
+
+ ///
/// Can be used by developers at runtime to set their ICultureDictionaryFactory at app startup
///
///
diff --git a/src/Umbraco.Core/LightInject/LightInject.cs b/src/Umbraco.Core/LightInject/LightInject.cs
new file mode 100644
index 0000000000..5077aa251c
--- /dev/null
+++ b/src/Umbraco.Core/LightInject/LightInject.cs
@@ -0,0 +1,6067 @@
+/*********************************************************************************
+ The MIT License (MIT)
+
+ Copyright (c) 2014 bernhard.richter@gmail.com
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+******************************************************************************
+ LightInject version 3.0.2.2
+ http://www.lightinject.net/
+ http://twitter.com/bernhardrichter
+******************************************************************************/
+[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1126:PrefixCallsCorrectly", Justification = "Reviewed")]
+[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "No inheritance")]
+[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Single source file deployment.")]
+[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:FileMustHaveHeader", Justification = "Custom header.")]
+[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "All public members are documented.")]
+[module: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Performance")]
+
+namespace Umbraco.Core.LightInject
+{
+ using System;
+ using System.Collections.Concurrent;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.IO;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.Remoting.Messaging;
+ using System.Text;
+ using System.Text.RegularExpressions;
+ using System.Threading;
+
+ ///
+ /// Defines a set of methods used to register services into the service container.
+ ///
+ internal interface IServiceRegistry
+ {
+ ///
+ /// Gets a list of instances that represents the
+ /// registered services.
+ ///
+ IEnumerable AvailableServices { get; }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ void Register(Type serviceType, Type implementingType);
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(Type serviceType, Type implementingType, ILifetime lifetime);
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ void Register(Type serviceType, Type implementingType, string serviceName);
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(Type serviceType, Type implementingType, string serviceName, ILifetime lifetime);
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ void Register() where TImplementation : TService;
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(ILifetime lifetime) where TImplementation : TService;
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ void Register(string serviceName) where TImplementation : TService;
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(string serviceName, ILifetime lifetime) where TImplementation : TService;
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ void RegisterInstance(TService instance);
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ /// The name of the service.
+ void RegisterInstance(TService instance, string serviceName);
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ void RegisterInstance(Type serviceType, object instance);
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ /// The name of the service.
+ void RegisterInstance(Type serviceType, object instance, string serviceName);
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The service type to register.
+ void Register();
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The service type to register.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(ILifetime lifetime);
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The concrete type to register.
+ void Register(Type serviceType);
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The concrete type to register.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(Type serviceType, ILifetime lifetime);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ void Register(Expression> factory);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The parameter type.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ void Register(Expression> factory);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The parameter type.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ void Register(Expression> factory, string serviceName);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ void Register(Expression> factory);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ void Register(Expression> factory, string serviceName);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ void Register(Expression> factory);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ void Register(Expression> factory, string serviceName);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The type of the fourth parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ void Register(Expression> factory);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The type of the fourth parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ void Register(Expression> factory, string serviceName);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(Expression> factory, ILifetime lifetime);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ /// The name of the service.
+ void Register(Expression> factory, string serviceName);
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ /// The name of the service.
+ /// The instance that controls the lifetime of the registered service.
+ void Register(Expression> factory, string serviceName, ILifetime lifetime);
+
+ ///
+ /// Registers a custom factory delegate used to create services that is otherwise unknown to the service container.
+ ///
+ /// Determines if the service can be created by the delegate.
+ /// Creates a service instance according to the predicate.
+ void RegisterFallback(Func predicate, Func factory);
+
+ ///
+ /// Registers a custom factory delegate used to create services that is otherwise unknown to the service container.
+ ///
+ /// Determines if the service can be created by the delegate.
+ /// Creates a service instance according to the predicate.
+ /// The instance that controls the lifetime of the registered service.
+ void RegisterFallback(Func predicate, Func factory, ILifetime lifetime);
+
+ ///
+ /// Registers a service based on a instance.
+ ///
+ /// The instance that contains service metadata.
+ void Register(ServiceRegistration serviceRegistration);
+
+ ///
+ /// Registers composition roots from the given .
+ ///
+ /// The assembly to be scanned for services.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ void RegisterAssembly(Assembly assembly);
+
+ ///
+ /// Registers services from the given .
+ ///
+ /// The assembly to be scanned for services.
+ /// A function delegate that determines if a service implementation should be registered.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ void RegisterAssembly(Assembly assembly, Func shouldRegister);
+
+ ///
+ /// Registers services from the given .
+ ///
+ /// The assembly to be scanned for services.
+ /// The instance that controls the lifetime of the registered service.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ void RegisterAssembly(Assembly assembly, Func lifetime);
+
+ ///
+ /// Registers services from the given .
+ ///
+ /// The assembly to be scanned for services.
+ /// The factory that controls the lifetime of the registered service.
+ /// A function delegate that determines if a service implementation should be registered.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ void RegisterAssembly(Assembly assembly, Func lifetimeFactory, Func shouldRegister);
+
+ ///
+ /// Registers services from the given type.
+ ///
+ /// The type of to register from.
+ void RegisterFrom() where TCompositionRoot : ICompositionRoot, new();
+
+ ///
+ /// Registers composition roots from assemblies in the base directory that matches the .
+ ///
+ /// The search pattern used to filter the assembly files.
+ void RegisterAssembly(string searchPattern);
+
+ ///
+ /// Decorates the with the given .
+ ///
+ /// The target service type.
+ /// The decorator type used to decorate the .
+ /// A function delegate that determines if the
+ /// should be applied to the target .
+ void Decorate(Type serviceType, Type decoratorType, Func predicate);
+
+ ///
+ /// Decorates the with the given .
+ ///
+ /// The target service type.
+ /// The decorator type used to decorate the .
+ void Decorate(Type serviceType, Type decoratorType);
+
+ ///
+ /// Decorates the with the given .
+ ///
+ /// The target service type.
+ /// The decorator type used to decorate the .
+ void Decorate() where TDecorator : TService;
+
+ ///
+ /// Decorates the using the given decorator .
+ ///
+ /// The target service type.
+ /// A factory delegate used to create a decorator instance.
+ void Decorate(Expression> factory);
+
+ ///
+ /// Registers a decorator based on a instance.
+ ///
+ /// The instance that contains the decorator metadata.
+ void Decorate(DecoratorRegistration decoratorRegistration);
+
+ ///
+ /// Allows a registered service to be overridden by another .
+ ///
+ /// A function delegate that is used to determine the service that should be
+ /// overridden using the returned from the .
+ /// The factory delegate used to create a that overrides
+ /// the incoming .
+ void Override(
+ Func serviceSelector,
+ Func serviceRegistrationFactory);
+ }
+
+ ///
+ /// Defines a set of methods used to retrieve service instances.
+ ///
+ internal interface IServiceFactory
+ {
+ ///
+ /// Starts a new .
+ ///
+ ///
+ Scope BeginScope();
+
+ ///
+ /// Ends the current .
+ ///
+ void EndCurrentScope();
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The requested service instance.
+ object GetInstance(Type serviceType);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The arguments to be passed to the target instance.
+ /// The requested service instance.
+ object GetInstance(Type serviceType, object[] arguments);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The name of the requested service.
+ /// The arguments to be passed to the target instance.
+ /// The requested service instance.
+ object GetInstance(Type serviceType, string serviceName, object[] arguments);
+
+ ///
+ /// Gets a named instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The name of the requested service.
+ /// The requested service instance.
+ object GetInstance(Type serviceType, string serviceName);
+
+ ///
+ /// Gets an instance of the given type.
+ ///
+ /// The type of the requested service.
+ /// The requested service instance.
+ TService GetInstance();
+
+ ///
+ /// Gets a named instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The name of the requested service.
+ /// The requested service instance.
+ TService GetInstance(string serviceName);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the argument.
+ /// The type of the requested service.
+ /// The argument value.
+ /// The requested service instance.
+ TService GetInstance(T value);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the parameter.
+ /// The type of the requested service.
+ /// The argument value.
+ /// The name of the requested service.
+ /// The requested service instance.
+ TService GetInstance(T value, string serviceName);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the requested service.
+ /// The first argument value.
+ /// The second argument value.
+ /// The requested service instance.
+ TService GetInstance(T1 arg1, T2 arg2);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the requested service.
+ /// The first argument value.
+ /// The second argument value.
+ /// The name of the requested service.
+ /// The requested service instance.
+ TService GetInstance(T1 arg1, T2 arg2, string serviceName);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The type of the requested service.
+ /// The first argument value.
+ /// The second argument value.
+ /// The third argument value.
+ /// The requested service instance.
+ TService GetInstance(T1 arg1, T2 arg2, T3 arg3);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The type of the requested service.
+ /// The first argument value.
+ /// The second argument value.
+ /// The third argument value.
+ /// The name of the requested service.
+ /// The requested service instance.
+ TService GetInstance(T1 arg1, T2 arg2, T3 arg3, string serviceName);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The type of the fourth parameter.
+ /// The type of the requested service.
+ /// The first argument value.
+ /// The second argument value.
+ /// The third argument value.
+ /// The fourth argument value.
+ /// The requested service instance.
+ TService GetInstance(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The type of the fourth parameter.
+ /// The type of the requested service.
+ /// The first argument value.
+ /// The second argument value.
+ /// The third argument value.
+ /// The fourth argument value.
+ /// The name of the requested service.
+ /// The requested service instance.
+ TService GetInstance(T1 arg1, T2 arg2, T3 arg3, T4 arg4, string serviceName);
+
+ ///
+ /// Gets an instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The requested service instance if available, otherwise null.
+ object TryGetInstance(Type serviceType);
+
+ ///
+ /// Gets a named instance of the given .
+ ///
+ /// The type of the requested service.
+ /// The name of the requested service.
+ /// The requested service instance if available, otherwise null.
+ object TryGetInstance(Type serviceType, string serviceName);
+
+ ///
+ /// Tries to get an instance of the given type.
+ ///
+ /// The type of the requested service.
+ /// The requested service instance if available, otherwise default(T).
+ TService TryGetInstance();
+
+ ///
+ /// Tries to get an instance of the given type.
+ ///
+ /// The type of the requested service.
+ /// The name of the requested service.
+ /// The requested service instance if available, otherwise default(T).
+ TService TryGetInstance(string serviceName);
+
+ ///
+ /// Gets all instances of the given .
+ ///
+ /// The type of services to resolve.
+ /// A list that contains all implementations of the .
+ IEnumerable GetAllInstances(Type serviceType);
+
+ ///
+ /// Gets all instances of type .
+ ///
+ /// The type of services to resolve.
+ /// A list that contains all implementations of the type.
+ IEnumerable GetAllInstances();
+
+ ///
+ /// Creates an instance of a concrete class.
+ ///
+ /// The type of class for which to create an instance.
+ /// An instance of .
+ /// The concrete type will be registered if not already registered with the container.
+ TService Create() where TService : class;
+
+ ///
+ /// Creates an instance of a concrete class.
+ ///
+ /// The type of class for which to create an instance.
+ /// An instance of the .
+ object Create(Type serviceType);
+ }
+
+ ///
+ /// Represents an inversion of control container.
+ ///
+ internal interface IServiceContainer : IServiceRegistry, IServiceFactory, IDisposable
+ {
+ ///
+ /// Gets or sets the that is responsible
+ /// for providing the used to manage scopes.
+ ///
+ IScopeManagerProvider ScopeManagerProvider { get; set; }
+
+ ///
+ /// Returns true if the container can create the requested service, otherwise false .
+ ///
+ /// The of the service.
+ /// The name of the service.
+ /// true if the container can create the requested service, otherwise false .
+ bool CanGetInstance(Type serviceType, string serviceName);
+
+ ///
+ /// Injects the property dependencies for a given .
+ ///
+ /// The target instance for which to inject its property dependencies.
+ /// The with its property dependencies injected.
+ object InjectProperties(object instance);
+ }
+
+ ///
+ /// Represents a class that manages the lifetime of a service instance.
+ ///
+ internal interface ILifetime
+ {
+ ///
+ /// Returns a service instance according to the specific lifetime characteristics.
+ ///
+ /// The function delegate used to create a new service instance.
+ /// The of the current service request.
+ /// The requested services instance.
+ object GetInstance(Func createInstance, Scope scope);
+ }
+
+ ///
+ /// Represents a class that acts as a composition root for an instance.
+ ///
+ internal interface ICompositionRoot
+ {
+ ///
+ /// Composes services by adding services to the .
+ ///
+ /// The target .
+ void Compose(IServiceRegistry serviceRegistry);
+ }
+
+ ///
+ /// Represents a class that extracts a set of types from an .
+ ///
+ internal interface ITypeExtractor
+ {
+ ///
+ /// Extracts types found in the given .
+ ///
+ /// The for which to extract types.
+ /// A set of types found in the given .
+ Type[] Execute(Assembly assembly);
+ }
+
+ ///
+ /// Represents a class that is responsible for selecting injectable properties.
+ ///
+ internal interface IPropertySelector
+ {
+ ///
+ /// Selects properties that represents a dependency from the given .
+ ///
+ /// The for which to select the properties.
+ /// A list of injectable properties.
+ IEnumerable Execute(Type type);
+ }
+
+ ///
+ /// Represents a class that is responsible for selecting the property dependencies for a given .
+ ///
+ internal interface IPropertyDependencySelector
+ {
+ ///
+ /// Selects the property dependencies for the given .
+ ///
+ /// The for which to select the property dependencies.
+ /// A list of instances that represents the property
+ /// dependencies for the given .
+ IEnumerable Execute(Type type);
+ }
+
+ ///
+ /// Represents a class that is responsible for selecting the constructor dependencies for a given .
+ ///
+ internal interface IConstructorDependencySelector
+ {
+ ///
+ /// Selects the constructor dependencies for the given .
+ ///
+ /// The for which to select the constructor dependencies.
+ /// A list of instances that represents the constructor
+ /// dependencies for the given .
+ IEnumerable Execute(ConstructorInfo constructor);
+ }
+
+ ///
+ /// Represents a class that is capable of building a instance
+ /// based on a .
+ ///
+ internal interface IConstructionInfoBuilder
+ {
+ ///
+ /// Returns a instance based on the given .
+ ///
+ /// The for which to return a instance.
+ /// A instance that describes how to create a service instance.
+ ConstructionInfo Execute(Registration registration);
+ }
+
+ ///
+ /// Represents a class that keeps track of a instance for each .
+ ///
+ internal interface IConstructionInfoProvider
+ {
+ ///
+ /// Gets a instance for the given .
+ ///
+ /// The for which to get a instance.
+ /// The instance that describes how to create an instance of the given .
+ ConstructionInfo GetConstructionInfo(Registration registration);
+
+ ///
+ /// Invalidates the and causes new instances
+ /// to be created when the method is called.
+ ///
+ void Invalidate();
+ }
+
+ ///
+ /// Represents a class that builds a instance based on a .
+ ///
+ internal interface ILambdaConstructionInfoBuilder
+ {
+ ///
+ /// Parses the and returns a instance.
+ ///
+ /// The to parse.
+ /// A instance.
+ ConstructionInfo Execute(LambdaExpression lambdaExpression);
+ }
+
+ ///
+ /// Represents a class that builds a instance based on the implementing .
+ ///
+ internal interface ITypeConstructionInfoBuilder
+ {
+ ///
+ /// Analyzes the and returns a instance.
+ ///
+ /// The that represents the implementing type to analyze.
+ /// A instance.
+ ConstructionInfo Execute(Registration registration);
+ }
+
+ ///
+ /// Represents a class that selects the constructor to be used for creating a new service instance.
+ ///
+ internal interface IConstructorSelector
+ {
+ ///
+ /// Selects the constructor to be used when creating a new instance of the .
+ ///
+ /// The for which to return a .
+ /// A instance that represents the constructor to be used
+ /// when creating a new instance of the .
+ ConstructorInfo Execute(Type implementingType);
+ }
+
+ ///
+ /// Represents a class that is responsible loading a set of assemblies based on the given search pattern.
+ ///
+ internal interface IAssemblyLoader
+ {
+ ///
+ /// Loads a set of assemblies based on the given .
+ ///
+ /// The search pattern to use.
+ /// A list of assemblies based on the given .
+ IEnumerable Load(string searchPattern);
+ }
+
+ ///
+ /// Represents a class that is capable of scanning an assembly and register services into an instance.
+ ///
+ internal interface IAssemblyScanner
+ {
+ ///
+ /// Scans the target and registers services found within the assembly.
+ ///
+ /// The to scan.
+ /// The target instance.
+ /// The instance that controls the lifetime of the registered service.
+ /// A function delegate that determines if a service implementation should be registered.
+ void Scan(Assembly assembly, IServiceRegistry serviceRegistry, Func lifetime, Func shouldRegister);
+
+ ///
+ /// Scans the target and executes composition roots found within the .
+ ///
+ /// The to scan.
+ /// The target instance.
+ void Scan(Assembly assembly, IServiceRegistry serviceRegistry);
+ }
+
+ ///
+ /// Represents a class that is responsible for instantiating and executing an .
+ ///
+ internal interface ICompositionRootExecutor
+ {
+ ///
+ /// Creates an instance of the and executes the method.
+ ///
+ /// The concrete type to be instantiated and executed.
+ void Execute(Type compositionRootType);
+ }
+
+ ///
+ /// Represents an abstraction of the class that provides information
+ /// about the currently on the stack.
+ ///
+ internal interface IEmitter
+ {
+ ///
+ /// Gets the currently on the stack.
+ ///
+ Type StackType { get; }
+
+ ///
+ /// Gets a list containing each to be emitted into the dynamic method.
+ ///
+ List Instructions { get; }
+
+ ///
+ /// Puts the specified instruction onto the stream of instructions.
+ ///
+ /// The Microsoft Intermediate Language (MSIL) instruction to be put onto the stream.
+ void Emit(OpCode code);
+
+ ///
+ /// Puts the specified instruction and numerical argument onto the Microsoft intermediate language (MSIL) stream of instructions.
+ ///
+ /// The MSIL instruction to be put onto the stream.
+ /// The numerical argument pushed onto the stream immediately after the instruction.
+ void Emit(OpCode code, int arg);
+
+ ///
+ /// Puts the specified instruction and numerical argument onto the Microsoft intermediate language (MSIL) stream of instructions.
+ ///
+ /// The MSIL instruction to be put onto the stream.
+ /// The numerical argument pushed onto the stream immediately after the instruction.
+ void Emit(OpCode code, sbyte arg);
+
+ ///
+ /// Puts the specified instruction and numerical argument onto the Microsoft intermediate language (MSIL) stream of instructions.
+ ///
+ /// The MSIL instruction to be put onto the stream.
+ /// The numerical argument pushed onto the stream immediately after the instruction.
+ void Emit(OpCode code, byte arg);
+
+ ///
+ /// Puts the specified instruction onto the Microsoft intermediate language (MSIL) stream followed by the metadata token for the given type.
+ ///
+ /// The MSIL instruction to be put onto the stream.
+ /// A representing the type metadata token.
+ void Emit(OpCode code, Type type);
+
+ ///
+ /// Puts the specified instruction and metadata token for the specified constructor onto the Microsoft intermediate language (MSIL) stream of instructions.
+ ///
+ /// The MSIL instruction to be emitted onto the stream.
+ /// A representing a constructor.
+ void Emit(OpCode code, ConstructorInfo constructor);
+
+ ///
+ /// Puts the specified instruction onto the Microsoft intermediate language (MSIL) stream followed by the index of the given local variable.
+ ///
+ /// The MSIL instruction to be emitted onto the stream.
+ /// A local variable.
+ void Emit(OpCode code, LocalBuilder localBuilder);
+
+ ///
+ /// Puts the specified instruction onto the Microsoft intermediate language (MSIL) stream followed by the metadata token for the given method.
+ ///
+ /// The MSIL instruction to be emitted onto the stream.
+ /// A representing a method.
+ void Emit(OpCode code, MethodInfo methodInfo);
+
+ ///
+ /// Declares a local variable of the specified type.
+ ///
+ /// A object that represents the type of the local variable.
+ /// The declared local variable.
+ LocalBuilder DeclareLocal(Type type);
+ }
+
+ ///
+ /// Represents a dynamic method skeleton for emitting the code needed to resolve a service instance.
+ ///
+ internal interface IMethodSkeleton
+ {
+ ///
+ /// Gets the for the this dynamic method.
+ ///
+ /// The for this dynamic method.
+ IEmitter GetEmitter();
+
+ ///
+ /// Completes the dynamic method and creates a delegate that can be used to execute it.
+ ///
+ /// A delegate type whose signature matches that of the dynamic method.
+ /// A delegate of the specified type, which can be used to execute the dynamic method.
+ Delegate CreateDelegate(Type delegateType);
+ }
+
+ ///
+ /// Represents a class that is capable of providing the current .
+ ///
+ internal interface IScopeManagerProvider
+ {
+ ///
+ /// Returns the that is responsible for managing scopes.
+ ///
+ /// The that is responsible for managing scopes.
+ ScopeManager GetScopeManager();
+ }
+
+ ///
+ /// Extends the class.
+ ///
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class ExpressionExtensions
+ {
+ ///
+ /// Flattens the into an .
+ ///
+ /// The target .
+ /// The represented as a list of sub expressions.
+ public static IEnumerable AsEnumerable(this Expression expression)
+ {
+ var flattener = new ExpressionTreeFlattener();
+ return flattener.Flatten(expression);
+ }
+
+ private class ExpressionTreeFlattener : ExpressionVisitor
+ {
+ private readonly ICollection nodes = new Collection();
+
+ public IEnumerable Flatten(Expression expression)
+ {
+ Visit(expression);
+ return nodes;
+ }
+
+ public override Expression Visit(Expression node)
+ {
+ nodes.Add(node);
+ return base.Visit(node);
+ }
+ }
+ }
+
+ ///
+ /// Extends the class.
+ ///
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class ImmutableHashTreeExtensions
+ {
+ ///
+ /// Searches for a using the given .
+ ///
+ /// The type of the key.
+ /// The type of the value.
+ /// The target .
+ /// The key of the to get.
+ /// If found, the with the given , otherwise the default .
+ public static TValue Search(this ImmutableHashTree tree, TKey key)
+ {
+ int hashCode = key.GetHashCode();
+
+ while (tree.Height != 0 && tree.HashCode != hashCode)
+ {
+ tree = hashCode < tree.HashCode ? tree.Left : tree.Right;
+ }
+
+ if (!tree.IsEmpty && (ReferenceEquals(tree.Key, key) || Equals(tree.Key, key)))
+ {
+ return tree.Value;
+ }
+
+ if (tree.Duplicates.Items.Length > 0)
+ {
+ foreach (var keyValue in tree.Duplicates.Items)
+ {
+ if (ReferenceEquals(keyValue.Key, key) || Equals(keyValue.Key, key))
+ {
+ return keyValue.Value;
+ }
+ }
+ }
+
+ return default(TValue);
+ }
+
+ ///
+ /// Adds a new element to the .
+ ///
+ /// The type of the key.
+ /// The type of the value.
+ /// The target .
+ /// The key to be associated with the value.
+ /// The value to be added to the tree.
+ /// A new that contains the new key/value pair.
+ public static ImmutableHashTree Add(this ImmutableHashTree tree, TKey key, TValue value)
+ {
+ if (tree.IsEmpty)
+ {
+ return new ImmutableHashTree(key, value, tree, tree);
+ }
+
+ int hashCode = key.GetHashCode();
+
+ if (hashCode > tree.HashCode)
+ {
+ return AddToRightBranch(tree, key, value);
+ }
+
+ if (hashCode < tree.HashCode)
+ {
+ return AddToLeftBranch(tree, key, value);
+ }
+
+ return new ImmutableHashTree(key, value, tree);
+ }
+
+ private static ImmutableHashTree AddToLeftBranch(ImmutableHashTree tree, TKey key, TValue value)
+ {
+ return new ImmutableHashTree(tree.Key, tree.Value, tree.Left.Add(key, value), tree.Right);
+ }
+
+ private static ImmutableHashTree AddToRightBranch(ImmutableHashTree tree, TKey key, TValue value)
+ {
+ return new ImmutableHashTree(tree.Key, tree.Value, tree.Left, tree.Right.Add(key, value));
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class LazyTypeExtensions
+ {
+ private static readonly ThreadSafeDictionary Constructors = new ThreadSafeDictionary();
+
+ public static ConstructorInfo GetLazyConstructor(this Type type)
+ {
+ return Constructors.GetOrAdd(type, GetConstructor);
+ }
+
+ private static ConstructorInfo GetConstructor(Type type)
+ {
+ Type closedGenericLazyType = typeof(Lazy<>).MakeGenericType(type);
+ return closedGenericLazyType.GetConstructor(new[] { type.GetFuncType() });
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class EnumerableTypeExtensions
+ {
+ private static readonly ThreadSafeDictionary EnumerableTypes = new ThreadSafeDictionary();
+
+ public static Type GetEnumerableType(this Type returnType)
+ {
+ return EnumerableTypes.GetOrAdd(returnType, CreateEnumerableType);
+ }
+
+ private static Type CreateEnumerableType(Type type)
+ {
+ return typeof(IEnumerable<>).MakeGenericType(type);
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class FuncTypeExtensions
+ {
+ private static readonly ThreadSafeDictionary FuncTypes = new ThreadSafeDictionary();
+
+ public static Type GetFuncType(this Type returnType)
+ {
+ return FuncTypes.GetOrAdd(returnType, CreateFuncType);
+ }
+
+ private static Type CreateFuncType(Type type)
+ {
+ return typeof(Func<>).MakeGenericType(type);
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class LifetimeHelper
+ {
+ static LifetimeHelper()
+ {
+ GetInstanceMethod = typeof(ILifetime).GetMethod("GetInstance");
+ GetCurrentScopeMethod = typeof(ScopeManager).GetProperty("CurrentScope").GetGetMethod();
+ GetScopeManagerMethod = typeof(IScopeManagerProvider).GetMethod("GetScopeManager");
+ }
+
+ public static MethodInfo GetInstanceMethod { get; private set; }
+
+ public static MethodInfo GetCurrentScopeMethod { get; private set; }
+
+ public static MethodInfo GetScopeManagerMethod { get; private set; }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class DelegateTypeExtensions
+ {
+ private static readonly MethodInfo OpenGenericGetInstanceMethodInfo =
+ typeof(IServiceFactory).GetMethod("GetInstance", new Type[] { });
+
+ private static readonly ThreadSafeDictionary GetInstanceMethods =
+ new ThreadSafeDictionary();
+
+ public static Delegate CreateGetInstanceDelegate(this Type serviceType, IServiceFactory serviceFactory)
+ {
+ Type delegateType = serviceType.GetFuncType();
+ MethodInfo getInstanceMethod = GetInstanceMethods.GetOrAdd(serviceType, CreateGetInstanceMethod);
+ return getInstanceMethod.CreateDelegate(delegateType, serviceFactory);
+ }
+
+ private static MethodInfo CreateGetInstanceMethod(Type type)
+ {
+ return OpenGenericGetInstanceMethodInfo.MakeGenericMethod(type);
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class NamedDelegateTypeExtensions
+ {
+ private static readonly MethodInfo CreateInstanceDelegateMethodInfo =
+ typeof(NamedDelegateTypeExtensions).GetPrivateStaticMethod("CreateInstanceDelegate");
+
+ private static readonly ThreadSafeDictionary CreateInstanceDelegateMethods =
+ new ThreadSafeDictionary();
+
+ public static Delegate CreateNamedGetInstanceDelegate(this Type serviceType, string serviceName, IServiceFactory factory)
+ {
+ MethodInfo createInstanceDelegateMethodInfo = CreateInstanceDelegateMethods.GetOrAdd(
+ serviceType,
+ CreateClosedGenericCreateInstanceDelegateMethod);
+
+ return (Delegate)createInstanceDelegateMethodInfo.Invoke(null, new object[] { factory, serviceName });
+ }
+
+ private static MethodInfo CreateClosedGenericCreateInstanceDelegateMethod(Type type)
+ {
+ return CreateInstanceDelegateMethodInfo.MakeGenericMethod(type);
+ }
+
+ // ReSharper disable UnusedMember.Local
+ private static Func CreateInstanceDelegate(IServiceFactory factory, string serviceName)
+ // ReSharper restore UnusedMember.Local
+ {
+ return () => factory.GetInstance(serviceName);
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class ReflectionHelper
+ {
+ private static readonly Lazy> GetInstanceWithParametersMethods;
+
+ static ReflectionHelper()
+ {
+ GetInstanceWithParametersMethods = CreateLazyGetInstanceWithParametersMethods();
+ }
+
+ public static MethodInfo GetGetInstanceWithParametersMethod(Type serviceType)
+ {
+ return GetInstanceWithParametersMethods.Value.GetOrAdd(serviceType, CreateGetInstanceWithParametersMethod);
+ }
+
+ public static Delegate CreateGetNamedInstanceWithParametersDelegate(IServiceFactory factory, Type delegateType, string serviceName)
+ {
+ Type[] genericTypeArguments = delegateType.GetGenericTypeArguments();
+ var openGenericMethod =
+ typeof(ReflectionHelper).GetPrivateStaticMethods()
+ .Single(
+ m =>
+ m.GetGenericArguments().Length == genericTypeArguments.Length
+ && m.Name == "CreateGenericGetNamedParameterizedInstanceDelegate");
+ var closedGenericMethod = openGenericMethod.MakeGenericMethod(genericTypeArguments);
+ return (Delegate)closedGenericMethod.Invoke(null, new object[] { factory, serviceName });
+ }
+
+ private static Lazy> CreateLazyGetInstanceWithParametersMethods()
+ {
+ return new Lazy>(
+ () => new ThreadSafeDictionary());
+ }
+
+ private static MethodInfo CreateGetInstanceWithParametersMethod(Type serviceType)
+ {
+ Type[] genericTypeArguments = serviceType.GetGenericTypeArguments();
+ MethodInfo openGenericMethod =
+ typeof(IServiceFactory).GetMethods().Single(m => m.Name == "GetInstance"
+ && m.GetGenericArguments().Length == genericTypeArguments.Length && m.GetParameters().All(p => p.Name != "serviceName"));
+
+ MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(genericTypeArguments);
+
+ return closedGenericMethod;
+ }
+
+ // ReSharper disable UnusedMember.Local
+ private static Func CreateGenericGetNamedParameterizedInstanceDelegate(IServiceFactory factory, string serviceName)
+ // ReSharper restore UnusedMember.Local
+ {
+ return arg => factory.GetInstance(arg, serviceName);
+ }
+
+ // ReSharper disable UnusedMember.Local
+ private static Func CreateGenericGetNamedParameterizedInstanceDelegate(IServiceFactory factory, string serviceName)
+ // ReSharper restore UnusedMember.Local
+ {
+ return (arg1, arg2) => factory.GetInstance(arg1, arg2, serviceName);
+ }
+
+ // ReSharper disable UnusedMember.Local
+ private static Func CreateGenericGetNamedParameterizedInstanceDelegate(IServiceFactory factory, string serviceName)
+ // ReSharper restore UnusedMember.Local
+ {
+ return (arg1, arg2, arg3) => factory.GetInstance(arg1, arg2, arg3, serviceName);
+ }
+
+ // ReSharper disable UnusedMember.Local
+ private static Func CreateGenericGetNamedParameterizedInstanceDelegate(IServiceFactory factory, string serviceName)
+ // ReSharper restore UnusedMember.Local
+ {
+ return (arg1, arg2, arg3, arg4) => factory.GetInstance(arg1, arg2, arg3, arg4, serviceName);
+ }
+ }
+
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class TypeHelper
+ {
+ public static Type[] GetGenericTypeArguments(this Type type)
+ {
+ return type.GetGenericArguments();
+ }
+
+ public static bool IsClass(this Type type)
+ {
+ return type.IsClass;
+ }
+
+ public static bool IsAbstract(this Type type)
+ {
+ return type.IsAbstract;
+ }
+
+ public static bool IsNestedPrivate(this Type type)
+ {
+ return type.IsNestedPrivate;
+ }
+
+ public static bool IsGenericType(this Type type)
+ {
+ return type.IsGenericType;
+ }
+
+ public static bool ContainsGenericParameters(this Type type)
+ {
+ return type.ContainsGenericParameters;
+ }
+
+ public static Type GetBaseType(this Type type)
+ {
+ return type.BaseType;
+ }
+
+ public static bool IsGenericTypeDefinition(this Type type)
+ {
+ return type.IsGenericTypeDefinition;
+ }
+
+ public static Assembly GetAssembly(this Type type)
+ {
+ return type.Assembly;
+ }
+
+ public static bool IsValueType(this Type type)
+ {
+ return type.IsValueType;
+ }
+
+ public static MethodInfo GetMethodInfo(this Delegate del)
+ {
+ return del.Method;
+ }
+
+ public static MethodInfo GetPrivateMethod(this Type type, string name)
+ {
+ return type.GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic);
+ }
+
+ public static MethodInfo GetPrivateStaticMethod(this Type type, string name)
+ {
+ return type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic);
+ }
+
+ public static MethodInfo[] GetPrivateStaticMethods(this Type type)
+ {
+ return type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
+ }
+
+ public static IEnumerable GetCustomAttributes(this Assembly assembly, Type attributeType)
+ {
+ return assembly.GetCustomAttributes(attributeType, false).Cast();
+ }
+
+ public static bool IsEnumerableOfT(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>);
+ }
+
+ public static bool IsListOfT(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(IList<>);
+ }
+
+ public static bool IsCollectionOfT(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(ICollection<>);
+ }
+
+ public static bool IsReadOnlyCollectionOfT(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>);
+ }
+
+ public static bool IsReadOnlyListOfT(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(IReadOnlyList<>);
+ }
+
+ public static bool IsLazy(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(Lazy<>);
+ }
+
+ public static bool IsFunc(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && serviceType.GetGenericTypeDefinition() == typeof(Func<>);
+ }
+
+ public static bool IsFuncWithParameters(this Type serviceType)
+ {
+ if (!serviceType.IsGenericType())
+ {
+ return false;
+ }
+
+ Type genericTypeDefinition = serviceType.GetGenericTypeDefinition();
+
+ return genericTypeDefinition == typeof(Func<,>) || genericTypeDefinition == typeof(Func<,,>)
+ || genericTypeDefinition == typeof(Func<,,,>) || genericTypeDefinition == typeof(Func<,,,,>);
+ }
+
+ public static bool IsClosedGeneric(this Type serviceType)
+ {
+ return serviceType.IsGenericType() && !serviceType.IsGenericTypeDefinition();
+ }
+
+ public static Type GetElementType(Type type)
+ {
+ if (type.IsGenericType() && type.GetGenericTypeArguments().Count() == 1)
+ {
+ return type.GetGenericTypeArguments()[0];
+ }
+
+ return type.GetElementType();
+ }
+ }
+
+ ///
+ /// Extends the interface with a set of methods
+ /// that optimizes and simplifies emitting MSIL instructions.
+ ///
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal static class EmitterExtensions
+ {
+ ///
+ /// Performs a cast or unbox operation if the current is
+ /// different from the given .
+ ///
+ /// The target .
+ /// The requested stack type.
+ public static void UnboxOrCast(this IEmitter emitter, Type type)
+ {
+ if (!type.IsAssignableFrom(emitter.StackType))
+ {
+ emitter.Emit(type.IsValueType() ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
+ }
+ }
+
+ ///
+ /// Pushes a constant value onto the evaluation stack.
+ ///
+ /// The target .
+ /// The index of the constant value to be pushed onto the stack.
+ /// The requested stack type.
+ public static void PushConstant(this IEmitter emitter, int index, Type type)
+ {
+ emitter.PushConstant(index);
+ emitter.UnboxOrCast(type);
+ }
+
+ ///
+ /// Pushes a constant value onto the evaluation stack as a object reference.
+ ///
+ /// The target .
+ /// The index of the constant value to be pushed onto the stack.
+ public static void PushConstant(this IEmitter emitter, int index)
+ {
+ emitter.PushArgument(0);
+ emitter.Push(index);
+ emitter.PushArrayElement();
+ }
+
+ ///
+ /// Pushes the element containing an object reference at a specified index onto the stack.
+ ///
+ /// The target .
+ public static void PushArrayElement(this IEmitter emitter)
+ {
+ emitter.Emit(OpCodes.Ldelem_Ref);
+ }
+
+ ///
+ /// Pushes the arguments associated with a service request onto the stack.
+ /// The arguments are found as an array in the last element of the constants array
+ /// that is passed into the dynamic method.
+ ///
+ /// The target .
+ /// A list of instances that
+ /// represent the arguments to be pushed onto the stack.
+ public static void PushArguments(this IEmitter emitter, ParameterInfo[] parameters)
+ {
+ var argumentArray = emitter.DeclareLocal(typeof(object[]));
+ emitter.Emit(OpCodes.Ldarg_0);
+ emitter.Emit(OpCodes.Ldarg_0);
+ emitter.Emit(OpCodes.Ldlen);
+ emitter.Emit(OpCodes.Conv_I4);
+ emitter.Emit(OpCodes.Ldc_I4_1);
+ emitter.Emit(OpCodes.Sub);
+ emitter.Emit(OpCodes.Ldelem_Ref);
+ emitter.Emit(OpCodes.Castclass, typeof(object[]));
+ emitter.Emit(OpCodes.Stloc, argumentArray);
+
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ emitter.Emit(OpCodes.Ldloc, argumentArray);
+ emitter.Emit(OpCodes.Ldc_I4, i);
+ emitter.Emit(OpCodes.Ldelem_Ref);
+ emitter.Emit(
+ parameters[i].ParameterType.IsValueType() ? OpCodes.Unbox_Any : OpCodes.Castclass,
+ parameters[i].ParameterType);
+ }
+ }
+
+ ///
+ /// Calls a late-bound method on an object, pushing the return value onto the stack.
+ ///
+ /// The target .
+ /// The that represents the method to be called.
+ public static void Call(this IEmitter emitter, MethodInfo methodInfo)
+ {
+ emitter.Emit(OpCodes.Callvirt, methodInfo);
+ }
+
+ ///
+ /// Pushes a new instance onto the stack.
+ ///
+ /// The target .
+ /// The that represent the object to be created.
+ public static void New(this IEmitter emitter, ConstructorInfo constructorInfo)
+ {
+ emitter.Emit(OpCodes.Newobj, constructorInfo);
+ }
+
+ ///
+ /// Pushes the given onto the stack.
+ ///
+ /// The target .
+ /// The to be pushed onto the stack.
+ public static void Push(this IEmitter emitter, LocalBuilder localBuilder)
+ {
+ int index = localBuilder.LocalIndex;
+ switch (index)
+ {
+ case 0:
+ emitter.Emit(OpCodes.Ldloc_0);
+ return;
+ case 1:
+ emitter.Emit(OpCodes.Ldloc_1);
+ return;
+ case 2:
+ emitter.Emit(OpCodes.Ldloc_2);
+ return;
+ case 3:
+ emitter.Emit(OpCodes.Ldloc_3);
+ return;
+ }
+
+ if (index <= 255)
+ {
+ emitter.Emit(OpCodes.Ldloc_S, (byte)index);
+ }
+ else
+ {
+ emitter.Emit(OpCodes.Ldloc, index);
+ }
+ }
+
+ ///
+ /// Pushes an argument with the given onto the stack.
+ ///
+ /// The target .
+ /// The index of the argument to be pushed onto the stack.
+ public static void PushArgument(this IEmitter emitter, int index)
+ {
+ switch (index)
+ {
+ case 0:
+ emitter.Emit(OpCodes.Ldarg_0);
+ return;
+ case 1:
+ emitter.Emit(OpCodes.Ldarg_1);
+ return;
+ case 2:
+ emitter.Emit(OpCodes.Ldarg_2);
+ return;
+ case 3:
+ emitter.Emit(OpCodes.Ldarg_3);
+ return;
+ }
+
+ if (index <= 255)
+ {
+ emitter.Emit(OpCodes.Ldarg_S, (byte)index);
+ }
+ else
+ {
+ emitter.Emit(OpCodes.Ldarg, index);
+ }
+ }
+
+ ///
+ /// Stores the value currently on top of the stack in the given .
+ ///
+ /// The target .
+ /// The for which the value is to be stored.
+ public static void Store(this IEmitter emitter, LocalBuilder localBuilder)
+ {
+ int index = localBuilder.LocalIndex;
+ switch (index)
+ {
+ case 0:
+ emitter.Emit(OpCodes.Stloc_0);
+ return;
+ case 1:
+ emitter.Emit(OpCodes.Stloc_1);
+ return;
+ case 2:
+ emitter.Emit(OpCodes.Stloc_2);
+ return;
+ case 3:
+ emitter.Emit(OpCodes.Stloc_3);
+ return;
+ }
+
+ if (index <= 255)
+ {
+ emitter.Emit(OpCodes.Stloc_S, (byte)index);
+ }
+ else
+ {
+ emitter.Emit(OpCodes.Stloc, index);
+ }
+ }
+
+ ///
+ /// Pushes a new array of the given onto the stack.
+ ///
+ /// The target .
+ /// The element of the new array.
+ public static void PushNewArray(this IEmitter emitter, Type elementType)
+ {
+ emitter.Emit(OpCodes.Newarr, elementType);
+ }
+
+ ///
+ /// Pushes an value onto the stack.
+ ///
+ /// The target .
+ /// The value to be pushed onto the stack.
+ public static void Push(this IEmitter emitter, int value)
+ {
+ switch (value)
+ {
+ case 0:
+ emitter.Emit(OpCodes.Ldc_I4_0);
+ return;
+ case 1:
+ emitter.Emit(OpCodes.Ldc_I4_1);
+ return;
+ case 2:
+ emitter.Emit(OpCodes.Ldc_I4_2);
+ return;
+ case 3:
+ emitter.Emit(OpCodes.Ldc_I4_3);
+ return;
+ case 4:
+ emitter.Emit(OpCodes.Ldc_I4_4);
+ return;
+ case 5:
+ emitter.Emit(OpCodes.Ldc_I4_5);
+ return;
+ case 6:
+ emitter.Emit(OpCodes.Ldc_I4_6);
+ return;
+ case 7:
+ emitter.Emit(OpCodes.Ldc_I4_7);
+ return;
+ case 8:
+ emitter.Emit(OpCodes.Ldc_I4_8);
+ return;
+ }
+
+ if (value > -129 && value < 128)
+ {
+ emitter.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
+ }
+ else
+ {
+ emitter.Emit(OpCodes.Ldc_I4, value);
+ }
+ }
+
+ ///
+ /// Performs a cast of the value currently on top of the stack to the given .
+ ///
+ /// The target .
+ /// The for which the value will be casted into.
+ public static void Cast(this IEmitter emitter, Type type)
+ {
+ emitter.Emit(OpCodes.Castclass, type);
+ }
+
+ ///
+ /// Returns from the current method.
+ ///
+ /// The target .
+ public static void Return(this IEmitter emitter)
+ {
+ emitter.Emit(OpCodes.Ret);
+ }
+ }
+
+ ///
+ /// An ultra lightweight service container.
+ ///
+ [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ internal class ServiceContainer : IServiceContainer
+ {
+ private const string UnresolvedDependencyError = "Unresolved dependency {0}";
+ private readonly Func methodSkeletonFactory;
+ private readonly ServiceRegistry> emitters = new ServiceRegistry>();
+ private readonly object lockObject = new object();
+
+ private readonly Storage constants = new Storage();
+
+ private readonly Storage factoryRules = new Storage();
+ private readonly Stack> dependencyStack = new Stack>();
+
+ private readonly ServiceRegistry availableServices = new ServiceRegistry();
+
+ private readonly Storage decorators = new Storage();
+ private readonly Storage overrides = new Storage();
+
+ private readonly Lazy constructionInfoProvider;
+ private readonly ICompositionRootExecutor compositionRootExecutor;
+
+ private readonly ITypeExtractor compositionRootTypeExtractor;
+ private ImmutableHashTree> delegates =
+ ImmutableHashTree>.Empty;
+
+ private ImmutableHashTree, Func> namedDelegates =
+ ImmutableHashTree, Func>.Empty;
+
+ private ImmutableHashTree> propertyInjectionDelegates =
+ ImmutableHashTree>.Empty;
+
+ private bool isLocked;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ServiceContainer()
+ {
+ var concreteTypeExtractor = new CachedTypeExtractor(new ConcreteTypeExtractor());
+ compositionRootTypeExtractor = new CachedTypeExtractor(new CompositionRootTypeExtractor());
+ compositionRootExecutor = new CompositionRootExecutor(this);
+ AssemblyScanner = new AssemblyScanner(concreteTypeExtractor, compositionRootTypeExtractor, compositionRootExecutor);
+ PropertyDependencySelector = new PropertyDependencySelector(new PropertySelector());
+ ConstructorDependencySelector = new ConstructorDependencySelector();
+ ConstructorSelector = new MostResolvableConstructorSelector(CanGetInstance);
+ constructionInfoProvider = new Lazy(CreateConstructionInfoProvider);
+ methodSkeletonFactory = (returnType, parameterTypes) => new DynamicMethodSkeleton(returnType, parameterTypes);
+ ScopeManagerProvider = new PerThreadScopeManagerProvider();
+ AssemblyLoader = new AssemblyLoader();
+ }
+
+ ///
+ /// Gets or sets the that is responsible
+ /// for providing the used to manage scopes.
+ ///
+ public IScopeManagerProvider ScopeManagerProvider { get; set; }
+
+ ///
+ /// Gets or sets the instance that
+ /// is responsible for selecting the property dependencies for a given type.
+ ///
+ public IPropertyDependencySelector PropertyDependencySelector { get; set; }
+
+ ///
+ /// Gets or sets the instance that
+ /// is responsible for selecting the constructor dependencies for a given constructor.
+ ///
+ public IConstructorDependencySelector ConstructorDependencySelector { get; set; }
+
+ ///
+ /// Gets or sets the instance that is responsible
+ /// for selecting the constructor to be used when creating new service instances.
+ ///
+ public IConstructorSelector ConstructorSelector { get; set; }
+
+ ///
+ /// Gets or sets the instance that is responsible for scanning assemblies.
+ ///
+ public IAssemblyScanner AssemblyScanner { get; set; }
+
+ ///
+ /// Gets or sets the instance that is responsible for loading assemblies during assembly scanning.
+ ///
+ public IAssemblyLoader AssemblyLoader { get; set; }
+
+ ///
+ /// Gets a list of instances that represents the registered services.
+ ///
+ public IEnumerable AvailableServices
+ {
+ get
+ {
+ return availableServices.Values.SelectMany(t => t.Values);
+ }
+ }
+
+ ///
+ /// Returns true if the container can create the requested service, otherwise false .
+ ///
+ /// The of the service.
+ /// The name of the service.
+ /// true if the container can create the requested service, otherwise false .
+ public bool CanGetInstance(Type serviceType, string serviceName)
+ {
+ return GetEmitMethod(serviceType, serviceName) != null;
+ }
+
+ ///
+ /// Starts a new .
+ ///
+ ///
+ public Scope BeginScope()
+ {
+ return ScopeManagerProvider.GetScopeManager().BeginScope();
+ }
+
+ ///
+ /// Ends the current .
+ ///
+ public void EndCurrentScope()
+ {
+ Scope currentScope = ScopeManagerProvider.GetScopeManager().CurrentScope;
+ currentScope.Dispose();
+ }
+
+ ///
+ /// Injects the property dependencies for a given .
+ ///
+ /// The target instance for which to inject its property dependencies.
+ /// The with its property dependencies injected.
+ public object InjectProperties(object instance)
+ {
+ var type = instance.GetType();
+
+ var del = propertyInjectionDelegates.Search(type);
+
+ if (del == null)
+ {
+ del = CreatePropertyInjectionDelegate(type);
+ propertyInjectionDelegates = propertyInjectionDelegates.Add(type, del);
+ }
+
+ return del(constants.Items, instance);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ /// The name of the service.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(Expression> factory, string serviceName, ILifetime lifetime)
+ {
+ RegisterServiceFromLambdaExpression(factory, lifetime, serviceName);
+ }
+
+ ///
+ /// Registers a custom factory delegate used to create services that is otherwise unknown to the service container.
+ ///
+ /// Determines if the service can be created by the delegate.
+ /// Creates a service instance according to the predicate.
+ public void RegisterFallback(Func predicate, Func factory)
+ {
+ factoryRules.Add(new FactoryRule { CanCreateInstance = predicate, Factory = factory });
+ }
+
+ ///
+ /// Registers a custom factory delegate used to create services that is otherwise unknown to the service container.
+ ///
+ /// Determines if the service can be created by the delegate.
+ /// Creates a service instance according to the predicate.
+ /// The instance that controls the lifetime of the registered service.
+ public void RegisterFallback(Func predicate, Func factory, ILifetime lifetime)
+ {
+ factoryRules.Add(new FactoryRule { CanCreateInstance = predicate, Factory = factory, LifeTime = lifetime });
+ }
+
+ ///
+ /// Registers a service based on a instance.
+ ///
+ /// The instance that contains service metadata.
+ public void Register(ServiceRegistration serviceRegistration)
+ {
+ var services = GetAvailableServices(serviceRegistration.ServiceType);
+ var sr = serviceRegistration;
+ services.AddOrUpdate(
+ serviceRegistration.ServiceName,
+ s => AddServiceRegistration(sr),
+ (k, existing) => UpdateServiceRegistration(existing, sr));
+ }
+
+ ///
+ /// Registers composition roots from the given .
+ ///
+ /// The assembly to be scanned for services.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ public void RegisterAssembly(Assembly assembly)
+ {
+ Type[] compositionRootTypes = compositionRootTypeExtractor.Execute(assembly);
+ if (compositionRootTypes.Length == 0)
+ {
+ RegisterAssembly(assembly, (serviceType, implementingType) => true);
+ }
+ else
+ {
+ AssemblyScanner.Scan(assembly, this);
+ }
+ }
+
+ ///
+ /// Registers services from the given .
+ ///
+ /// The assembly to be scanned for services.
+ /// A function delegate that determines if a service implementation should be registered.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ public void RegisterAssembly(Assembly assembly, Func shouldRegister)
+ {
+ AssemblyScanner.Scan(assembly, this, () => null, shouldRegister);
+ }
+
+ ///
+ /// Registers services from the given .
+ ///
+ /// The assembly to be scanned for services.
+ /// The factory that controls the lifetime of the registered service.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ public void RegisterAssembly(Assembly assembly, Func lifetimeFactory)
+ {
+ AssemblyScanner.Scan(assembly, this, lifetimeFactory, (serviceType, implementingType) => true);
+ }
+
+ ///
+ /// Registers services from the given .
+ ///
+ /// The assembly to be scanned for services.
+ /// The factory that controls the lifetime of the registered service.
+ /// A function delegate that determines if a service implementation should be registered.
+ ///
+ /// If the target contains an implementation of the interface, this
+ /// will be used to configure the container.
+ ///
+ public void RegisterAssembly(Assembly assembly, Func lifetimeFactory, Func shouldRegister)
+ {
+ AssemblyScanner.Scan(assembly, this, lifetimeFactory, shouldRegister);
+ }
+
+ ///
+ /// Registers services from the given type.
+ ///
+ /// The type of to register from.
+ public void RegisterFrom() where TCompositionRoot : ICompositionRoot, new()
+ {
+ compositionRootExecutor.Execute(typeof(TCompositionRoot));
+ }
+
+ ///
+ /// Registers composition roots from assemblies in the base directory that matches the .
+ ///
+ /// The search pattern used to filter the assembly files.
+ public void RegisterAssembly(string searchPattern)
+ {
+ foreach (Assembly assembly in AssemblyLoader.Load(searchPattern))
+ {
+ RegisterAssembly(assembly);
+ }
+ }
+
+ ///
+ /// Decorates the with the given .
+ ///
+ /// The target service type.
+ /// The decorator type used to decorate the .
+ /// A function delegate that determines if the
+ /// should be applied to the target .
+ public void Decorate(Type serviceType, Type decoratorType, Func predicate)
+ {
+ var decoratorRegistration = new DecoratorRegistration { ServiceType = serviceType, ImplementingType = decoratorType, CanDecorate = predicate };
+ Decorate(decoratorRegistration);
+ }
+
+ ///
+ /// Decorates the with the given .
+ ///
+ /// The target service type.
+ /// The decorator type used to decorate the .
+ public void Decorate(Type serviceType, Type decoratorType)
+ {
+ Decorate(serviceType, decoratorType, si => true);
+ }
+
+ ///
+ /// Decorates the with the given .
+ ///
+ /// The target service type.
+ /// The decorator type used to decorate the .
+ public void Decorate() where TDecorator : TService
+ {
+ Decorate(typeof(TService), typeof(TDecorator));
+ }
+
+ ///
+ /// Decorates the using the given decorator .
+ ///
+ /// The target service type.
+ /// A factory delegate used to create a decorator instance.
+ public void Decorate(Expression> factory)
+ {
+ var decoratorRegistration = new DecoratorRegistration { FactoryExpression = factory, ServiceType = typeof(TService), CanDecorate = si => true };
+ Decorate(decoratorRegistration);
+ }
+
+ ///
+ /// Registers a decorator based on a instance.
+ ///
+ /// The instance that contains the decorator metadata.
+ public void Decorate(DecoratorRegistration decoratorRegistration)
+ {
+ int index = decorators.Add(decoratorRegistration);
+ decoratorRegistration.Index = index;
+ }
+
+ ///
+ /// Allows a registered service to be overridden by another .
+ ///
+ /// A function delegate that is used to determine the service that should be
+ /// overridden using the returned from the .
+ /// The factory delegate used to create a that overrides
+ /// the incoming .
+ public void Override(Func serviceSelector, Func serviceRegistrationFactory)
+ {
+ var serviceOverride = new ServiceOverride
+ {
+ CanOverride = serviceSelector,
+ ServiceRegistrationFactory = serviceRegistrationFactory
+ };
+ overrides.Add(serviceOverride);
+ }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(Type serviceType, Type implementingType, ILifetime lifetime)
+ {
+ Register(serviceType, implementingType, string.Empty, lifetime);
+ }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(Type serviceType, Type implementingType, string serviceName, ILifetime lifetime)
+ {
+ RegisterService(serviceType, implementingType, lifetime, serviceName);
+ }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ public void Register() where TImplementation : TService
+ {
+ Register(typeof(TService), typeof(TImplementation));
+ }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(ILifetime lifetime) where TImplementation : TService
+ {
+ Register(typeof(TService), typeof(TImplementation), lifetime);
+ }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ public void Register(string serviceName) where TImplementation : TService
+ {
+ Register(serviceName, lifetime: null);
+ }
+
+ ///
+ /// Registers the with the .
+ ///
+ /// The service type to register.
+ /// The implementing type.
+ /// The name of the service.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(string serviceName, ILifetime lifetime) where TImplementation : TService
+ {
+ Register(typeof(TService), typeof(TImplementation), serviceName, lifetime);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(Expression> factory, ILifetime lifetime)
+ {
+ RegisterServiceFromLambdaExpression(factory, lifetime, string.Empty);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ /// The name of the service.
+ public void Register(Expression> factory, string serviceName)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, serviceName);
+ }
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The service type to register.
+ public void Register()
+ {
+ Register();
+ }
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The concrete type to register.
+ public void Register(Type serviceType)
+ {
+ Register(serviceType, serviceType);
+ }
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The concrete type to register.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(Type serviceType, ILifetime lifetime)
+ {
+ Register(serviceType, serviceType, lifetime);
+ }
+
+ ///
+ /// Registers a concrete type as a service.
+ ///
+ /// The service type to register.
+ /// The instance that controls the lifetime of the registered service.
+ public void Register(ILifetime lifetime)
+ {
+ Register(lifetime);
+ }
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ /// The name of the service.
+ public void RegisterInstance(TService instance, string serviceName)
+ {
+ RegisterInstance(typeof(TService), instance, serviceName);
+ }
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ public void RegisterInstance(TService instance)
+ {
+ RegisterInstance(typeof(TService), instance);
+ }
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ public void RegisterInstance(Type serviceType, object instance)
+ {
+ RegisterInstance(serviceType, instance, string.Empty);
+ }
+
+ ///
+ /// Registers the with the given .
+ ///
+ /// The service type to register.
+ /// The instance returned when this service is requested.
+ /// The name of the service.
+ public void RegisterInstance(Type serviceType, object instance, string serviceName)
+ {
+ RegisterValue(serviceType, instance, serviceName);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The service type to register.
+ /// The lambdaExpression that describes the dependencies of the service.
+ public void Register(Expression> factory)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, string.Empty);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The parameter type.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ public void Register(Expression> factory)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, string.Empty);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The parameter type.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ public void Register(Expression> factory, string serviceName)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, serviceName);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ public void Register(Expression> factory)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, string.Empty);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ public void Register(Expression> factory, string serviceName)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, serviceName);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ public void Register(Expression> factory)
+ {
+ RegisterServiceFromLambdaExpression(factory, null, string.Empty);
+ }
+
+ ///
+ /// Registers the with the that
+ /// describes the dependencies of the service.
+ ///
+ /// The type of the first parameter.
+ /// The type of the second parameter.
+ /// The type of the third parameter.
+ /// The service type to register.
+ /// A factory delegate used to create the instance.
+ /// The name of the service.
+ public void Register(Expression> factory, string serviceName)
+ {
+ RegisterServiceFromLambdaExpression