using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Nancy; using Nancy.Bootstrapper; using Nancy.Configuration; using Nancy.Diagnostics; using TinyIoC; #pragma warning disable SX1101 namespace Radarr.Http { /// /// TinyIoC bootstrapper - registers default route resolver and registers itself as /// INancyModuleCatalog for resolving modules but behaviour can be overridden if required. /// public class TinyIoCNancyBootstrapper : NancyBootstrapperWithRequestContainerBase { /// /// Default assemblies that are ignored for autoregister /// public static IEnumerable> DefaultAutoRegisterIgnoredAssemblies = new Func[] { asm => !asm.FullName.StartsWith("Nancy.", StringComparison.InvariantCulture) }; /// /// Gets the assemblies to ignore when autoregistering the application container /// Return true from the delegate to ignore that particular assembly, returning false /// does not mean the assembly *will* be included, a true from another delegate will /// take precedence. /// protected virtual IEnumerable> AutoRegisterIgnoredAssemblies => DefaultAutoRegisterIgnoredAssemblies; /// /// Configures the container using AutoRegister followed by registration /// of default INancyModuleCatalog and IRouteResolver. /// /// Container instance protected override void ConfigureApplicationContainer(TinyIoCContainer container) { AutoRegister(container, this.AutoRegisterIgnoredAssemblies); } /// /// Resolve INancyEngine /// /// INancyEngine implementation protected override sealed INancyEngine GetEngineInternal() { return this.ApplicationContainer.Resolve(); } /// /// Gets the Nancy.Configuration.INancyEnvironmentConfigurator used by th. /// /// An Nancy.Configuration.INancyEnvironmentConfigurator instance. protected override INancyEnvironmentConfigurator GetEnvironmentConfigurator() { return this.ApplicationContainer.Resolve(); } /// /// Get the Nancy.Configuration.INancyEnvironment instance. /// /// An configured Nancy.Configuration.INancyEnvironment instance. /// /// The boostrapper must be initialised (Nancy.Bootstrapper.INancyBootstrapper.Initialise) prior to calling this. /// public override INancyEnvironment GetEnvironment() { return this.ApplicationContainer.Resolve(); } /// /// Registers an Nancy.Configuration.INancyEnvironment instance in the container. /// /// The container to register into. /// The Nancy.Configuration.INancyEnvironment instance to register. protected override void RegisterNancyEnvironment(TinyIoCContainer container, INancyEnvironment environment) { ApplicationContainer.Register(environment); } /// /// 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) { switch (typeRegistration.Lifetime) { case Lifetime.Transient: container.Register(typeRegistration.RegistrationType, typeRegistration.ImplementationType).AsMultiInstance(); break; case Lifetime.Singleton: container.Register(typeRegistration.RegistrationType, typeRegistration.ImplementationType).AsSingleton(); break; case Lifetime.PerRequest: throw new InvalidOperationException("Unable to directly register a per request lifetime."); default: throw new ArgumentOutOfRangeException(); } } } /// /// 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 collectionTypeRegistrations) { foreach (var collectionTypeRegistration in collectionTypeRegistrations) { switch (collectionTypeRegistration.Lifetime) { case Lifetime.Transient: container.RegisterMultiple(collectionTypeRegistration.RegistrationType, collectionTypeRegistration.ImplementationTypes).AsMultiInstance(); break; case Lifetime.Singleton: container.RegisterMultiple(collectionTypeRegistration.RegistrationType, collectionTypeRegistration.ImplementationTypes).AsSingleton(); break; case Lifetime.PerRequest: throw new InvalidOperationException("Unable to directly register a per request lifetime."); default: throw new ArgumentOutOfRangeException(); } } } /// /// 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.ModuleType.FullName). 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 /// /// Current context /// Request container instance protected override TinyIoCContainer CreateRequestContainer(NancyContext context) { return this.ApplicationContainer.GetChildContainer(); } /// /// Gets the diagnostics for initialisation /// /// IDiagnostics 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 request startup tasks /// /// An instance containing instances. protected override IEnumerable RegisterAndGetRequestStartupTasks(TinyIoCContainer container, Type[] requestStartupTypes) { container.RegisterMultiple(typeof(IRequestStartup), requestStartupTypes); return container.ResolveAll(false); } /// /// Gets all registered application registration tasks /// /// An instance containing instances. protected override IEnumerable GetRegistrationTasks() { 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; } /// /// Retrieve a specific module instance from the container /// /// Container to use /// Type of the module /// NancyModule instance protected override sealed INancyModule GetModule(TinyIoCContainer container, Type moduleType) { container.Register(typeof(INancyModule), moduleType); return container.Resolve(); } /// /// Executes auto registation with the given container. /// /// Container instance private static void AutoRegister(TinyIoCContainer container, IEnumerable> ignoredAssemblies) { var assembly = typeof(NancyEngine).Assembly; container.AutoRegister(AppDomain.CurrentDomain.GetAssemblies().Where(a => !ignoredAssemblies.Any(ia => ia(a))), DuplicateImplementationActions.RegisterMultiple, t => t.Assembly != assembly); } } }