using TinyIoC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Nancy;
using Nancy.Diagnostics;
using Nancy.Bootstrapper;
namespace NzbDrone.Api
{
///
/// 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
{
get { return 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();
}
///
/// 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.");
break;
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.");
break;
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);
}
}
}