diff --git a/Marr.Data/Marr.Data.csproj b/Marr.Data/Marr.Data.csproj index 6cd601100..060887697 100644 --- a/Marr.Data/Marr.Data.csproj +++ b/Marr.Data/Marr.Data.csproj @@ -20,7 +20,8 @@ 3.5 - + + ..\ true diff --git a/NzbDrone.Api/ApiContainerExtensions.cs b/NzbDrone.Api/ApiContainerExtensions.cs deleted file mode 100644 index 01ca85966..000000000 --- a/NzbDrone.Api/ApiContainerExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Linq; -using Autofac; -using Nancy.Bootstrapper; -using NzbDrone.Common; - -namespace NzbDrone.Api -{ - public static class ApiContainerExtensions - { - public static void RegisterApiServices(this ContainerBuilder containerBuilder) - { - containerBuilder.RegisterAssemblyTypes("NzbDrone.Api"); - containerBuilder.RegisterType().As(); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Api/Extensions/RootPathProvider.cs b/NzbDrone.Api/Extensions/RootPathProvider.cs deleted file mode 100644 index 8f19bdb73..000000000 --- a/NzbDrone.Api/Extensions/RootPathProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.IO; -using System.Linq; -using Nancy; - -namespace NzbDrone.Api.Extensions -{ - public class RootPathProvider : IRootPathProvider - { - public string GetRootPath() - { - return Directory.GetCurrentDirectory(); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Api/NancyBootstrapper.cs b/NzbDrone.Api/NancyBootstrapper.cs index 4b7535f2e..6fad25955 100644 --- a/NzbDrone.Api/NancyBootstrapper.cs +++ b/NzbDrone.Api/NancyBootstrapper.cs @@ -1,54 +1,48 @@ using System; using System.Collections.Generic; -using Autofac; using NLog; -using Nancy; using Nancy.Bootstrapper; -using Nancy.Bootstrappers.Autofac; using Nancy.Conventions; using Nancy.Diagnostics; using NzbDrone.Api.ErrorManagement; using NzbDrone.Api.Extensions; using NzbDrone.Api.Frontend; using NzbDrone.Common; -using NzbDrone.Core; using NzbDrone.Core.Configuration; using NzbDrone.Core.Lifecycle; -using SignalR; +using TinyIoC; using ErrorPipeline = NzbDrone.Api.ErrorManagement.ErrorPipeline; namespace NzbDrone.Api { - - public class NancyBootstrapper : AutofacNancyBootstrapper + public class TinyNancyBootstrapper : TinyIoCNancyBootstrapper { + private readonly TinyIoCContainer _tinyIoCContainer; private readonly Logger _logger; - public NancyBootstrapper() + public TinyNancyBootstrapper(TinyIoCContainer tinyIoCContainer) { + _tinyIoCContainer = tinyIoCContainer; _logger = LogManager.GetCurrentClassLogger(); } - protected override Nancy.IRootPathProvider RootPathProvider - { - get - { - return new RootPathProvider(); - } - } - - protected override void ApplicationStartup(ILifetimeScope container, IPipelines pipelines) + protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) { _logger.Info("Starting NzbDrone API"); AutomapperBootstraper.InitializeAutomapper(); - SignalRBootstraper.InitializeAutomapper(container); RegisterReporting(container); KickoffInitilizables(container); ApplicationPipelines.OnError.AddItemToEndOfPipeline(container.Resolve().HandleException); } - private void KickoffInitilizables(ILifetimeScope container) + private void RegisterReporting(TinyIoCContainer container) + { + EnvironmentProvider.UGuid = container.Resolve().UGuid; + ReportingService.RestProvider = container.Resolve(); + } + + private void KickoffInitilizables(TinyIoCContainer container) { var initilizables = container.Resolve>(); @@ -67,23 +61,10 @@ namespace NzbDrone.Api } } - private void RegisterReporting(ILifetimeScope container) - { - EnvironmentProvider.UGuid = container.Resolve().UGuid; - ReportingService.RestProvider = container.Resolve(); - } - protected override ILifetimeScope GetApplicationContainer() + protected override TinyIoCContainer GetApplicationContainer() { - _logger.Debug("Initializing Service Container"); - - var builder = new ContainerBuilder(); - builder.RegisterCoreServices(); - builder.RegisterApiServices(); - - var container = builder.Build(); - - return container; + return _tinyIoCContainer; } protected override NancyInternalConfiguration InternalConfiguration @@ -110,15 +91,5 @@ namespace NzbDrone.Api var processors = ApplicationContainer.Resolve(); Conventions.StaticContentsConventions.Add(processors.ProcessStaticResourceRequest); } - - } - - public static class SignalRBootstraper - { - - public static void InitializeAutomapper(ILifetimeScope container) - { - GlobalHost.DependencyResolver = new AutofacSignalrDependencyResolver(container.BeginLifetimeScope("SignalR")); - } } } \ No newline at end of file diff --git a/NzbDrone.Api/NzbDrone.Api.csproj b/NzbDrone.Api/NzbDrone.Api.csproj index 75a2cf157..cad11de30 100644 --- a/NzbDrone.Api/NzbDrone.Api.csproj +++ b/NzbDrone.Api/NzbDrone.Api.csproj @@ -13,6 +13,8 @@ 512 ..\ true + + true @@ -53,10 +55,6 @@ - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - False ..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll @@ -68,10 +66,6 @@ False ..\packages\Nancy.0.16.1\lib\net40\Nancy.dll - - False - ..\packages\Nancy.Bootstrappers.Autofac.0.16.1\lib\net40\Nancy.Bootstrappers.Autofac.dll - False ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll @@ -94,7 +88,6 @@ - @@ -111,7 +104,6 @@ - @@ -133,6 +125,8 @@ + + diff --git a/NzbDrone.Api/TinyIoCDependencyResolver.cs b/NzbDrone.Api/TinyIoCDependencyResolver.cs new file mode 100644 index 000000000..e045a9b1d --- /dev/null +++ b/NzbDrone.Api/TinyIoCDependencyResolver.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SignalR; +using TinyIoC; + +namespace NzbDrone.Api +{ + public class TinyIoCDependencyResolver : DefaultDependencyResolver + { + private readonly TinyIoCContainer _container; + + public TinyIoCDependencyResolver(TinyIoCContainer container) + { + _container = container; + } + + public override object GetService(Type serviceType) + { + if (_container.CanResolve(serviceType)) + { + return _container.Resolve(serviceType); + } + + return base.GetService(serviceType); + } + + public override IEnumerable GetServices(Type serviceType) + { + IEnumerable services = new object[] { }; + + if (_container.CanResolve(serviceType)) + { + services = _container.ResolveAll(serviceType); + } + + return services.Concat(base.GetServices(serviceType)); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Api/TinyIoCNancyBootstrapper.cs b/NzbDrone.Api/TinyIoCNancyBootstrapper.cs new file mode 100644 index 000000000..8ed1c5795 --- /dev/null +++ b/NzbDrone.Api/TinyIoCNancyBootstrapper.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Nancy; +using Nancy.Bootstrapper; +using Nancy.Diagnostics; +using TinyIoC; + +namespace NzbDrone.Api +{ + public abstract class TinyIoCNancyBootstrapper : NancyBootstrapperWithRequestContainerBase + { + /// + /// Resolve INancyEngine + /// + /// INancyEngine implementation + protected override sealed INancyEngine GetEngineInternal() + { + return this.ApplicationContainer.Resolve(); + } + + /// + /// Get the moduleKey generator + /// + /// IModuleKeyGenerator instance + protected override sealed IModuleKeyGenerator GetModuleKeyGenerator() + { + return this.ApplicationContainer.Resolve(); + } + + /// + /// Create a default, unconfigured, container + /// + /// Container instance + protected override TinyIoCContainer GetApplicationContainer() + { + return new TinyIoCContainer(); + } + + /// + /// Register the bootstrapper's implemented types into the container. + /// This is necessary so a user can pass in a populated container but not have + /// to take the responsibility of registering things like INancyModuleCatalog manually. + /// + /// Application container to register into + protected override sealed void RegisterBootstrapperTypes(TinyIoCContainer applicationContainer) + { + applicationContainer.Register(this); + } + + /// + /// Register the default implementations of internally used types into the container as singletons + /// + /// Container to register into + /// Type registrations to register + protected override sealed void RegisterTypes(TinyIoCContainer container, IEnumerable typeRegistrations) + { + foreach (var typeRegistration in typeRegistrations) + { + container.Register(typeRegistration.RegistrationType, typeRegistration.ImplementationType).AsSingleton(); + } + } + + /// + /// Register the various collections into the container as singletons to later be resolved + /// by IEnumerable{Type} constructor dependencies. + /// + /// Container to register into + /// Collection type registrations to register + protected override sealed void RegisterCollectionTypes(TinyIoCContainer container, IEnumerable collectionTypeRegistrationsn) + { + foreach (var collectionTypeRegistration in collectionTypeRegistrationsn) + { + container.RegisterMultiple(collectionTypeRegistration.RegistrationType, collectionTypeRegistration.ImplementationTypes.Distinct()); + } + } + + /// + /// Register the given module types into the container + /// + /// Container to register into + /// NancyModule types + protected override sealed void RegisterRequestContainerModules(TinyIoCContainer container, IEnumerable moduleRegistrationTypes) + { + foreach (var moduleRegistrationType in moduleRegistrationTypes) + { + container.Register( + typeof(INancyModule), + moduleRegistrationType.ModuleType, + moduleRegistrationType.ModuleKey). + AsSingleton(); + } + } + + /// + /// Register the given instances into the container + /// + /// Container to register into + /// Instance registration types + protected override void RegisterInstances(TinyIoCContainer container, IEnumerable instanceRegistrations) + { + foreach (var instanceRegistration in instanceRegistrations) + { + container.Register( + instanceRegistration.RegistrationType, + instanceRegistration.Implementation); + } + } + + /// + /// Creates a per request child/nested container + /// + /// Request container instance + protected override sealed TinyIoCContainer CreateRequestContainer() + { + return this.ApplicationContainer.GetChildContainer(); + } + + /// + /// Gets the diagnostics for intialisation + /// + /// IDagnostics implementation + protected override IDiagnostics GetDiagnostics() + { + return this.ApplicationContainer.Resolve(); + } + + /// + /// Gets all registered startup tasks + /// + /// An instance containing instances. + protected override IEnumerable GetApplicationStartupTasks() + { + return this.ApplicationContainer.ResolveAll(false); + } + + /// + /// Gets all registered application registration tasks + /// + /// An instance containing instances. + protected override IEnumerable GetApplicationRegistrationTasks() + { + return this.ApplicationContainer.ResolveAll(false); + } + + /// + /// Retrieve all module instances from the container + /// + /// Container to use + /// Collection of NancyModule instances + protected override sealed IEnumerable GetAllModules(TinyIoCContainer container) + { + var nancyModules = container.ResolveAll(false); + return nancyModules; + } + + /// + /// Retreive a specific module instance from the container by its key + /// + /// Container to use + /// Module key of the module + /// NancyModule instance + protected override sealed INancyModule GetModuleByKey(TinyIoCContainer container, string moduleKey) + { + return container.Resolve(moduleKey); + } + + /// + /// Executes auto registation with the given container. + /// + /// Container instance + private static void AutoRegister(TinyIoCContainer container, IEnumerable> ignoredAssemblies) + { + var assembly = typeof(NancyEngine).Assembly; + + var whitelist = new Type[] { }; + + container.AutoRegister(AppDomain.CurrentDomain.GetAssemblies().Where(a => !ignoredAssemblies.Any(ia => ia(a))), t => t.Assembly != assembly || whitelist.Any(wt => wt == t)); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Api/packages.config b/NzbDrone.Api/packages.config index c61a1a28d..4299af370 100644 --- a/NzbDrone.Api/packages.config +++ b/NzbDrone.Api/packages.config @@ -1,10 +1,8 @@  - - diff --git a/NzbDrone.App.Test/NzbDrone.App.Test.csproj b/NzbDrone.App.Test/NzbDrone.App.Test.csproj index 62096af43..a76f20d73 100644 --- a/NzbDrone.App.Test/NzbDrone.App.Test.csproj +++ b/NzbDrone.App.Test/NzbDrone.App.Test.csproj @@ -53,10 +53,6 @@ MinimumRecommendedRules.ruleset - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - False ..\packages\Exceptron.Client.1.0.20\lib\net20\Exceptron.Client.dll diff --git a/NzbDrone.App.Test/packages.config b/NzbDrone.App.Test/packages.config index f10567332..a1254ed6d 100644 --- a/NzbDrone.App.Test/packages.config +++ b/NzbDrone.App.Test/packages.config @@ -1,6 +1,5 @@  - diff --git a/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj b/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj index 2eeca23ee..9c9fd50fc 100644 --- a/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj +++ b/NzbDrone.Common.Test/NzbDrone.Common.Test.csproj @@ -53,14 +53,6 @@ MinimumRecommendedRules.ruleset - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll - False ..\packages\FluentAssertions.2.0.1\lib\net40\FluentAssertions.dll diff --git a/NzbDrone.Common.Test/packages.config b/NzbDrone.Common.Test/packages.config index 4d5465ff2..fe8992544 100644 --- a/NzbDrone.Common.Test/packages.config +++ b/NzbDrone.Common.Test/packages.config @@ -1,6 +1,5 @@  - diff --git a/NzbDrone.Common/CommonContainerExtentions.cs b/NzbDrone.Common/CommonContainerExtentions.cs deleted file mode 100644 index f75bb70f9..000000000 --- a/NzbDrone.Common/CommonContainerExtentions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using Autofac; - -namespace NzbDrone.Common -{ - public static class CommonContainerExtensions - { - public static void RegisterCommonServices(this ContainerBuilder containerBuilder) - { - containerBuilder.RegisterAssemblyTypes("NzbDrone.Common"); - } - - public static void RegisterAssemblyTypes(this ContainerBuilder containerBuilder, string assemblyName) - { - var apiAssembly = Assembly.Load(assemblyName); - - if (apiAssembly == null) - { - throw new ApplicationException("Couldn't load assembly " + assemblyName); - } - - containerBuilder.RegisterAssemblyTypes(apiAssembly) - .AsImplementedInterfaces(); - - containerBuilder.RegisterAssemblyTypes(apiAssembly) - .AsSelf(); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Common/NzbDrone.Common.csproj b/NzbDrone.Common/NzbDrone.Common.csproj index ec3b28cd5..0f6d87234 100644 --- a/NzbDrone.Common/NzbDrone.Common.csproj +++ b/NzbDrone.Common/NzbDrone.Common.csproj @@ -14,6 +14,8 @@ 512 ..\ true + + true @@ -53,10 +55,6 @@ MinimumRecommendedRules.ruleset - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll @@ -84,7 +82,6 @@ - @@ -111,6 +108,7 @@ + @@ -133,6 +131,7 @@ Form + diff --git a/NzbDrone.Common/ReflectionExtentions.cs b/NzbDrone.Common/ReflectionExtentions.cs new file mode 100644 index 000000000..32ce6759a --- /dev/null +++ b/NzbDrone.Common/ReflectionExtentions.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace NzbDrone.Common +{ + public static class ReflectionExtensions + { + public static IEnumerable GetInterfaces(this Assembly assembly) + { + return assembly.GetTypes().Where(c => c.IsInterface); + } + + public static IEnumerable GetImplementations(this Assembly assembly, Type contractType) + { + return assembly.GetTypes() + .Where(implementation => + contractType.IsAssignableFrom(implementation) && + !implementation.IsInterface && + !implementation.IsAbstract + ); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Common/TinyIoC.cs b/NzbDrone.Common/TinyIoC.cs new file mode 100644 index 000000000..d10956002 --- /dev/null +++ b/NzbDrone.Common/TinyIoC.cs @@ -0,0 +1,3878 @@ +//=============================================================================== +// TinyIoC +// +// An easy to use, hassle free, Inversion of Control Container for small projects +// and beginners alike. +// +// https://github.com/grumpydev/TinyIoC +//=============================================================================== +// Copyright © Steven Robbins. All rights reserved. +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT +// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE. +//=============================================================================== + +#region Preprocessor Directives +// Uncomment this line if you want the container to automatically +// register the TinyMessenger messenger/event aggregator +//#define TINYMESSENGER + +// Preprocessor directives for enabling/disabling functionality +// depending on platform features. If the platform has an appropriate +// #DEFINE then these should be set automatically below. + + +#define EXPRESSIONS // Platform supports System.Linq.Expressions +#define COMPILED_EXPRESSIONS // Platform supports compiling expressions +#define APPDOMAIN_GETASSEMBLIES // Platform supports getting all assemblies from the AppDomain object +#define UNBOUND_GENERICS_GETCONSTRUCTORS // Platform supports GetConstructors on unbound generic types +#define GETPARAMETERS_OPEN_GENERICS // Platform supports GetParameters on open generics +#define RESOLVE_OPEN_GENERICS // Platform supports resolving open generics +#define READER_WRITER_LOCK_SLIM // Platform supports ReaderWriterLockSlim + +//// NETFX_CORE +//#if NETFX_CORE +//#endif + +// CompactFramework / Windows Phone 7 +// By default does not support System.Linq.Expressions. +// AppDomain object does not support enumerating all assemblies in the app domain. +#if PocketPC || WINDOWS_PHONE +#undef EXPRESSIONS +#undef COMPILED_EXPRESSIONS +#undef APPDOMAIN_GETASSEMBLIES +#undef UNBOUND_GENERICS_GETCONSTRUCTORS +#endif + +// PocketPC has a bizarre limitation on enumerating parameters on unbound generic methods. +// We need to use a slower workaround in that case. +#if PocketPC +#undef GETPARAMETERS_OPEN_GENERICS +#undef RESOLVE_OPEN_GENERICS +#undef READER_WRITER_LOCK_SLIM +#endif + +#if SILVERLIGHT +#undef APPDOMAIN_GETASSEMBLIES +#endif + +#if NETFX_CORE +#undef APPDOMAIN_GETASSEMBLIES +#undef RESOLVE_OPEN_GENERICS +#endif + +#if COMPILED_EXPRESSIONS +#define USE_OBJECT_CONSTRUCTOR +#endif + +#endregion +namespace TinyIoC +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using System.Reflection; + using NLog; + +#if EXPRESSIONS + using System.Linq.Expressions; + using System.Threading; + +#endif + +#if NETFX_CORE + using System.Threading.Tasks; + using Windows.Storage.Search; + using Windows.Storage; + using Windows.UI.Xaml.Shapes; +#endif + + #region SafeDictionary +#if READER_WRITER_LOCK_SLIM + public class SafeDictionary : IDisposable + { + private readonly ReaderWriterLockSlim _padlock = new ReaderWriterLockSlim(); + private readonly Dictionary _Dictionary = new Dictionary(); + + public TValue this[TKey key] + { + set + { + _padlock.EnterWriteLock(); + + try + { + TValue current; + if (_Dictionary.TryGetValue(key, out current)) + { + var disposable = current as IDisposable; + + if (disposable != null) + disposable.Dispose(); + } + + _Dictionary[key] = value; + } + finally + { + _padlock.ExitWriteLock(); + } + } + } + + public bool TryGetValue(TKey key, out TValue value) + { + _padlock.EnterReadLock(); + try + { + return _Dictionary.TryGetValue(key, out value); + } + finally + { + _padlock.ExitReadLock(); + } + } + + public bool Remove(TKey key) + { + _padlock.EnterWriteLock(); + try + { + return _Dictionary.Remove(key); + } + finally + { + _padlock.ExitWriteLock(); + } + } + + public void Clear() + { + _padlock.EnterWriteLock(); + try + { + _Dictionary.Clear(); + } + finally + { + _padlock.ExitWriteLock(); + } + } + + public IEnumerable Keys + { + get + { + _padlock.EnterReadLock(); + try + { + return new List(_Dictionary.Keys); + } + finally + { + _padlock.ExitReadLock(); + } + } + } + + #region IDisposable Members + + public void Dispose() + { + _padlock.EnterWriteLock(); + + try + { + var disposableItems = from item in _Dictionary.Values + where item is IDisposable + select item as IDisposable; + + foreach (var item in disposableItems) + { + item.Dispose(); + } + } + finally + { + _padlock.ExitWriteLock(); + } + + GC.SuppressFinalize(this); + } + + #endregion + } +#else + public class SafeDictionary : IDisposable + { + private readonly object _Padlock = new object(); + private readonly Dictionary _Dictionary = new Dictionary(); + + public TValue this[TKey key] + { + set + { + lock (_Padlock) + { + TValue current; + if (_Dictionary.TryGetValue(key, out current)) + { + var disposable = current as IDisposable; + + if (disposable != null) + disposable.Dispose(); + } + + _Dictionary[key] = value; + } + } + } + + public bool TryGetValue(TKey key, out TValue value) + { + lock (_Padlock) + { + return _Dictionary.TryGetValue(key, out value); + } + } + + public bool Remove(TKey key) + { + lock (_Padlock) + { + return _Dictionary.Remove(key); + } + } + + public void Clear() + { + lock (_Padlock) + { + _Dictionary.Clear(); + } + } + + public IEnumerable Keys + { + get + { + return _Dictionary.Keys; + } + } + #region IDisposable Members + + public void Dispose() + { + lock (_Padlock) + { + var disposableItems = from item in _Dictionary.Values + where item is IDisposable + select item as IDisposable; + + foreach (var item in disposableItems) + { + item.Dispose(); + } + } + + GC.SuppressFinalize(this); + } + + #endregion + } +#endif + #endregion + + #region Extensions + public static class AssemblyExtensions + { + public static Type[] SafeGetTypes(this Assembly assembly) + { + Type[] assemblies; + + try + { + assemblies = assembly.GetTypes(); + } + catch (System.IO.FileNotFoundException) + { + assemblies = new Type[] { }; + } + catch (NotSupportedException) + { + assemblies = new Type[] { }; + } +#if !NETFX_CORE + catch (ReflectionTypeLoadException e) + { + assemblies = e.Types.Where(t => t != null).ToArray(); + } +#endif + return assemblies; + } + } + + public static class TypeExtensions + { + private static SafeDictionary _genericMethodCache; + + static TypeExtensions() + { + _genericMethodCache = new SafeDictionary(); + } + + //#if NETFX_CORE + // /// + // /// Gets a generic method from a type given the method name, generic types and parameter types + // /// + // /// Source type + // /// Name of the method + // /// Generic types to use to make the method generic + // /// Method parameters + // /// MethodInfo or null if no matches found + // /// + // /// + // public static MethodInfo GetGenericMethod(this Type sourceType, string methodName, Type[] genericTypes, Type[] parameterTypes) + // { + // MethodInfo method; + // var cacheKey = new GenericMethodCacheKey(sourceType, methodName, genericTypes, parameterTypes); + + // // Shouldn't need any additional locking + // // we don't care if we do the method info generation + // // more than once before it gets cached. + // if (!_genericMethodCache.TryGetValue(cacheKey, out method)) + // { + // method = GetMethod(sourceType, methodName, genericTypes, parameterTypes); + // _genericMethodCache[cacheKey] = method; + // } + + // return method; + // } + //#else + /// + /// Gets a generic method from a type given the method name, binding flags, generic types and parameter types + /// + /// Source type + /// Binding flags + /// Name of the method + /// Generic types to use to make the method generic + /// Method parameters + /// MethodInfo or null if no matches found + /// + /// + public static MethodInfo GetGenericMethod(this Type sourceType, BindingFlags bindingFlags, string methodName, Type[] genericTypes, Type[] parameterTypes) + { + MethodInfo method; + var cacheKey = new GenericMethodCacheKey(sourceType, methodName, genericTypes, parameterTypes); + + // Shouldn't need any additional locking + // we don't care if we do the method info generation + // more than once before it gets cached. + if (!_genericMethodCache.TryGetValue(cacheKey, out method)) + { + method = GetMethod(sourceType, bindingFlags, methodName, genericTypes, parameterTypes); + _genericMethodCache[cacheKey] = method; + } + + return method; + } + //#endif + +#if NETFX_CORE + private static MethodInfo GetMethod(Type sourceType, BindingFlags flags, string methodName, Type[] genericTypes, Type[] parameterTypes) + { + var methods = + sourceType.GetMethods(flags).Where( + mi => string.Equals(methodName, mi.Name, StringComparison.Ordinal)).Where( + mi => mi.ContainsGenericParameters).Where(mi => mi.GetGenericArguments().Length == genericTypes.Length). + Where(mi => mi.GetParameters().Length == parameterTypes.Length).Select( + mi => mi.MakeGenericMethod(genericTypes)).Where( + mi => mi.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes)).ToList(); + + if (methods.Count > 1) + { + throw new AmbiguousMatchException(); + } + + return methods.FirstOrDefault(); + } +#else + private static MethodInfo GetMethod(Type sourceType, BindingFlags bindingFlags, string methodName, Type[] genericTypes, Type[] parameterTypes) + { +#if GETPARAMETERS_OPEN_GENERICS + var methods = + sourceType.GetMethods(bindingFlags).Where( + mi => string.Equals(methodName, mi.Name, StringComparison.Ordinal)).Where( + mi => mi.ContainsGenericParameters).Where(mi => mi.GetGenericArguments().Length == genericTypes.Length). + Where(mi => mi.GetParameters().Length == parameterTypes.Length).Select( + mi => mi.MakeGenericMethod(genericTypes)).Where( + mi => mi.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes)).ToList(); +#else + var validMethods = from method in sourceType.GetMethods(bindingFlags) + where method.Name == methodName + where method.IsGenericMethod + where method.GetGenericArguments().Length == genericTypes.Length + let genericMethod = method.MakeGenericMethod(genericTypes) + where genericMethod.GetParameters().Count() == parameterTypes.Length + where genericMethod.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes) + select genericMethod; + + var methods = validMethods.ToList(); +#endif + if (methods.Count > 1) + { + throw new AmbiguousMatchException(); + } + + return methods.FirstOrDefault(); + } +#endif + + private sealed class GenericMethodCacheKey + { + private readonly Type _sourceType; + + private readonly string _methodName; + + private readonly Type[] _genericTypes; + + private readonly Type[] _parameterTypes; + + private readonly int _hashCode; + + public GenericMethodCacheKey(Type sourceType, string methodName, Type[] genericTypes, Type[] parameterTypes) + { + _sourceType = sourceType; + _methodName = methodName; + _genericTypes = genericTypes; + _parameterTypes = parameterTypes; + _hashCode = GenerateHashCode(); + } + + public override bool Equals(object obj) + { + var cacheKey = obj as GenericMethodCacheKey; + if (cacheKey == null) + return false; + + if (_sourceType != cacheKey._sourceType) + return false; + + if (!String.Equals(_methodName, cacheKey._methodName, StringComparison.Ordinal)) + return false; + + if (_genericTypes.Length != cacheKey._genericTypes.Length) + return false; + + if (_parameterTypes.Length != cacheKey._parameterTypes.Length) + return false; + + for (int i = 0; i < _genericTypes.Length; ++i) + { + if (_genericTypes[i] != cacheKey._genericTypes[i]) + return false; + } + + for (int i = 0; i < _parameterTypes.Length; ++i) + { + if (_parameterTypes[i] != cacheKey._parameterTypes[i]) + return false; + } + + return true; + } + + public override int GetHashCode() + { + return _hashCode; + } + + private int GenerateHashCode() + { + unchecked + { + var result = _sourceType.GetHashCode(); + + result = (result * 397) ^ _methodName.GetHashCode(); + + for (int i = 0; i < _genericTypes.Length; ++i) + { + result = (result * 397) ^ _genericTypes[i].GetHashCode(); + } + + for (int i = 0; i < _parameterTypes.Length; ++i) + { + result = (result * 397) ^ _parameterTypes[i].GetHashCode(); + } + + return result; + } + } + } + + } + + // @mbrit - 2012-05-22 - shim for ForEach call on List... +#if NETFX_CORE + internal static class ListExtender + { + internal static void ForEach(this List list, Action callback) + { + foreach (T obj in list) + callback(obj); + } + } +#endif + + #endregion + + #region TinyIoC Exception Types + public class TinyIoCResolutionException : Exception + { + private const string ERROR_TEXT = "Unable to resolve type: {0}"; + + public TinyIoCResolutionException(Type type) + : base(String.Format(ERROR_TEXT, type.FullName)) + { + } + + public TinyIoCResolutionException(Type type, Exception innerException) + : base(String.Format(ERROR_TEXT, type.FullName), innerException) + { + } + } + + public class TinyIoCRegistrationTypeException : Exception + { + private const string REGISTER_ERROR_TEXT = "Cannot register type {0} - abstract classes or interfaces are not valid implementation types for {1}."; + + public TinyIoCRegistrationTypeException(Type type, string factory) + : base(String.Format(REGISTER_ERROR_TEXT, type.FullName, factory)) + { + } + + public TinyIoCRegistrationTypeException(Type type, string factory, Exception innerException) + : base(String.Format(REGISTER_ERROR_TEXT, type.FullName, factory), innerException) + { + } + } + + public class TinyIoCRegistrationException : Exception + { + private const string CONVERT_ERROR_TEXT = "Cannot convert current registration of {0} to {1}"; + private const string GENERIC_CONSTRAINT_ERROR_TEXT = "Type {1} is not valid for a registration of type {0}"; + + public TinyIoCRegistrationException(Type type, string method) + : base(String.Format(CONVERT_ERROR_TEXT, type.FullName, method)) + { + } + + public TinyIoCRegistrationException(Type type, string method, Exception innerException) + : base(String.Format(CONVERT_ERROR_TEXT, type.FullName, method), innerException) + { + } + + public TinyIoCRegistrationException(Type registerType, Type implementationType) + : base(String.Format(GENERIC_CONSTRAINT_ERROR_TEXT, registerType.FullName, implementationType.FullName)) + { + } + + public TinyIoCRegistrationException(Type registerType, Type implementationType, Exception innerException) + : base(String.Format(GENERIC_CONSTRAINT_ERROR_TEXT, registerType.FullName, implementationType.FullName), innerException) + { + } + } + + public class TinyIoCWeakReferenceException : Exception + { + private const string ERROR_TEXT = "Unable to instantiate {0} - referenced object has been reclaimed"; + + public TinyIoCWeakReferenceException(Type type) + : base(String.Format(ERROR_TEXT, type.FullName)) + { + } + + public TinyIoCWeakReferenceException(Type type, Exception innerException) + : base(String.Format(ERROR_TEXT, type.FullName), innerException) + { + } + } + + public class TinyIoCConstructorResolutionException : Exception + { + private const string ERROR_TEXT = "Unable to resolve constructor for {0} using provided Expression."; + + public TinyIoCConstructorResolutionException(Type type) + : base(String.Format(ERROR_TEXT, type.FullName)) + { + } + + public TinyIoCConstructorResolutionException(Type type, Exception innerException) + : base(String.Format(ERROR_TEXT, type.FullName), innerException) + { + } + + public TinyIoCConstructorResolutionException(string message, Exception innerException) + : base(message, innerException) + { + } + + public TinyIoCConstructorResolutionException(string message) + : base(message) + { + } + } + + public class TinyIoCAutoRegistrationException : Exception + { + private const string ERROR_TEXT = "Duplicate implementation of type {0} found ({1})."; + + public TinyIoCAutoRegistrationException(Type registerType, IEnumerable types) + : base(String.Format(ERROR_TEXT, registerType, GetTypesString(types))) + { + } + + public TinyIoCAutoRegistrationException(Type registerType, IEnumerable types, Exception innerException) + : base(String.Format(ERROR_TEXT, registerType, GetTypesString(types)), innerException) + { + } + + private static string GetTypesString(IEnumerable types) + { + var typeNames = from type in types + select type.FullName; + + return string.Join(",", typeNames.ToArray()); + } + } + #endregion + + #region Public Setup / Settings Classes + /// + /// Name/Value pairs for specifying "user" parameters when resolving + /// + public sealed class NamedParameterOverloads : Dictionary + { + public static NamedParameterOverloads FromIDictionary(IDictionary data) + { + return data as NamedParameterOverloads ?? new NamedParameterOverloads(data); + } + + public NamedParameterOverloads() + { + } + + public NamedParameterOverloads(IDictionary data) + : base(data) + { + } + + private static readonly NamedParameterOverloads _Default = new NamedParameterOverloads(); + + public static NamedParameterOverloads Default + { + get + { + return _Default; + } + } + } + + public enum UnregisteredResolutionActions + { + /// + /// Attempt to resolve type, even if the type isn't registered. + /// + /// Registered types/options will always take precedence. + /// + AttemptResolve, + + /// + /// Fail resolution if type not explicitly registered + /// + Fail, + + /// + /// Attempt to resolve unregistered type if requested type is generic + /// and no registration exists for the specific generic parameters used. + /// + /// Registered types/options will always take precedence. + /// + GenericsOnly + } + + public enum NamedResolutionFailureActions + { + AttemptUnnamedResolution, + Fail + } + + /// + /// Resolution settings + /// + public sealed class ResolveOptions + { + private static readonly ResolveOptions _Default = new ResolveOptions(); + private static readonly ResolveOptions _FailUnregisteredAndNameNotFound = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.Fail, UnregisteredResolutionAction = UnregisteredResolutionActions.Fail }; + private static readonly ResolveOptions _FailUnregisteredOnly = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.AttemptUnnamedResolution, UnregisteredResolutionAction = UnregisteredResolutionActions.Fail }; + private static readonly ResolveOptions _FailNameNotFoundOnly = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.Fail, UnregisteredResolutionAction = UnregisteredResolutionActions.AttemptResolve }; + + private UnregisteredResolutionActions _UnregisteredResolutionAction = UnregisteredResolutionActions.AttemptResolve; + public UnregisteredResolutionActions UnregisteredResolutionAction + { + get { return _UnregisteredResolutionAction; } + set { _UnregisteredResolutionAction = value; } + } + + private NamedResolutionFailureActions _NamedResolutionFailureAction = NamedResolutionFailureActions.Fail; + public NamedResolutionFailureActions NamedResolutionFailureAction + { + get { return _NamedResolutionFailureAction; } + set { _NamedResolutionFailureAction = value; } + } + + /// + /// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found) + /// + public static ResolveOptions Default + { + get + { + return _Default; + } + } + + /// + /// Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found + /// + public static ResolveOptions FailNameNotFoundOnly + { + get + { + return _FailNameNotFoundOnly; + } + } + + /// + /// Preconfigured option for failing on resolving unregistered types and on named resolution if name not found + /// + public static ResolveOptions FailUnregisteredAndNameNotFound + { + get + { + return _FailUnregisteredAndNameNotFound; + } + } + + /// + /// Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found + /// + public static ResolveOptions FailUnregisteredOnly + { + get + { + return _FailUnregisteredOnly; + } + } + } + #endregion + + public sealed partial class TinyIoCContainer : IDisposable + { + #region Fake NETFX_CORE Classes +#if NETFX_CORE + private sealed class MethodAccessException : Exception + { + } + + private sealed class AppDomain + { + public static AppDomain CurrentDomain { get; private set; } + + static AppDomain() + { + CurrentDomain = new AppDomain(); + } + + // @mbrit - 2012-05-30 - in WinRT, this should be done async... + public async Task> GetAssembliesAsync() + { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + + List assemblies = new List(); + + var files = await folder.GetFilesAsync(); + + foreach (StorageFile file in files) + { + if (file.FileType == ".dll" || file.FileType == ".exe") + { + AssemblyName name = new AssemblyName() { Name = System.IO.Path.GetFileNameWithoutExtension(file.Name) }; + try + { + var asm = Assembly.Load(name); + assemblies.Add(asm); + } + catch + { + // ignore exceptions here... + } + } + } + + return assemblies; + } + } +#endif + #endregion + + #region "Fluent" API + /// + /// Registration options for "fluent" API + /// + public sealed class RegisterOptions + { + private TinyIoCContainer _Container; + private TypeRegistration _Registration; + + public RegisterOptions(TinyIoCContainer container, TypeRegistration registration) + { + _Container = container; + _Registration = registration; + } + + /// + /// Make registration a singleton (single instance) if possible + /// + /// RegisterOptions + /// + public RegisterOptions AsSingleton() + { + var currentFactory = _Container.GetCurrentFactory(_Registration); + + if (currentFactory == null) + throw new TinyIoCRegistrationException(_Registration.Type, "singleton"); + + return _Container.AddUpdateRegistration(_Registration, currentFactory.SingletonVariant); + } + + /// + /// Make registration multi-instance if possible + /// + /// RegisterOptions + /// + public RegisterOptions AsMultiInstance() + { + var currentFactory = _Container.GetCurrentFactory(_Registration); + + if (currentFactory == null) + throw new TinyIoCRegistrationException(_Registration.Type, "multi-instance"); + + return _Container.AddUpdateRegistration(_Registration, currentFactory.MultiInstanceVariant); + } + + /// + /// Make registration hold a weak reference if possible + /// + /// RegisterOptions + /// + public RegisterOptions WithWeakReference() + { + var currentFactory = _Container.GetCurrentFactory(_Registration); + + if (currentFactory == null) + throw new TinyIoCRegistrationException(_Registration.Type, "weak reference"); + + return _Container.AddUpdateRegistration(_Registration, currentFactory.WeakReferenceVariant); + } + + /// + /// Make registration hold a strong reference if possible + /// + /// RegisterOptions + /// + public RegisterOptions WithStrongReference() + { + var currentFactory = _Container.GetCurrentFactory(_Registration); + + if (currentFactory == null) + throw new TinyIoCRegistrationException(_Registration.Type, "strong reference"); + + return _Container.AddUpdateRegistration(_Registration, currentFactory.StrongReferenceVariant); + } + +#if EXPRESSIONS + public RegisterOptions UsingConstructor(Expression> constructor) + { + var lambda = constructor as LambdaExpression; + if (lambda == null) + throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); + + var newExpression = lambda.Body as NewExpression; + if (newExpression == null) + throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); + + var constructorInfo = newExpression.Constructor; + if (constructorInfo == null) + throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); + + var currentFactory = _Container.GetCurrentFactory(_Registration); + if (currentFactory == null) + throw new TinyIoCConstructorResolutionException(typeof(RegisterType)); + + currentFactory.SetConstructor(constructorInfo); + + return this; + } +#endif + /// + /// Switches to a custom lifetime manager factory if possible. + /// + /// Usually used for RegisterOptions "To*" extension methods such as the ASP.Net per-request one. + /// + /// RegisterOptions instance + /// Custom lifetime manager + /// Error string to display if switch fails + /// RegisterOptions + public static RegisterOptions ToCustomLifetimeManager(RegisterOptions instance, ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + if (instance == null) + throw new ArgumentNullException("instance", "instance is null."); + + if (lifetimeProvider == null) + throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null."); + + if (String.IsNullOrEmpty(errorString)) + throw new ArgumentException("errorString is null or empty.", "errorString"); + + var currentFactory = instance._Container.GetCurrentFactory(instance._Registration); + + if (currentFactory == null) + throw new TinyIoCRegistrationException(instance._Registration.Type, errorString); + + return instance._Container.AddUpdateRegistration(instance._Registration, currentFactory.GetCustomObjectLifetimeVariant(lifetimeProvider, errorString)); + } + } + + /// + /// Registration options for "fluent" API when registering multiple implementations + /// + public sealed class MultiRegisterOptions + { + private IEnumerable _RegisterOptions; + + /// + /// Initializes a new instance of the MultiRegisterOptions class. + /// + /// Registration options + public MultiRegisterOptions(IEnumerable registerOptions) + { + _RegisterOptions = registerOptions; + } + + /// + /// Make registration a singleton (single instance) if possible + /// + /// RegisterOptions + /// + public MultiRegisterOptions AsSingleton() + { + _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton()); + return this; + } + + /// + /// Make registration multi-instance if possible + /// + /// MultiRegisterOptions + /// + public MultiRegisterOptions AsMultiInstance() + { + _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance()); + return this; + } + + private IEnumerable ExecuteOnAllRegisterOptions(Func action) + { + var newRegisterOptions = new List(); + + foreach (var registerOption in _RegisterOptions) + { + newRegisterOptions.Add(action(registerOption)); + } + + return newRegisterOptions; + } + } + #endregion + + #region Public API + #region Child Containers + public TinyIoCContainer GetChildContainer() + { + return new TinyIoCContainer(this); + } + #endregion + + #region Registration + /// + /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. + /// + /// If more than one class implements an interface then only one implementation will be registered + /// although no error will be thrown. + /// + public void AutoRegister() + { +#if APPDOMAIN_GETASSEMBLIES + AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), true, null); +#else + AutoRegisterInternal(new Assembly[] {this.GetType().Assembly()}, true, null); +#endif + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. + /// Types will only be registered if they pass the supplied registration predicate. + /// + /// If more than one class implements an interface then only one implementation will be registered + /// although no error will be thrown. + /// + /// Predicate to determine if a particular type should be registered + public void AutoRegister(Func registrationPredicate) + { +#if APPDOMAIN_GETASSEMBLIES + AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), true, registrationPredicate); +#else + AutoRegisterInternal(new Assembly[] { this.GetType().Assembly()}, true, registrationPredicate); +#endif + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. + /// + /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception + /// + public void AutoRegister(bool ignoreDuplicateImplementations) + { +#if APPDOMAIN_GETASSEMBLIES + AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), ignoreDuplicateImplementations, null); +#else + AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, null); +#endif + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. + /// Types will only be registered if they pass the supplied registration predicate. + /// + /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception + /// Predicate to determine if a particular type should be registered + /// + public void AutoRegister(bool ignoreDuplicateImplementations, Func registrationPredicate) + { +#if APPDOMAIN_GETASSEMBLIES + AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), ignoreDuplicateImplementations, registrationPredicate); +#else + AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, registrationPredicate); +#endif + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + /// + /// If more than one class implements an interface then only one implementation will be registered + /// although no error will be thrown. + /// + /// Assemblies to process + public void AutoRegister(IEnumerable assemblies) + { + AutoRegisterInternal(assemblies, true, null); + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + /// Types will only be registered if they pass the supplied registration predicate. + /// + /// If more than one class implements an interface then only one implementation will be registered + /// although no error will be thrown. + /// + /// Assemblies to process + /// Predicate to determine if a particular type should be registered + public void AutoRegister(IEnumerable assemblies, Func registrationPredicate) + { + AutoRegisterInternal(assemblies, true, registrationPredicate); + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + /// + /// Assemblies to process + /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception + /// + public void AutoRegister(IEnumerable assemblies, bool ignoreDuplicateImplementations) + { + AutoRegisterInternal(assemblies, ignoreDuplicateImplementations, null); + } + + /// + /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies + /// Types will only be registered if they pass the supplied registration predicate. + /// + /// Assemblies to process + /// Whether to ignore duplicate implementations of an interface/base class. False=throw an exception + /// Predicate to determine if a particular type should be registered + /// + public void AutoRegister(IEnumerable assemblies, bool ignoreDuplicateImplementations, Func registrationPredicate) + { + AutoRegisterInternal(assemblies, ignoreDuplicateImplementations, registrationPredicate); + } + + /// + /// Creates/replaces a container class registration with default options. + /// + /// Type to register + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType) + { + return RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerType)); + } + + /// + /// Creates/replaces a named container class registration with default options. + /// + /// Type to register + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, string name) + { + return RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerType)); + + } + + /// + /// Creates/replaces a container class registration with a given implementation and default options. + /// + /// Type to register + /// Type to instantiate that implements RegisterType + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, Type registerImplementation) + { + return this.RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerImplementation)); + } + + /// + /// Creates/replaces a named container class registration with a given implementation and default options. + /// + /// Type to register + /// Type to instantiate that implements RegisterType + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, Type registerImplementation, string name) + { + return this.RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerImplementation)); + } + + /// + /// Creates/replaces a container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Instance of RegisterType to register + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, object instance) + { + return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerType, instance)); + } + + /// + /// Creates/replaces a named container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Instance of RegisterType to register + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, object instance, string name) + { + return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerType, instance)); + } + + /// + /// Creates/replaces a container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Type of instance to register that implements RegisterType + /// Instance of RegisterImplementation to register + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, Type registerImplementation, object instance) + { + return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerImplementation, instance)); + } + + /// + /// Creates/replaces a named container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Type of instance to register that implements RegisterType + /// Instance of RegisterImplementation to register + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, Type registerImplementation, object instance, string name) + { + return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerImplementation, instance)); + } + + /// + /// Creates/replaces a container class registration with a user specified factory + /// + /// Type to register + /// Factory/lambda that returns an instance of RegisterType + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, Func factory) + { + return RegisterInternal(registerType, string.Empty, new DelegateFactory(registerType, factory)); + } + + /// + /// Creates/replaces a container class registration with a user specified factory + /// + /// Type to register + /// Factory/lambda that returns an instance of RegisterType + /// Name of registation + /// RegisterOptions for fluent API + public RegisterOptions Register(Type registerType, Func factory, string name) + { + return RegisterInternal(registerType, name, new DelegateFactory(registerType, factory)); + } + + /// + /// Creates/replaces a container class registration with default options. + /// + /// Type to register + /// RegisterOptions for fluent API + public RegisterOptions Register() + where RegisterType : class + { + return this.Register(typeof(RegisterType)); + } + + /// + /// Creates/replaces a named container class registration with default options. + /// + /// Type to register + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(string name) + where RegisterType : class + { + return this.Register(typeof(RegisterType), name); + } + + /// + /// Creates/replaces a container class registration with a given implementation and default options. + /// + /// Type to register + /// Type to instantiate that implements RegisterType + /// RegisterOptions for fluent API + public RegisterOptions Register() + where RegisterType : class + where RegisterImplementation : class, RegisterType + { + return this.Register(typeof(RegisterType), typeof(RegisterImplementation)); + } + + /// + /// Creates/replaces a named container class registration with a given implementation and default options. + /// + /// Type to register + /// Type to instantiate that implements RegisterType + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(string name) + where RegisterType : class + where RegisterImplementation : class, RegisterType + { + return this.Register(typeof(RegisterType), typeof(RegisterImplementation), name); + } + + /// + /// Creates/replaces a container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Instance of RegisterType to register + /// RegisterOptions for fluent API + public RegisterOptions Register(RegisterType instance) + where RegisterType : class + { + return this.Register(typeof(RegisterType), instance); + } + + /// + /// Creates/replaces a named container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Instance of RegisterType to register + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(RegisterType instance, string name) + where RegisterType : class + { + return this.Register(typeof(RegisterType), instance, name); + } + + /// + /// Creates/replaces a container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Type of instance to register that implements RegisterType + /// Instance of RegisterImplementation to register + /// RegisterOptions for fluent API + public RegisterOptions Register(RegisterImplementation instance) + where RegisterType : class + where RegisterImplementation : class, RegisterType + { + return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance); + } + + /// + /// Creates/replaces a named container class registration with a specific, strong referenced, instance. + /// + /// Type to register + /// Type of instance to register that implements RegisterType + /// Instance of RegisterImplementation to register + /// Name of registration + /// RegisterOptions for fluent API + public RegisterOptions Register(RegisterImplementation instance, string name) + where RegisterType : class + where RegisterImplementation : class, RegisterType + { + return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance, name); + } + + /// + /// Creates/replaces a container class registration with a user specified factory + /// + /// Type to register + /// Factory/lambda that returns an instance of RegisterType + /// RegisterOptions for fluent API + public RegisterOptions Register(Func factory) + where RegisterType : class + { + if (factory == null) + { + throw new ArgumentNullException("factory"); + } + + return this.Register(typeof(RegisterType), (c, o) => factory(c, o)); + } + + /// + /// Creates/replaces a named container class registration with a user specified factory + /// + /// Type to register + /// Factory/lambda that returns an instance of RegisterType + /// Name of registation + /// RegisterOptions for fluent API + public RegisterOptions Register(Func factory, string name) + where RegisterType : class + { + if (factory == null) + { + throw new ArgumentNullException("factory"); + } + + return this.Register(typeof(RegisterType), (c, o) => factory(c, o), name); + } + + /// + /// Register multiple implementations of a type. + /// + /// Internally this registers each implementation using the full name of the class as its registration name. + /// + /// Type that each implementation implements + /// Types that implement RegisterType + /// MultiRegisterOptions for the fluent API + public MultiRegisterOptions RegisterMultiple(IEnumerable implementationTypes) + { + return RegisterMultiple(typeof(RegisterType), implementationTypes); + } + + /// + /// Register multiple implementations of a type. + /// + /// Internally this registers each implementation using the full name of the class as its registration name. + /// + /// Type that each implementation implements + /// Types that implement RegisterType + /// MultiRegisterOptions for the fluent API + public MultiRegisterOptions RegisterMultiple(Type registrationType, IEnumerable implementationTypes) + { + if (implementationTypes == null) + throw new ArgumentNullException("types", "types is null."); + + foreach (var type in implementationTypes) + //#if NETFX_CORE + // if (!registrationType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) + //#else + if (!registrationType.IsAssignableFrom(type)) + //#endif + throw new ArgumentException(String.Format("types: The type {0} is not assignable from {1}", registrationType.FullName, type.FullName)); + + if (implementationTypes.Count() != implementationTypes.Distinct().Count()) + { + var queryForDuplicatedTypes = from i in implementationTypes + group i by i + into j + where j.Count() > 1 + select j.Key.FullName; + + var fullNamesOfDuplicatedTypes = string.Join(",\n", queryForDuplicatedTypes.ToArray()); + var multipleRegMessage = string.Format("types: The same implementation type cannot be specified multiple times for {0}\n\n{1}", registrationType.FullName, fullNamesOfDuplicatedTypes); + throw new ArgumentException(multipleRegMessage); + } + + var registerOptions = new List(); + + foreach (var type in implementationTypes) + { + registerOptions.Add(Register(registrationType, type, type.FullName)); + } + + return new MultiRegisterOptions(registerOptions); + } + #endregion + + #region Resolution + /// + /// Attempts to resolve a type using default options. + /// + /// Type to resolve + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType) + { + return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default); + } + + /// + /// Attempts to resolve a type using specified options. + /// + /// Type to resolve + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, ResolveOptions options) + { + return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options); + } + + /// + /// Attempts to resolve a type using default options and the supplied name. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// Name of registration + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, string name) + { + return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default); + } + + /// + /// Attempts to resolve a type using supplied options and name. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, string name, ResolveOptions options) + { + return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options); + } + + /// + /// Attempts to resolve a type using default options and the supplied constructor parameters. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// User specified constructor parameters + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, NamedParameterOverloads parameters) + { + return ResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default); + } + + /// + /// Attempts to resolve a type using specified options and the supplied constructor parameters. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// User specified constructor parameters + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options) + { + return ResolveInternal(new TypeRegistration(resolveType), parameters, options); + } + + /// + /// Attempts to resolve a type using default options and the supplied constructor parameters and name. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// User specified constructor parameters + /// Name of registration + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters) + { + return ResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default); + } + + /// + /// Attempts to resolve a named type using specified options and the supplied constructor parameters. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options) + { + return ResolveInternal(new TypeRegistration(resolveType, name), parameters, options); + } + + /// + /// Attempts to resolve a type using default options. + /// + /// Type to resolve + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve() + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType)); + } + + /// + /// Attempts to resolve a type using specified options. + /// + /// Type to resolve + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(ResolveOptions options) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), options); + } + + /// + /// Attempts to resolve a type using default options and the supplied name. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// Name of registration + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(string name) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), name); + } + + /// + /// Attempts to resolve a type using supplied options and name. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(string name, ResolveOptions options) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), name, options); + } + + /// + /// Attempts to resolve a type using default options and the supplied constructor parameters. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// User specified constructor parameters + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(NamedParameterOverloads parameters) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), parameters); + } + + /// + /// Attempts to resolve a type using specified options and the supplied constructor parameters. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// User specified constructor parameters + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(NamedParameterOverloads parameters, ResolveOptions options) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), parameters, options); + } + + /// + /// Attempts to resolve a type using default options and the supplied constructor parameters and name. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// User specified constructor parameters + /// Name of registration + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(string name, NamedParameterOverloads parameters) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), name, parameters); + } + + /// + /// Attempts to resolve a named type using specified options and the supplied constructor parameters. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Instance of type + /// Unable to resolve the type. + public ResolveType Resolve(string name, NamedParameterOverloads parameters, ResolveOptions options) + where ResolveType : class + { + return (ResolveType)Resolve(typeof(ResolveType), name, parameters, options); + } + + /// + /// Attempts to predict whether a given type can be resolved with default options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType) + { + return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default); + } + + /// + /// Attempts to predict whether a given named type can be resolved with default options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Bool indicating whether the type can be resolved + private bool CanResolve(Type resolveType, string name) + { + return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default); + } + + /// + /// Attempts to predict whether a given type can be resolved with the specified options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType, ResolveOptions options) + { + return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options); + } + + /// + /// Attempts to predict whether a given named type can be resolved with the specified options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType, string name, ResolveOptions options) + { + return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options); + } + + /// + /// Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// User supplied named parameter overloads + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType, NamedParameterOverloads parameters) + { + return CanResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default); + } + + /// + /// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// User supplied named parameter overloads + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters) + { + return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default); + } + + /// + /// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// User supplied named parameter overloads + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options) + { + return CanResolveInternal(new TypeRegistration(resolveType), parameters, options); + } + + /// + /// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// User supplied named parameter overloads + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options) + { + return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, options); + } + + /// + /// Attempts to predict whether a given type can be resolved with default options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// Bool indicating whether the type can be resolved + public bool CanResolve() + where ResolveType : class + { + return CanResolve(typeof(ResolveType)); + } + + /// + /// Attempts to predict whether a given named type can be resolved with default options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Bool indicating whether the type can be resolved + public bool CanResolve(string name) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), name); + } + + /// + /// Attempts to predict whether a given type can be resolved with the specified options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(ResolveOptions options) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), options); + } + + /// + /// Attempts to predict whether a given named type can be resolved with the specified options. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(string name, ResolveOptions options) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), name, options); + } + + /// + /// Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// User supplied named parameter overloads + /// Bool indicating whether the type can be resolved + public bool CanResolve(NamedParameterOverloads parameters) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), parameters); + } + + /// + /// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// User supplied named parameter overloads + /// Bool indicating whether the type can be resolved + public bool CanResolve(string name, NamedParameterOverloads parameters) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), name, parameters); + } + + /// + /// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// User supplied named parameter overloads + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(NamedParameterOverloads parameters, ResolveOptions options) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), parameters, options); + } + + /// + /// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options. + /// + /// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists). + /// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail. + /// + /// Note: Resolution may still fail if user defined factory registations fail to construct objects when called. + /// + /// Type to resolve + /// Name of registration + /// User supplied named parameter overloads + /// Resolution options + /// Bool indicating whether the type can be resolved + public bool CanResolve(string name, NamedParameterOverloads parameters, ResolveOptions options) + where ResolveType : class + { + return CanResolve(typeof(ResolveType), name, parameters, options); + } + + /// + /// Attemps to resolve a type using the default options + /// + /// Type to resolve + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the given options + /// + /// Type to resolve + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, ResolveOptions options, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and given name + /// + /// Type to resolve + /// Name of registration + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, string name, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, name); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the given options and name + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, string name, ResolveOptions options, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, name, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and supplied constructor parameters + /// + /// Type to resolve + /// User specified constructor parameters + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, parameters); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and supplied name and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, string name, NamedParameterOverloads parameters, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, name, parameters); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the supplied options and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, parameters, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the supplied name, options and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options, out object resolvedType) + { + try + { + resolvedType = Resolve(resolveType, name, parameters, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = null; + return false; + } + } + + /// + /// Attemps to resolve a type using the default options + /// + /// Type to resolve + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the given options + /// + /// Type to resolve + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and given name + /// + /// Type to resolve + /// Name of registration + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(name); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the given options and name + /// + /// Type to resolve + /// Name of registration + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(name, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and supplied constructor parameters + /// + /// Type to resolve + /// User specified constructor parameters + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(NamedParameterOverloads parameters, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(parameters); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the default options and supplied name and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, NamedParameterOverloads parameters, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(name, parameters); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the supplied options and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(parameters, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Attemps to resolve a type using the supplied name, options and constructor parameters + /// + /// Type to resolve + /// Name of registration + /// User specified constructor parameters + /// Resolution options + /// Resolved type or default if resolve fails + /// True if resolved sucessfully, false otherwise + public bool TryResolve(string name, NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) + where ResolveType : class + { + try + { + resolvedType = Resolve(name, parameters, options); + return true; + } + catch (TinyIoCResolutionException) + { + resolvedType = default(ResolveType); + return false; + } + } + + /// + /// Returns all registrations of a type + /// + /// Type to resolveAll + /// Whether to include un-named (default) registrations + /// IEnumerable + public IEnumerable ResolveAll(Type resolveType, bool includeUnnamed) + { + return ResolveAllInternal(resolveType, includeUnnamed); + } + + /// + /// Returns all registrations of a type, both named and unnamed + /// + /// Type to resolveAll + /// IEnumerable + public IEnumerable ResolveAll(Type resolveType) + { + return ResolveAll(resolveType, false); + } + + /// + /// Returns all registrations of a type + /// + /// Type to resolveAll + /// Whether to include un-named (default) registrations + /// IEnumerable + public IEnumerable ResolveAll(bool includeUnnamed) + where ResolveType : class + { + return this.ResolveAll(typeof(ResolveType), includeUnnamed).Cast(); + } + + /// + /// Returns all registrations of a type, both named and unnamed + /// + /// Type to resolveAll + /// Whether to include un-named (default) registrations + /// IEnumerable + public IEnumerable ResolveAll() + where ResolveType : class + { + return ResolveAll(true); + } + + /// + /// Attempts to resolve all public property dependencies on the given object. + /// + /// Object to "build up" + public void BuildUp(object input) + { + BuildUpInternal(input, ResolveOptions.Default); + } + + /// + /// Attempts to resolve all public property dependencies on the given object using the given resolve options. + /// + /// Object to "build up" + /// Resolve options to use + public void BuildUp(object input, ResolveOptions resolveOptions) + { + BuildUpInternal(input, resolveOptions); + } + #endregion + #endregion + + #region Object Factories + /// + /// Provides custom lifetime management for ASP.Net per-request lifetimes etc. + /// + public interface ITinyIoCObjectLifetimeProvider + { + /// + /// Gets the stored object if it exists, or null if not + /// + /// Object instance or null + object GetObject(); + + /// + /// Store the object + /// + /// Object to store + void SetObject(object value); + + /// + /// Release the object + /// + void ReleaseObject(); + } + + private abstract class ObjectFactoryBase + { + /// + /// Whether to assume this factory sucessfully constructs its objects + /// + /// Generally set to true for delegate style factories as CanResolve cannot delve + /// into the delegates they contain. + /// + public virtual bool AssumeConstruction { get { return false; } } + + /// + /// The type the factory instantiates + /// + public abstract Type CreatesType { get; } + + /// + /// Constructor to use, if specified + /// + public ConstructorInfo Constructor { get; protected set; } + + /// + /// Create the type + /// + /// Type user requested to be resolved + /// Container that requested the creation + /// Any user parameters passed + /// + /// + public abstract object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options); + + public virtual ObjectFactoryBase SingletonVariant + { + get + { + throw new TinyIoCRegistrationException(this.GetType(), "singleton"); + } + } + + public virtual ObjectFactoryBase MultiInstanceVariant + { + get + { + throw new TinyIoCRegistrationException(this.GetType(), "multi-instance"); + } + } + + public virtual ObjectFactoryBase StrongReferenceVariant + { + get + { + throw new TinyIoCRegistrationException(this.GetType(), "strong reference"); + } + } + + public virtual ObjectFactoryBase WeakReferenceVariant + { + get + { + throw new TinyIoCRegistrationException(this.GetType(), "weak reference"); + } + } + + public virtual ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + throw new TinyIoCRegistrationException(this.GetType(), errorString); + } + + public virtual void SetConstructor(ConstructorInfo constructor) + { + Constructor = constructor; + } + + public virtual ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child) + { + return this; + } + } + + /// + /// IObjectFactory that creates new instances of types for each resolution + /// + private class MultiInstanceFactory : ObjectFactoryBase + { + private readonly Type registerType; + private readonly Type registerImplementation; + public override Type CreatesType { get { return this.registerImplementation; } } + + public MultiInstanceFactory(Type registerType, Type registerImplementation) + { + //#if NETFX_CORE + // if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface()) + // throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory"); + //#else + if (registerImplementation.IsAbstract() || registerImplementation.IsInterface()) + throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory"); + //#endif + if (!IsValidAssignment(registerType, registerImplementation)) + throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory"); + + this.registerType = registerType; + this.registerImplementation = registerImplementation; + } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + try + { + return container.ConstructType(requestedType, this.registerImplementation, Constructor, parameters, options); + } + catch (TinyIoCResolutionException ex) + { + throw new TinyIoCResolutionException(this.registerType, ex); + } + } + + public override ObjectFactoryBase SingletonVariant + { + get + { + return new SingletonFactory(this.registerType, this.registerImplementation); + } + } + + public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString); + } + + public override ObjectFactoryBase MultiInstanceVariant + { + get + { + return this; + } + } + } + + /// + /// IObjectFactory that invokes a specified delegate to construct the object + /// + private class DelegateFactory : ObjectFactoryBase + { + private readonly Type registerType; + + private Func _factory; + + public override bool AssumeConstruction { get { return true; } } + + public override Type CreatesType { get { return this.registerType; } } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + try + { + return _factory.Invoke(container, parameters); + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(this.registerType, ex); + } + } + + public DelegateFactory(Type registerType, Func factory) + { + if (factory == null) + throw new ArgumentNullException("factory"); + + _factory = factory; + + this.registerType = registerType; + } + + public override ObjectFactoryBase WeakReferenceVariant + { + get + { + return new WeakDelegateFactory(this.registerType, _factory); + } + } + + public override ObjectFactoryBase StrongReferenceVariant + { + get + { + return this; + } + } + + public override void SetConstructor(ConstructorInfo constructor) + { + throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations"); + } + } + + /// + /// IObjectFactory that invokes a specified delegate to construct the object + /// Holds the delegate using a weak reference + /// + private class WeakDelegateFactory : ObjectFactoryBase + { + private readonly Type registerType; + + private WeakReference _factory; + + public override bool AssumeConstruction { get { return true; } } + + public override Type CreatesType { get { return this.registerType; } } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + var factory = _factory.Target as Func; + + if (factory == null) + throw new TinyIoCWeakReferenceException(this.registerType); + + try + { + return factory.Invoke(container, parameters); + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(this.registerType, ex); + } + } + + public WeakDelegateFactory(Type registerType, Func factory) + { + if (factory == null) + throw new ArgumentNullException("factory"); + + _factory = new WeakReference(factory); + + this.registerType = registerType; + } + + public override ObjectFactoryBase StrongReferenceVariant + { + get + { + var factory = _factory.Target as Func; + + if (factory == null) + throw new TinyIoCWeakReferenceException(this.registerType); + + return new DelegateFactory(this.registerType, factory); + } + } + + public override ObjectFactoryBase WeakReferenceVariant + { + get + { + return this; + } + } + + public override void SetConstructor(ConstructorInfo constructor) + { + throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations"); + } + } + + /// + /// Stores an particular instance to return for a type + /// + private class InstanceFactory : ObjectFactoryBase, IDisposable + { + private readonly Type registerType; + private readonly Type registerImplementation; + private object _instance; + + public override bool AssumeConstruction { get { return true; } } + + public InstanceFactory(Type registerType, Type registerImplementation, object instance) + { + if (!IsValidAssignment(registerType, registerImplementation)) + throw new TinyIoCRegistrationTypeException(registerImplementation, "InstanceFactory"); + + this.registerType = registerType; + this.registerImplementation = registerImplementation; + _instance = instance; + } + + public override Type CreatesType + { + get { return this.registerImplementation; } + } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + return _instance; + } + + public override ObjectFactoryBase MultiInstanceVariant + { + get { return new MultiInstanceFactory(this.registerType, this.registerImplementation); } + } + + public override ObjectFactoryBase WeakReferenceVariant + { + get + { + return new WeakInstanceFactory(this.registerType, this.registerImplementation, this._instance); + } + } + + public override ObjectFactoryBase StrongReferenceVariant + { + get + { + return this; + } + } + + public override void SetConstructor(ConstructorInfo constructor) + { + throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations"); + } + + public void Dispose() + { + var disposable = _instance as IDisposable; + + if (disposable != null) + disposable.Dispose(); + } + } + + /// + /// Stores an particular instance to return for a type + /// + /// Stores the instance with a weak reference + /// + private class WeakInstanceFactory : ObjectFactoryBase, IDisposable + { + private readonly Type registerType; + private readonly Type registerImplementation; + private readonly WeakReference _instance; + + public WeakInstanceFactory(Type registerType, Type registerImplementation, object instance) + { + if (!IsValidAssignment(registerType, registerImplementation)) + throw new TinyIoCRegistrationTypeException(registerImplementation, "WeakInstanceFactory"); + + this.registerType = registerType; + this.registerImplementation = registerImplementation; + _instance = new WeakReference(instance); + } + + public override Type CreatesType + { + get { return this.registerImplementation; } + } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + var instance = _instance.Target; + + if (instance == null) + throw new TinyIoCWeakReferenceException(this.registerType); + + return instance; + } + + public override ObjectFactoryBase MultiInstanceVariant + { + get + { + return new MultiInstanceFactory(this.registerType, this.registerImplementation); + } + } + + public override ObjectFactoryBase WeakReferenceVariant + { + get + { + return this; + } + } + + public override ObjectFactoryBase StrongReferenceVariant + { + get + { + var instance = _instance.Target; + + if (instance == null) + throw new TinyIoCWeakReferenceException(this.registerType); + + return new InstanceFactory(this.registerType, this.registerImplementation, instance); + } + } + + public override void SetConstructor(ConstructorInfo constructor) + { + throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations"); + } + + public void Dispose() + { + var disposable = _instance.Target as IDisposable; + + if (disposable != null) + disposable.Dispose(); + } + } + + /// + /// A factory that lazy instantiates a type and always returns the same instance + /// + private class SingletonFactory : ObjectFactoryBase, IDisposable + { + private readonly Type registerType; + private readonly Type registerImplementation; + private readonly object SingletonLock = new object(); + private object _Current; + + public SingletonFactory(Type registerType, Type registerImplementation) + { + //#if NETFX_CORE + // if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface()) + //#else + if (registerImplementation.IsAbstract() || registerImplementation.IsInterface()) + //#endif + throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory"); + + if (!IsValidAssignment(registerType, registerImplementation)) + throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory"); + + this.registerType = registerType; + this.registerImplementation = registerImplementation; + } + + public override Type CreatesType + { + get { return this.registerImplementation; } + } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + if (parameters.Count != 0) + throw new ArgumentException("Cannot specify parameters for singleton types"); + + lock (SingletonLock) + if (_Current == null) + _Current = container.ConstructType(requestedType, this.registerImplementation, Constructor, options); + + return _Current; + } + + public override ObjectFactoryBase SingletonVariant + { + get + { + return this; + } + } + + public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString); + } + + public override ObjectFactoryBase MultiInstanceVariant + { + get + { + return new MultiInstanceFactory(this.registerType, this.registerImplementation); + } + } + + public override ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child) + { + // We make sure that the singleton is constructed before the child container takes the factory. + // Otherwise the results would vary depending on whether or not the parent container had resolved + // the type before the child container does. + GetObject(type, parent, NamedParameterOverloads.Default, ResolveOptions.Default); + return this; + } + + public void Dispose() + { + if (this._Current == null) + return; + + var disposable = this._Current as IDisposable; + + if (disposable != null) + disposable.Dispose(); + } + } + + /// + /// A factory that offloads lifetime to an external lifetime provider + /// + private class CustomObjectLifetimeFactory : ObjectFactoryBase, IDisposable + { + private readonly object SingletonLock = new object(); + private readonly Type registerType; + private readonly Type registerImplementation; + private readonly ITinyIoCObjectLifetimeProvider _LifetimeProvider; + + public CustomObjectLifetimeFactory(Type registerType, Type registerImplementation, ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorMessage) + { + if (lifetimeProvider == null) + throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null."); + + if (!IsValidAssignment(registerType, registerImplementation)) + throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory"); + + //#if NETFX_CORE + // if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface()) + //#else + if (registerImplementation.IsAbstract() || registerImplementation.IsInterface()) + //#endif + throw new TinyIoCRegistrationTypeException(registerImplementation, errorMessage); + + this.registerType = registerType; + this.registerImplementation = registerImplementation; + _LifetimeProvider = lifetimeProvider; + } + + public override Type CreatesType + { + get { return this.registerImplementation; } + } + + public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) + { + object current; + + lock (SingletonLock) + { + current = _LifetimeProvider.GetObject(); + if (current == null) + { + current = container.ConstructType(requestedType, this.registerImplementation, Constructor, options); + _LifetimeProvider.SetObject(current); + } + } + + return current; + } + + public override ObjectFactoryBase SingletonVariant + { + get + { + _LifetimeProvider.ReleaseObject(); + return new SingletonFactory(this.registerType, this.registerImplementation); + } + } + + public override ObjectFactoryBase MultiInstanceVariant + { + get + { + _LifetimeProvider.ReleaseObject(); + return new MultiInstanceFactory(this.registerType, this.registerImplementation); + } + } + + public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) + { + _LifetimeProvider.ReleaseObject(); + return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString); + } + + public override ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child) + { + // We make sure that the singleton is constructed before the child container takes the factory. + // Otherwise the results would vary depending on whether or not the parent container had resolved + // the type before the child container does. + GetObject(type, parent, NamedParameterOverloads.Default, ResolveOptions.Default); + return this; + } + + public void Dispose() + { + _LifetimeProvider.ReleaseObject(); + } + } + #endregion + + #region Singleton Container + private static readonly TinyIoCContainer _Current = new TinyIoCContainer(); + + static TinyIoCContainer() + { + } + + /// + /// Lazy created Singleton instance of the container for simple scenarios + /// + public static TinyIoCContainer Current + { + get + { + return _Current; + } + } + #endregion + + #region Type Registrations + public sealed class TypeRegistration + { + private int _hashCode; + + public Type Type { get; private set; } + public string Name { get; private set; } + + public TypeRegistration(Type type) + : this(type, string.Empty) + { + } + + public TypeRegistration(Type type, string name) + { + Type = type; + Name = name; + + _hashCode = String.Concat(Type.FullName, "|", Name).GetHashCode(); + } + + public override bool Equals(object obj) + { + var typeRegistration = obj as TypeRegistration; + + if (typeRegistration == null) + return false; + + if (Type != typeRegistration.Type) + return false; + + if (String.Compare(Name, typeRegistration.Name, StringComparison.Ordinal) != 0) + return false; + + return true; + } + + public override int GetHashCode() + { + return _hashCode; + } + } + private readonly SafeDictionary _RegisteredTypes; +#if USE_OBJECT_CONSTRUCTOR + private delegate object ObjectConstructor(params object[] parameters); + private static readonly SafeDictionary _ObjectConstructorCache = new SafeDictionary(); +#endif + #endregion + + #region Constructors + public TinyIoCContainer() + { + _RegisteredTypes = new SafeDictionary(); + + RegisterDefaultTypes(); + } + + TinyIoCContainer _Parent; + private TinyIoCContainer(TinyIoCContainer parent) + : this() + { + _Parent = parent; + } + #endregion + + #region Internal Methods + private readonly object _AutoRegisterLock = new object(); + private void AutoRegisterInternal(IEnumerable assemblies, bool ignoreDuplicateImplementations, Func registrationPredicate) + { + lock (_AutoRegisterLock) + { + var types = assemblies.SelectMany(a => a.SafeGetTypes()).Where(t => !IsIgnoredType(t, registrationPredicate)).ToList(); + + var concreteTypes = from type in types + where type.IsClass() && (type.IsAbstract() == false) && (type != this.GetType() && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition())) + select type; + + foreach (var type in concreteTypes) + { + try + { + RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, type)); + } + catch (MethodAccessException) + { + // Ignore methods we can't access - added for Silverlight + } + } + + var abstractInterfaceTypes = from type in types + where ((type.IsInterface() || type.IsAbstract()) && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition())) + select type; + + foreach (var type in abstractInterfaceTypes) + { + var localType = type; + var implementations = from implementationType in concreteTypes + where localType.IsAssignableFrom(implementationType) + select implementationType; + + if (!ignoreDuplicateImplementations && implementations.Count() > 1) + throw new TinyIoCAutoRegistrationException(type, implementations); + + var firstImplementation = implementations.FirstOrDefault(); + if (firstImplementation != null) + { + try + { + RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, firstImplementation)); + } + catch (MethodAccessException) + { + // Ignore methods we can't access - added for Silverlight + } + } + } + } + } + + private bool IsIgnoredAssembly(Assembly assembly) + { + // TODO - find a better way to remove "system" assemblies from the auto registration + var ignoreChecks = new List>() + { + asm => asm.FullName.StartsWith("Microsoft.", StringComparison.Ordinal), + asm => asm.FullName.StartsWith("System.", StringComparison.Ordinal), + asm => asm.FullName.StartsWith("System,", StringComparison.Ordinal), + asm => asm.FullName.StartsWith("CR_ExtUnitTest", StringComparison.Ordinal), + asm => asm.FullName.StartsWith("mscorlib,", StringComparison.Ordinal), + asm => asm.FullName.StartsWith("CR_VSTest", StringComparison.Ordinal), + asm => asm.FullName.StartsWith("DevExpress.CodeRush", StringComparison.Ordinal), + }; + + foreach (var check in ignoreChecks) + { + if (check(assembly)) + return true; + } + + return false; + } + + private bool IsIgnoredType(Type type, Func registrationPredicate) + { + // TODO - find a better way to remove "system" types from the auto registration + var ignoreChecks = new List>() + { + t => t.FullName.StartsWith("System.", StringComparison.Ordinal), + t => t.FullName.StartsWith("Microsoft.", StringComparison.Ordinal), + t => t.IsPrimitive(), +#if !UNBOUND_GENERICS_GETCONSTRUCTORS + t => t.IsGenericTypeDefinition(), +#endif + t => (t.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Length == 0) && !(t.IsInterface() || t.IsAbstract()), + }; + + if (registrationPredicate != null) + { + ignoreChecks.Add(t => !registrationPredicate(t)); + } + + foreach (var check in ignoreChecks) + { + if (check(type)) + return true; + } + + return false; + } + + private void RegisterDefaultTypes() + { + Register(this); + +#if TINYMESSENGER + // Only register the TinyMessenger singleton if we are the root container + if (_Parent == null) + Register(); +#endif + } + + private ObjectFactoryBase GetCurrentFactory(TypeRegistration registration) + { + ObjectFactoryBase current = null; + + _RegisteredTypes.TryGetValue(registration, out current); + + return current; + } + + private RegisterOptions RegisterInternal(Type registerType, string name, ObjectFactoryBase factory) + { + var typeRegistration = new TypeRegistration(registerType, name); + + return AddUpdateRegistration(typeRegistration, factory); + } + + private RegisterOptions AddUpdateRegistration(TypeRegistration typeRegistration, ObjectFactoryBase factory) + { + _RegisteredTypes[typeRegistration] = factory; + + return new RegisterOptions(this, typeRegistration); + } + + private void RemoveRegistration(TypeRegistration typeRegistration) + { + _RegisteredTypes.Remove(typeRegistration); + } + + private ObjectFactoryBase GetDefaultObjectFactory(Type registerType, Type registerImplementation) + { + //#if NETFX_CORE + // if (registerType.GetTypeInfo().IsInterface() || registerType.GetTypeInfo().IsAbstract()) + //#else + if (registerType.IsInterface() || registerType.IsAbstract()) + //#endif + return new SingletonFactory(registerType, registerImplementation); + + return new MultiInstanceFactory(registerType, registerImplementation); + } + + private bool CanResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + + Type checkType = registration.Type; + string name = registration.Name; + + ObjectFactoryBase factory; + if (_RegisteredTypes.TryGetValue(new TypeRegistration(checkType, name), out factory)) + { + if (factory.AssumeConstruction) + return true; + + if (factory.Constructor == null) + return (GetBestConstructor(factory.CreatesType, parameters, options) != null) ? true : false; + else + return CanConstruct(factory.Constructor, parameters, options); + } + + // Fail if requesting named resolution and settings set to fail if unresolved + // Or bubble up if we have a parent + if (!String.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail) + return (_Parent != null) ? _Parent.CanResolveInternal(registration, parameters, options) : false; + + // Attemped unnamed fallback container resolution if relevant and requested + if (!String.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.AttemptUnnamedResolution) + { + if (_RegisteredTypes.TryGetValue(new TypeRegistration(checkType), out factory)) + { + if (factory.AssumeConstruction) + return true; + + return (GetBestConstructor(factory.CreatesType, parameters, options) != null) ? true : false; + } + } + + // Check if type is an automatic lazy factory request + if (IsAutomaticLazyFactoryRequest(checkType)) + return true; + + // Check if type is an IEnumerable + if (IsIEnumerableRequest(registration.Type)) + return true; + + // Attempt unregistered construction if possible and requested + // If we cant', bubble if we have a parent + if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (checkType.IsGenericType() && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly)) + return (GetBestConstructor(checkType, parameters, options) != null) ? true : (_Parent != null) ? _Parent.CanResolveInternal(registration, parameters, options) : false; + + // Bubble resolution up the container tree if we have a parent + if (_Parent != null) + return _Parent.CanResolveInternal(registration, parameters, options); + + return false; + } + + private bool IsIEnumerableRequest(Type type) + { + if (!type.IsGenericType()) + return false; + + Type genericType = type.GetGenericTypeDefinition(); + + if (genericType == typeof(IEnumerable<>)) + return true; + + return false; + } + + private bool IsAutomaticLazyFactoryRequest(Type type) + { + if (!type.IsGenericType()) + return false; + + Type genericType = type.GetGenericTypeDefinition(); + + // Just a func + if (genericType == typeof(Func<>)) + return true; + + // 2 parameter func with string as first parameter (name) + //#if NETFX_CORE + // if ((genericType == typeof(Func<,>) && type.GetTypeInfo().GenericTypeArguments[0] == typeof(string))) + //#else + if ((genericType == typeof(Func<,>) && type.GetGenericArguments()[0] == typeof(string))) + //#endif + return true; + + // 3 parameter func with string as first parameter (name) and IDictionary as second (parameters) + //#if NETFX_CORE + // if ((genericType == typeof(Func<,,>) && type.GetTypeInfo().GenericTypeArguments[0] == typeof(string) && type.GetTypeInfo().GenericTypeArguments[1] == typeof(IDictionary))) + //#else + if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary))) + //#endif + return true; + + return false; + } + + private ObjectFactoryBase GetParentObjectFactory(TypeRegistration registration) + { + if (_Parent == null) + return null; + + ObjectFactoryBase factory; + if (_Parent._RegisteredTypes.TryGetValue(registration, out factory)) + { + return factory.GetFactoryForChildContainer(registration.Type, _Parent, this); + } + + return _Parent.GetParentObjectFactory(registration); + } + + private object ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options) + { + ObjectFactoryBase factory; + + // Attempt container resolution + if (_RegisteredTypes.TryGetValue(registration, out factory)) + { + try + { + return factory.GetObject(registration.Type, this, parameters, options); + } + catch (TinyIoCResolutionException) + { + throw; + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(registration.Type, ex); + } + } + +#if RESOLVE_OPEN_GENERICS + // Attempt container resolution of open generic + if (registration.Type.IsGenericType()) + { + var openTypeRegistration = new TypeRegistration(registration.Type.GetGenericTypeDefinition(), + registration.Name); + + if (_RegisteredTypes.TryGetValue(openTypeRegistration, out factory)) + { + try + { + return factory.GetObject(registration.Type, this, parameters, options); + } + catch (TinyIoCResolutionException) + { + throw; + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(registration.Type, ex); + } + } + } +#endif + + // Attempt to get a factory from parent if we can + var bubbledObjectFactory = GetParentObjectFactory(registration); + if (bubbledObjectFactory != null) + { + try + { + return bubbledObjectFactory.GetObject(registration.Type, this, parameters, options); + } + catch (TinyIoCResolutionException) + { + throw; + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(registration.Type, ex); + } + } + + // Fail if requesting named resolution and settings set to fail if unresolved + if (!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail) + throw new TinyIoCResolutionException(registration.Type); + + // Attemped unnamed fallback container resolution if relevant and requested + if (!String.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.AttemptUnnamedResolution) + { + if (_RegisteredTypes.TryGetValue(new TypeRegistration(registration.Type, string.Empty), out factory)) + { + try + { + return factory.GetObject(registration.Type, this, parameters, options); + } + catch (TinyIoCResolutionException) + { + throw; + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(registration.Type, ex); + } + } + } + +#if EXPRESSIONS + // Attempt to construct an automatic lazy factory if possible + if (IsAutomaticLazyFactoryRequest(registration.Type)) + return GetLazyAutomaticFactoryRequest(registration.Type); +#endif + if (IsIEnumerableRequest(registration.Type)) + return GetIEnumerableRequest(registration.Type); + + // Attempt unregistered construction if possible and requested + if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (registration.Type.IsGenericType() && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly)) + { + if (!registration.Type.IsAbstract() && !registration.Type.IsInterface()) + return ConstructType(null, registration.Type, parameters, options); + } + + // Unable to resolve - throw + throw new TinyIoCResolutionException(registration.Type); + } + +#if EXPRESSIONS + private object GetLazyAutomaticFactoryRequest(Type type) + { + if (!type.IsGenericType()) + return null; + + Type genericType = type.GetGenericTypeDefinition(); + //#if NETFX_CORE + // Type[] genericArguments = type.GetTypeInfo().GenericTypeArguments.ToArray(); + //#else + Type[] genericArguments = type.GetGenericArguments(); + //#endif + + // Just a func + if (genericType == typeof(Func<>)) + { + Type returnType = genericArguments[0]; + + //#if NETFX_CORE + // MethodInfo resolveMethod = typeof(TinyIoCContainer).GetTypeInfo().GetDeclaredMethods("Resolve").First(mi => !mi.GetParameters().Any()); + //#else + MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { }); + //#endif + resolveMethod = resolveMethod.MakeGenericMethod(returnType); + + var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod); + + var resolveLambda = Expression.Lambda(resolveCall).Compile(); + + return resolveLambda; + } + + // 2 parameter func with string as first parameter (name) + if ((genericType == typeof(Func<,>)) && (genericArguments[0] == typeof(string))) + { + Type returnType = genericArguments[1]; + + //#if NETFX_CORE + // MethodInfo resolveMethod = typeof(TinyIoCContainer).GetTypeInfo().GetDeclaredMethods("Resolve").First(mi => mi.GetParameters().Length == 1 && mi.GetParameters()[0].GetType() == typeof(String)); + //#else + MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { typeof(String) }); + //#endif + resolveMethod = resolveMethod.MakeGenericMethod(returnType); + + ParameterExpression[] resolveParameters = new ParameterExpression[] { Expression.Parameter(typeof(String), "name") }; + var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod, resolveParameters); + + var resolveLambda = Expression.Lambda(resolveCall, resolveParameters).Compile(); + + return resolveLambda; + } + + // 3 parameter func with string as first parameter (name) and IDictionary as second (parameters) + //#if NETFX_CORE + // if ((genericType == typeof(Func<,,>) && type.GenericTypeArguments[0] == typeof(string) && type.GenericTypeArguments[1] == typeof(IDictionary))) + //#else + if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary))) + //#endif + { + Type returnType = genericArguments[2]; + + var name = Expression.Parameter(typeof(string), "name"); + var parameters = Expression.Parameter(typeof(IDictionary), "parameters"); + + //#if NETFX_CORE + // MethodInfo resolveMethod = typeof(TinyIoCContainer).GetTypeInfo().GetDeclaredMethods("Resolve").First(mi => mi.GetParameters().Length == 2 && mi.GetParameters()[0].GetType() == typeof(String) && mi.GetParameters()[1].GetType() == typeof(NamedParameterOverloads)); + //#else + MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { typeof(String), typeof(NamedParameterOverloads) }); + //#endif + resolveMethod = resolveMethod.MakeGenericMethod(returnType); + + var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod, name, Expression.Call(typeof(NamedParameterOverloads), "FromIDictionary", null, parameters)); + + var resolveLambda = Expression.Lambda(resolveCall, name, parameters).Compile(); + + return resolveLambda; + } + + throw new TinyIoCResolutionException(type); + } +#endif + private object GetIEnumerableRequest(Type type) + { + //#if NETFX_CORE + // var genericResolveAllMethod = this.GetType().GetGenericMethod("ResolveAll", type.GenericTypeArguments, new[] { typeof(bool) }); + //#else + var genericResolveAllMethod = this.GetType().GetGenericMethod(BindingFlags.Public | BindingFlags.Instance, "ResolveAll", type.GetGenericArguments(), new[] { typeof(bool) }); + //#endif + + return genericResolveAllMethod.Invoke(this, new object[] { false }); + } + + private bool CanConstruct(ConstructorInfo ctor, NamedParameterOverloads parameters, ResolveOptions options) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + + foreach (var parameter in ctor.GetParameters()) + { + if (string.IsNullOrEmpty(parameter.Name)) + return false; + + var isParameterOverload = parameters.ContainsKey(parameter.Name); + + //#if NETFX_CORE + // if (parameter.ParameterType.GetTypeInfo().IsPrimitive && !isParameterOverload) + //#else + if (parameter.ParameterType.IsPrimitive() && !isParameterOverload) + //#endif + return false; + + if (!isParameterOverload && !CanResolveInternal(new TypeRegistration(parameter.ParameterType), NamedParameterOverloads.Default, options)) + return false; + } + + return true; + } + + private ConstructorInfo GetBestConstructor(Type type, NamedParameterOverloads parameters, ResolveOptions options) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + + //#if NETFX_CORE + // if (type.GetTypeInfo().IsValueType) + //#else + if (type.IsValueType()) + //#endif + return null; + + // Get constructors in reverse order based on the number of parameters + // i.e. be as "greedy" as possible so we satify the most amount of dependencies possible + var ctors = this.GetTypeConstructors(type); + + foreach (var ctor in ctors) + { + if (this.CanConstruct(ctor, parameters, options)) + return ctor; + } + + return null; + } + + private IEnumerable GetTypeConstructors(Type type) + { + //#if NETFX_CORE + // return type.GetTypeInfo().DeclaredConstructors.OrderByDescending(ctor => ctor.GetParameters().Count()); + //#else + return type.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Count()); + //#endif + } + + private object ConstructType(Type requestedType, Type implementationType, ResolveOptions options) + { + return ConstructType(requestedType, implementationType, null, NamedParameterOverloads.Default, options); + } + + private object ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, ResolveOptions options) + { + return ConstructType(requestedType, implementationType, constructor, NamedParameterOverloads.Default, options); + } + + private object ConstructType(Type requestedType, Type implementationType, NamedParameterOverloads parameters, ResolveOptions options) + { + return ConstructType(requestedType, implementationType, null, parameters, options); + } + + private object ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options) + { + var typeToConstruct = implementationType; + +#if RESOLVE_OPEN_GENERICS + if (implementationType.IsGenericTypeDefinition()) + { + if (requestedType == null || !requestedType.IsGenericType() || !requestedType.GetGenericArguments().Any()) + throw new TinyIoCResolutionException(typeToConstruct); + + typeToConstruct = typeToConstruct.MakeGenericType(requestedType.GetGenericArguments()); + } +#endif + if (constructor == null) + { + // Try and get the best constructor that we can construct + // if we can't construct any then get the constructor + // with the least number of parameters so we can throw a meaningful + // resolve exception + constructor = GetBestConstructor(typeToConstruct, parameters, options) ?? GetTypeConstructors(typeToConstruct).LastOrDefault(); + } + + if (constructor == null) + throw new TinyIoCResolutionException(typeToConstruct); + + var ctorParams = constructor.GetParameters(); + object[] args = new object[ctorParams.Count()]; + + for (int parameterIndex = 0; parameterIndex < ctorParams.Count(); parameterIndex++) + { + var currentParam = ctorParams[parameterIndex]; + + try + { + + if (ctorParams[parameterIndex].ParameterType == typeof(Logger)) + { + args[parameterIndex] = LogManager.GetLogger(implementationType.Name); + } + else + { + + + args[parameterIndex] = parameters.ContainsKey(currentParam.Name) ? + parameters[currentParam.Name] : + ResolveInternal( + new TypeRegistration(currentParam.ParameterType), + NamedParameterOverloads.Default, + options); + } + } + catch (TinyIoCResolutionException ex) + { + // If a constructor parameter can't be resolved + // it will throw, so wrap it and throw that this can't + // be resolved. + throw new TinyIoCResolutionException(typeToConstruct, ex); + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(typeToConstruct, ex); + } + } + + try + { +#if USE_OBJECT_CONSTRUCTOR + var constructionDelegate = CreateObjectConstructionDelegateWithCache(constructor); + return constructionDelegate.Invoke(args); +#else + return constructor.Invoke(args); +#endif + } + catch (Exception ex) + { + throw new TinyIoCResolutionException(typeToConstruct, ex); + } + } + +#if USE_OBJECT_CONSTRUCTOR + private static ObjectConstructor CreateObjectConstructionDelegateWithCache(ConstructorInfo constructor) + { + ObjectConstructor objectConstructor; + if (_ObjectConstructorCache.TryGetValue(constructor, out objectConstructor)) + return objectConstructor; + + // We could lock the cache here, but there's no real side + // effect to two threads creating the same ObjectConstructor + // at the same time, compared to the cost of a lock for + // every creation. + var constructorParams = constructor.GetParameters(); + var lambdaParams = Expression.Parameter(typeof(object[]), "parameters"); + var newParams = new Expression[constructorParams.Length]; + + for (int i = 0; i < constructorParams.Length; i++) + { + var paramsParameter = Expression.ArrayIndex(lambdaParams, Expression.Constant(i)); + + newParams[i] = Expression.Convert(paramsParameter, constructorParams[i].ParameterType); + } + + var newExpression = Expression.New(constructor, newParams); + + var constructionLambda = Expression.Lambda(typeof(ObjectConstructor), newExpression, lambdaParams); + + objectConstructor = (ObjectConstructor)constructionLambda.Compile(); + + _ObjectConstructorCache[constructor] = objectConstructor; + return objectConstructor; + } +#endif + + private void BuildUpInternal(object input, ResolveOptions resolveOptions) + { + //#if NETFX_CORE + // var properties = from property in input.GetType().GetTypeInfo().DeclaredProperties + // where (property.GetMethod != null) && (property.SetMethod != null) && !property.PropertyType.GetTypeInfo().IsValueType + // select property; + //#else + var properties = from property in input.GetType().GetProperties() + where (property.GetGetMethod() != null) && (property.GetSetMethod() != null) && !property.PropertyType.IsValueType() + select property; + //#endif + + foreach (var property in properties) + { + if (property.GetValue(input, null) == null) + { + try + { + property.SetValue(input, ResolveInternal(new TypeRegistration(property.PropertyType), NamedParameterOverloads.Default, resolveOptions), null); + } + catch (TinyIoCResolutionException) + { + // Catch any resolution errors and ignore them + } + } + } + } + + private IEnumerable GetParentRegistrationsForType(Type resolveType) + { + if (_Parent == null) + return new TypeRegistration[] { }; + + var registrations = _Parent._RegisteredTypes.Keys.Where(tr => tr.Type == resolveType); + + return registrations.Concat(_Parent.GetParentRegistrationsForType(resolveType)); + } + + private IEnumerable ResolveAllInternal(Type resolveType, bool includeUnnamed) + { + var registrations = _RegisteredTypes.Keys.Where(tr => tr.Type == resolveType).Concat(GetParentRegistrationsForType(resolveType)); + + if (!includeUnnamed) + registrations = registrations.Where(tr => tr.Name != string.Empty); + + return registrations.Select(registration => this.ResolveInternal(registration, NamedParameterOverloads.Default, ResolveOptions.Default)); + } + + private static bool IsValidAssignment(Type registerType, Type registerImplementation) + { + //#if NETFX_CORE + // var registerTypeDef = registerType.GetTypeInfo(); + // var registerImplementationDef = registerImplementation.GetTypeInfo(); + + // if (!registerTypeDef.IsGenericTypeDefinition) + // { + // if (!registerTypeDef.IsAssignableFrom(registerImplementationDef)) + // return false; + // } + // else + // { + // if (registerTypeDef.IsInterface()) + // { + // if (!registerImplementationDef.ImplementedInterfaces.Any(t => t.GetTypeInfo().Name == registerTypeDef.Name)) + // return false; + // } + // else if (registerTypeDef.IsAbstract() && registerImplementationDef.BaseType() != registerType) + // { + // return false; + // } + // } + //#else + if (!registerType.IsGenericTypeDefinition()) + { + if (!registerType.IsAssignableFrom(registerImplementation)) + return false; + } + else + { + if (registerType.IsInterface()) + { + if (!registerImplementation.FindInterfaces((t, o) => t.Name == registerType.Name, null).Any()) + return false; + } + else if (registerType.IsAbstract() && registerImplementation.BaseType() != registerType) + { + return false; + } + } + //#endif + return true; + } + + #endregion + + #region IDisposable Members + bool disposed = false; + public void Dispose() + { + if (!disposed) + { + disposed = true; + + _RegisteredTypes.Dispose(); + + GC.SuppressFinalize(this); + } + } + + #endregion + } +} + +// reverse shim for WinRT SR changes... +#if !NETFX_CORE +namespace System.Reflection +{ + public static class ReverseTypeExtender + { + public static bool IsClass(this Type type) + { + return type.IsClass; + } + + public static bool IsAbstract(this Type type) + { + return type.IsAbstract; + } + + public static bool IsInterface(this Type type) + { + return type.IsInterface; + } + + public static bool IsPrimitive(this Type type) + { + return type.IsPrimitive; + } + + public static bool IsValueType(this Type type) + { + return type.IsValueType; + } + + public static bool IsGenericType(this Type type) + { + return type.IsGenericType; + } + + public static bool IsGenericParameter(this Type type) + { + return type.IsGenericParameter; + } + + public static bool IsGenericTypeDefinition(this Type type) + { + return type.IsGenericTypeDefinition; + } + + public static Type BaseType(this Type type) + { + return type.BaseType; + } + + public static Assembly Assembly(this Type type) + { + return type.Assembly; + } + } +} +#endif \ No newline at end of file diff --git a/NzbDrone.Common/packages.config b/NzbDrone.Common/packages.config index 969cf4904..f118c45c1 100644 --- a/NzbDrone.Common/packages.config +++ b/NzbDrone.Common/packages.config @@ -1,6 +1,5 @@  - diff --git a/NzbDrone.Console/NzbDrone.Console.csproj b/NzbDrone.Console/NzbDrone.Console.csproj index e4149e3a6..a419827e4 100644 --- a/NzbDrone.Console/NzbDrone.Console.csproj +++ b/NzbDrone.Console/NzbDrone.Console.csproj @@ -12,7 +12,8 @@ NzbDrone.Console v4.0 512 - + + false publish\ true diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 413252760..5affffc91 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -56,14 +56,6 @@ OnBuildSuccess - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll - ..\packages\AutoMoq.1.6.1\lib\AutoMoq.dll diff --git a/NzbDrone.Core.Test/packages.config b/NzbDrone.Core.Test/packages.config index 986570dc4..160f6289a 100644 --- a/NzbDrone.Core.Test/packages.config +++ b/NzbDrone.Core.Test/packages.config @@ -1,6 +1,5 @@  - diff --git a/NzbDrone.Core/App.config b/NzbDrone.Core/App.config index 99ddf3e08..e36560333 100644 --- a/NzbDrone.Core/App.config +++ b/NzbDrone.Core/App.config @@ -1,3 +1,3 @@ - + - \ No newline at end of file + diff --git a/NzbDrone.Core/AutofacSignalrDependencyResolver.cs b/NzbDrone.Core/AutofacSignalrDependencyResolver.cs deleted file mode 100644 index 600fe0f4d..000000000 --- a/NzbDrone.Core/AutofacSignalrDependencyResolver.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Autofac; -using Autofac.Builder; -using Autofac.Core; -using SignalR; - -namespace NzbDrone.Core -{ - public class AutofacSignalrDependencyResolver : DefaultDependencyResolver, IDependencyResolver, IRegistrationSource - { - private ILifetimeScope LifetimeScope { get; set; } - - public AutofacSignalrDependencyResolver(ILifetimeScope lifetimeScope) - { - LifetimeScope = lifetimeScope; - var currentRegistrationSource = - LifetimeScope.ComponentRegistry.Sources.FirstOrDefault(s => s.GetType() == GetType()); - if (currentRegistrationSource != null) - { - ((AutofacSignalrDependencyResolver)currentRegistrationSource).LifetimeScope = lifetimeScope; - } - else - { - LifetimeScope.ComponentRegistry.AddRegistrationSource(this); - } - } - - public AutofacSignalrDependencyResolver() - { - } - - public override object GetService(Type serviceType) - { - object result; - - if (LifetimeScope == null) - { - return base.GetService(serviceType); - } - - if (LifetimeScope.TryResolve(serviceType, out result)) - { - return result; - } - - return null; - } - - public override IEnumerable GetServices(Type serviceType) - { - object result; - - if (LifetimeScope == null) - { - return base.GetServices(serviceType); - } - - if (LifetimeScope.TryResolve(typeof(IEnumerable<>).MakeGenericType(serviceType), out result)) - { - return (IEnumerable)result; - } - - return Enumerable.Empty(); - } - - public IEnumerable RegistrationsFor(Service service, Func> registrationAccessor) - { - var typedService = service as TypedService; - if (typedService != null) - { - var instances = base.GetServices(typedService.ServiceType); - - if (instances != null) - { - return instances - .Select(i => RegistrationBuilder.ForDelegate(i.GetType(), (c, p) => i).As(typedService.ServiceType) - .InstancePerLifetimeScope() - .PreserveExistingDefaults() - .CreateRegistration()); - } - } - - return Enumerable.Empty(); - } - - bool IRegistrationSource.IsAdapterForIndividualComponents - { - get { return false; } - } - } -} diff --git a/NzbDrone.Core/ContainerExtensions.cs b/NzbDrone.Core/ContainerExtensions.cs deleted file mode 100644 index f2352ff15..000000000 --- a/NzbDrone.Core/ContainerExtensions.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Data; -using System.IO; -using System.Reflection; -using Autofac; -using NLog; -using NzbDrone.Common; -using NzbDrone.Common.Eventing; -using NzbDrone.Core.Datastore; -using NzbDrone.Core.ExternalNotification; -using NzbDrone.Core.IndexerSearch; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Instrumentation; - -namespace NzbDrone.Core -{ - public static class ContainerExtensions - { - - private static readonly Logger logger = LogManager.GetLogger("ServiceRegistration"); - - public static void RegisterCoreServices(this ContainerBuilder containerBuilder) - { - containerBuilder.RegisterAssembly("NzbDrone.Common"); - containerBuilder.RegisterAssembly("NzbDrone.Core"); - - containerBuilder.InitDatabase(); - - - containerBuilder.RegisterType() - .As().SingleInstance(); - - containerBuilder.RegisterModule(); - } - - - private static void RegisterAssembly(this ContainerBuilder container, string assemblyName) - { - - container.RegisterAssemblyTypes(assemblyName); - - var assembly = Assembly.Load(assemblyName); - - container.RegisterAssemblyTypes(assembly) - .Where(t => t.IsSubclassOf(typeof(IndexerBase))) - .As(); - - container.RegisterAssemblyTypes(assembly) - .Where(t => t.IsSubclassOf(typeof(IndexerSearchBase))) - .As(); - - container.RegisterAssemblyTypes(assembly) - .Where(t => t.IsSubclassOf(typeof(ExternalNotificationBase))) - .As(); - } - - private static void InitDatabase(this ContainerBuilder container) - { - logger.Info("Registering Database..."); - - var environmentProvider = new EnvironmentProvider(); - var appDataPath = environmentProvider.GetAppDataPath(); - if (!Directory.Exists(appDataPath)) Directory.CreateDirectory(appDataPath); - - container.Register(c => c.Resolve().Create(environmentProvider.GetNzbDroneDatabase())).As(); - - container.RegisterGeneric(typeof(BasicRepository<>)).As(typeof(IBasicRepository<>)); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs b/NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs index a3e4afcb6..da2ebdf47 100644 --- a/NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs +++ b/NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs @@ -10,6 +10,8 @@ using NzbDrone.Common; using NzbDrone.Core.Configuration; using NzbDrone.Core.Model; using NzbDrone.Core.Tv; +using RestSharp.Contrib; +using HttpUtility = System.Web.HttpUtility; namespace NzbDrone.Core.Download.Clients.Sabnzbd { diff --git a/NzbDrone.Core/Instrumentation/LogInjectionModule.cs b/NzbDrone.Core/Instrumentation/LogInjectionModule.cs deleted file mode 100644 index e7f2407d4..000000000 --- a/NzbDrone.Core/Instrumentation/LogInjectionModule.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Linq; -using Autofac; -using Autofac.Core; -using NLog; - -namespace NzbDrone.Core.Instrumentation -{ - public class LogInjectionModule : Module - { - protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration) - { - registration.Preparing += OnComponentPreparing; - } - - static void OnComponentPreparing(object sender, PreparingEventArgs e) - { - e.Parameters = e.Parameters.Union(new[] - { - new ResolvedParameter((p, i) => p.ParameterType == typeof(Logger), (p,i)=> GetLogger(p.Member.DeclaringType)) - }); - } - - private static object GetLogger(Type type) - { - return LogManager.GetLogger(type.Name); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index b468df2c3..da63de0f1 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -123,10 +123,6 @@ - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - ..\packages\FluentMigrator.1.0.6.0\lib\40\FluentMigrator.dll @@ -189,7 +185,6 @@ - @@ -249,7 +244,6 @@ - @@ -355,7 +349,6 @@ - diff --git a/NzbDrone.Core/Providers/XbmcProvider.cs b/NzbDrone.Core/Providers/XbmcProvider.cs index 7b12a1086..a3210387d 100644 --- a/NzbDrone.Core/Providers/XbmcProvider.cs +++ b/NzbDrone.Core/Providers/XbmcProvider.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Web.Script.Serialization; using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -67,7 +66,7 @@ namespace NzbDrone.Core.Providers var activePlayers = GetActivePlayersDharma(host, username, password); //If video is currently playing, then skip update - if(activePlayers["video"]) + if (activePlayers["video"]) { Logger.Debug("Video is currently playing, skipping library update"); continue; @@ -87,7 +86,7 @@ namespace NzbDrone.Core.Providers var activePlayers = GetActivePlayersEden(host, username, password); //If video is currently playing, then skip update - if(activePlayers.Any(a => a.Type.Equals("video"))) + if (activePlayers.Any(a => a.Type.Equals("video"))) { Logger.Debug("Video is currently playing, skipping library update"); continue; @@ -201,7 +200,7 @@ namespace NzbDrone.Core.Providers Logger.Trace(" from response"); var result = JsonConvert.DeserializeObject>(response); - if(!result.Result.Equals("OK", StringComparison.InvariantCultureIgnoreCase)) + if (!result.Result.Equals("OK", StringComparison.InvariantCultureIgnoreCase)) return false; } @@ -242,7 +241,7 @@ namespace NzbDrone.Core.Providers Logger.DebugException(ex.Message, ex); return false; } - + return true; } @@ -329,7 +328,7 @@ namespace NzbDrone.Core.Providers if (versionObject.Value.Type == JTokenType.Integer) return new XbmcVersion((int)versionObject.Value); - if(versionObject.Value.Type == JTokenType.Object) + if (versionObject.Value.Type == JTokenType.Object) return JsonConvert.DeserializeObject(versionObject.Value.ToString()); throw new InvalidCastException("Unknown Version structure!: " + versionObject); @@ -430,8 +429,7 @@ namespace NzbDrone.Core.Providers if (response.StartsWith("{\"error\"")) { - var serializer = new JavaScriptSerializer(); - var error = serializer.Deserialize(response); + var error = JsonConvert.DeserializeObject(response); var code = error.Error["code"]; var message = error.Error["message"]; diff --git a/NzbDrone.Core/packages.config b/NzbDrone.Core/packages.config index 24ef6e878..82a96136e 100644 --- a/NzbDrone.Core/packages.config +++ b/NzbDrone.Core/packages.config @@ -1,6 +1,5 @@  - diff --git a/NzbDrone.Update/NzbDrone.Update.csproj b/NzbDrone.Update/NzbDrone.Update.csproj index f3364c341..c75585887 100644 --- a/NzbDrone.Update/NzbDrone.Update.csproj +++ b/NzbDrone.Update/NzbDrone.Update.csproj @@ -59,6 +59,9 @@ False ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll + + ..\packages\Autofac.3.0.1\lib\net40\Autofac.Configuration.dll + False ..\packages\Exceptron.Client.1.0.20\lib\net20\Exceptron.Client.dll diff --git a/NzbDrone/AppMain.cs b/NzbDrone/AppMain.cs index 50cf33f21..0b8c1c4f4 100644 --- a/NzbDrone/AppMain.cs +++ b/NzbDrone/AppMain.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.Reflection; -using Autofac; using NLog; namespace NzbDrone @@ -42,8 +41,7 @@ namespace NzbDrone return; } - - NzbDroneBootstrapper.Container.Resolve().Route(args); + ContainerBuilder.Instance.Resolve().Route(args); } catch (Exception e) { diff --git a/NzbDrone/ApplicationServer.cs b/NzbDrone/ApplicationServer.cs index 4af1cd262..4444e85bb 100644 --- a/NzbDrone/ApplicationServer.cs +++ b/NzbDrone/ApplicationServer.cs @@ -30,11 +30,6 @@ namespace NzbDrone _securityProvider = securityProvider; } - public ApplicationServer() - { - - } - protected override void OnStart(string[] args) { Start(); diff --git a/NzbDrone/CommonContainerExtentions.cs b/NzbDrone/CommonContainerExtentions.cs new file mode 100644 index 000000000..40fd40c26 --- /dev/null +++ b/NzbDrone/CommonContainerExtentions.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using FluentMigrator.Runner; +using NLog; +using Nancy.Bootstrapper; +using NzbDrone.Api; +using NzbDrone.Common; +using NzbDrone.Common.Eventing; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore.Migration.Framework; +using NzbDrone.Core.ExternalNotification; +using NzbDrone.Core.IndexerSearch; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.RootFolders; +using TinyIoC; + +namespace NzbDrone +{ + public static class ContainerBuilder + { + private static readonly Logger logger = LogManager.GetLogger("ContainerBuilder"); + + public static TinyIoCContainer Instance { get; private set; } + + static ContainerBuilder() + { + var container = new TinyIoCContainer(); + + container.AutoRegisterInterfaces("NzbDrone"); + container.AutoRegisterInterfaces("NzbDrone.Common"); + container.AutoRegisterInterfaces("NzbDrone.Core"); + container.AutoRegisterInterfaces("NzbDrone.Api"); + + container.AutoRegisterImplementations(); + container.AutoRegisterImplementations(); + container.AutoRegisterImplementations(); + + container.Register().AsSingleton(); + container.Register().AsSingleton(); + container.Register().AsSingleton(); + + container.Register(typeof(IBasicRepository), typeof(BasicRepository)).AsMultiInstance(); + + container.InitDatabase(); + + Instance = container; + } + + private static void InitDatabase(this TinyIoCContainer container) + { + logger.Info("Registering Database..."); + + //TODO: move this to factory + var environmentProvider = new EnvironmentProvider(); + var appDataPath = environmentProvider.GetAppDataPath(); + if (!Directory.Exists(appDataPath)) Directory.CreateDirectory(appDataPath); + + container.Register( + delegate(TinyIoCContainer c, NamedParameterOverloads p) + { + return c.Resolve().Create(environmentProvider.GetNzbDroneDatabase()); + }); + } + + private static void AutoRegisterInterfaces(this TinyIoCContainer container, string assemblyName) + { + var assembly = Assembly.Load(assemblyName); + + if (assembly == null) + { + throw new ApplicationException("Couldn't load assembly " + assemblyName); + } + + var interfaces = assembly.GetInterfaces().Where(c => !c.FullName.StartsWith("Nancy.")); + + foreach (var contract in interfaces) + { + container.AutoRegisterImplementations(contract); + } + } + + private static void AutoRegisterImplementations(this TinyIoCContainer container) + { + container.AutoRegisterImplementations(typeof(TContract)); + } + + private static void AutoRegisterImplementations(this TinyIoCContainer container, Type contractType) + { + var implementations = contractType.Assembly.GetImplementations(contractType); + + foreach (var implementation in implementations) + { + logger.Trace("Registering {0} as {1}", implementation.Name, contractType.Name); + container.Register(contractType, implementation).AsMultiInstance(); + } + } + } +} \ No newline at end of file diff --git a/NzbDrone/NzbDrone.csproj b/NzbDrone/NzbDrone.csproj index ba62bd856..2631d3d1b 100644 --- a/NzbDrone/NzbDrone.csproj +++ b/NzbDrone/NzbDrone.csproj @@ -12,7 +12,8 @@ NzbDrone v4.0 512 - + + false publish\ true @@ -82,22 +83,22 @@ MinimumRecommendedRules.ruleset - - False - ..\packages\Autofac.3.0.1\lib\net40\Autofac.dll - ..\packages\Exceptron.Client.1.0.20\lib\net20\Exceptron.Client.dll ..\packages\Exceptron.Nlog.1.0.11\lib\net20\Exceptron.NLog.dll - - ..\packages\Nancy.0.16.1\lib\net40\Nancy.dll + + False + ..\packages\FluentMigrator.1.0.6.0\lib\40\FluentMigrator.dll - + False - ..\packages\Nancy.Bootstrappers.Autofac.0.16.1\lib\net40\Nancy.Bootstrappers.Autofac.dll + ..\packages\FluentMigrator.1.0.6.0\tools\FluentMigrator.Runner.dll + + + ..\packages\Nancy.0.16.1\lib\net40\Nancy.dll ..\packages\Nancy.Hosting.Self.0.16.1\lib\net40\Nancy.Hosting.Self.dll @@ -116,6 +117,7 @@ Component + diff --git a/NzbDrone/NzbDroneBootstrapper.cs b/NzbDrone/NzbDroneBootstrapper.cs index eb7ea249d..2b1cd20fe 100644 --- a/NzbDrone/NzbDroneBootstrapper.cs +++ b/NzbDrone/NzbDroneBootstrapper.cs @@ -1,47 +1,26 @@ -using System.Reflection; -using Autofac; -using NLog; -using NzbDrone.Api; +using NLog; using NzbDrone.Common; -using NzbDrone.Core.Instrumentation; +using TinyIoC; +using NzbDrone.Core; +using NzbDrone.Api; namespace NzbDrone { public static class NzbDroneBootstrapper { - private static readonly IContainer container; private static readonly Logger logger = LogManager.GetLogger("NzbDroneBootstrapper"); static NzbDroneBootstrapper() { - var builder = new ContainerBuilder(); - BindKernel(builder); - container = builder.Build(); InitializeApp(); } - public static IContainer Container - { - get - { - return container; - } - } - - private static void BindKernel(ContainerBuilder builder) - { - builder.RegisterModule(); - - builder.RegisterCommonServices(); - builder.RegisterApiServices(); - builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()); - } private static void InitializeApp() { - var environmentProvider = container.Resolve(); + var environmentProvider = ContainerBuilder.Instance.Resolve(); - ReportingService.RestProvider = container.Resolve(); + ReportingService.RestProvider = ContainerBuilder.Instance.Resolve(); logger.Info("Start-up Path:'{0}'", environmentProvider.WorkingDirectory); } diff --git a/NzbDrone/app.config b/NzbDrone/app.config index ca2c718c2..b3cead478 100644 --- a/NzbDrone/app.config +++ b/NzbDrone/app.config @@ -1,7 +1,7 @@  - + diff --git a/NzbDrone/packages.config b/NzbDrone/packages.config index bcfe36c81..d3cc7709c 100644 --- a/NzbDrone/packages.config +++ b/NzbDrone/packages.config @@ -1,10 +1,9 @@  - + -