Skip to content

Instantly share code, notes, and snippets.

@thecodejunkie
Created February 14, 2011 12:51
Show Gist options
  • Save thecodejunkie/825827 to your computer and use it in GitHub Desktop.
Save thecodejunkie/825827 to your computer and use it in GitHub Desktop.
namespace Nancy
{
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy.ViewEngines;
using TinyIoC;
using Nancy.Bootstrapper;
/// <summary>
/// TinyIoC bootstrapper - registers default route resolver and registers itself as
/// INancyModuleCatalog for resolving modules but behaviour can be overridden if required.
/// </summary>
public class DefaultNancyBootstrapper : NancyBootstrapperBase<TinyIoCContainer>, INancyBootstrapperPerRequestRegistration<TinyIoCContainer>, INancyModuleCatalog
{
/// <summary>
/// Container instance
/// </summary>
protected TinyIoCContainer container;
/// <summary>
/// Resolve INancyEngine
/// </summary>
/// <returns>INancyEngine implementation</returns>
protected sealed override INancyEngine GetEngineInternal()
{
return this.container.Resolve<INancyEngine>();
}
/// <summary>
/// Get the moduleKey generator
/// </summary>
/// <returns>IModuleKeyGenerator instance</returns>
protected sealed override IModuleKeyGenerator GetModuleKeyGenerator()
{
return this.container.Resolve<IModuleKeyGenerator>();
}
/// <summary>
/// Configures the container using AutoRegister followed by registration
/// of default INancyModuleCatalog and IRouteResolver.
/// </summary>
/// <param name="existingContainer"></param>
protected override void ConfigureApplicationContainer(TinyIoCContainer existingContainer)
{
base.ConfigureApplicationContainer(existingContainer);
existingContainer.AutoRegister();
}
public virtual void ConfigureRequestContainer(TinyIoCContainer existingContainer)
{
}
protected override void RegisterViewEngines(TinyIoCContainer container, IEnumerable<Type> viewEngineTypes)
{
this.container.Register(typeof(IViewEngine), viewEngineTypes.First()).AsSingleton();
this.container.RegisterMultiple<IViewEngine>(viewEngineTypes).AsSingleton();
var test = container.ResolveAll<IViewEngine>();
var i = 10;
}
/// <summary>
/// Creates a new container instance
/// </summary>
/// <returns>New container</returns>
protected sealed override TinyIoCContainer CreateContainer()
{
this.container = new TinyIoCContainer();
return this.container;
}
/// <summary>
/// Registers all modules in the container as multi-instance
/// </summary>
/// <param name="moduleRegistrations">NancyModule registration types</param>
protected sealed override void RegisterModules(IEnumerable<ModuleRegistration> moduleRegistrations)
{
foreach (var registrationType in moduleRegistrations)
{
this.container.Register(typeof(NancyModule), registrationType.ModuleType, registrationType.ModuleKey).AsMultiInstance();
}
}
/// <summary>
/// Register the default implementations of internally used types into the container as singletons
/// </summary>
protected sealed override void RegisterDefaults(TinyIoCContainer existingContainer, IEnumerable<TypeRegistration> typeRegistrations)
{
existingContainer.Register<INancyModuleCatalog>(this);
foreach (var typeRegistration in typeRegistrations)
{
existingContainer.Register(typeRegistration.RegistrationType, typeRegistration.ImplementationType).AsSingleton();
}
}
/// <summary>
/// Get all NancyModule implementation instances
/// </summary>
/// <returns>IEnumerable of NancyModule</returns>
public IEnumerable<NancyModule> GetAllModules()
{
var childContainer = this.container.GetChildContainer();
this.ConfigureRequestContainer(childContainer);
return childContainer.ResolveAll<NancyModule>(false);
}
/// <summary>
/// Gets a specific, per-request, module instance from the key
/// </summary>
/// <param name="moduleKey">ModuleKey</param>
/// <returns>NancyModule instance</returns>
public NancyModule GetModuleByKey(string moduleKey)
{
var childContainer = this.container.GetChildContainer();
this.ConfigureRequestContainer(childContainer);
return childContainer.Resolve<NancyModule>(moduleKey);
}
}
}
namespace Nancy.Bootstrapper
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Nancy.Diagnostics;
using Nancy.Routing;
using Nancy.Extensions;
using ViewEngines;
/// <summary>
/// Base class for container based Bootstrappers.
///
/// There are two component lifecycles, an application level one which is guaranteed to be generated at least once (on app startup)
/// and a request level one which should be guaranteed to be generated per-request. Depending on implementation details the application
/// lifecycle components may also be generated per request (without any critical issues), but this isn't ideal.
///
/// Doesn't have to be used (only INancyBootstrapper is required), but does provide a nice consistent base if possible.
///
/// The methods in the base class are all Application level are called as follows:
///
/// CreateContainer() - for creating an empty container
/// GetModuleTypes() - getting the module types in the application, default implementation grabs from the appdomain
/// RegisterModules() - register the modules into the container
/// ConfigureApplicationContainer() - register any application lifecycle dependencies
/// GetEngineInternal() - construct the container (if required) and resolve INancyEngine
///
/// Request level implementations may use <see cref="INancyBootstrapperPerRequestRegistration{TContainer}"/>, or implement custom
/// lifetime logic. It is preferred that users have the ability to register per-request scoped dependencies, and that instances retrieved
/// via <see cref="INancyModuleCatalog.GetModuleByKey"/> are per-request scoped.
/// </summary>
/// <typeparam name="TContainer">Container tyope</typeparam>
public abstract class NancyBootstrapperBase<TContainer> : INancyBootstrapper
where TContainer : class
{
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultRouteResolver { get { return typeof(DefaultRouteResolver); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultRoutePatternMatcher { get { return typeof (DefaultRoutePatternMatcher); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultTemplateEngineSelector { get { return typeof(DefaultTemplateEngineSelector); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultNancyEngine { get { return typeof(NancyEngine); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultModuleKeyGenerator { get { return typeof(DefaultModuleKeyGenerator); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultRouteCache { get { return typeof(DefaultRouteCache); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultRouteCacheProvider { get { return typeof(DefaultRouteCacheProvider); } }
/// <summary>
/// Type passed into RegisterDefaults - override this to switch out default implementations
/// </summary>
protected virtual Type DefaultViewLocator { get { return typeof (AspNetTemplateLocator); } }
/// <summary>
/// Gets the configured INancyEngine
/// </summary>
/// <returns>Configured INancyEngine</returns>
public INancyEngine GetEngine()
{
var container = CreateContainer();
ConfigureApplicationContainer(container);
RegisterDefaults(container, BuildDefaults());
RegisterModules(GetModuleTypes(GetModuleKeyGenerator()));
RegisterViewEngines(container, GetViewEngineTypes());
return GetEngineInternal();
}
private IEnumerable<TypeRegistration> BuildDefaults()
{
return new[]
{
new TypeRegistration(typeof(IRouteResolver), DefaultRouteResolver),
new TypeRegistration(typeof(ITemplateEngineSelector), DefaultTemplateEngineSelector),
new TypeRegistration(typeof(INancyEngine), DefaultNancyEngine),
new TypeRegistration(typeof(IModuleKeyGenerator), DefaultModuleKeyGenerator),
new TypeRegistration(typeof(IRouteCache), DefaultRouteCache),
new TypeRegistration(typeof(IRouteCacheProvider), DefaultRouteCacheProvider),
new TypeRegistration(typeof(IRoutePatternMatcher), DefaultRoutePatternMatcher),
new TypeRegistration(typeof(IViewLocator), DefaultViewLocator),
};
}
/// <summary>
/// Resolve INancyEngine
/// </summary>
/// <returns>INancyEngine implementation</returns>
protected abstract INancyEngine GetEngineInternal();
/// <summary>
/// Get the moduleKey generator
/// </summary>
/// <returns>IModuleKeyGenerator instance</returns>
protected abstract IModuleKeyGenerator GetModuleKeyGenerator();
/// <summary>
/// Returns available NancyModule types
/// </summary>
/// <returns>IEnumerable containing all NancyModule Type definitions</returns>
protected virtual IEnumerable<ModuleRegistration> GetModuleTypes(IModuleKeyGenerator moduleKeyGenerator)
{
var moduleType = typeof(NancyModule);
var locatedModuleTypes =
from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !assembly.ReflectionOnly
where !assembly.IsDynamic
from type in assembly.SafeGetExportedTypes()
where !type.IsAbstract
where moduleType.IsAssignableFrom(type)
select new ModuleRegistration(type, moduleKeyGenerator.GetKeyForModuleType(type));
return locatedModuleTypes;
}
protected virtual IEnumerable<Type> GetViewEngineTypes()
{
var viewEngineTypes =
from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !assembly.ReflectionOnly
where !assembly.IsDynamic
from type in assembly.SafeGetExportedTypes()
where !type.IsAbstract
where typeof(IViewEngine).IsAssignableFrom(type)
select type;
return viewEngineTypes;
}
protected abstract void RegisterViewEngines(TContainer container, IEnumerable<Type> viewEngineTypes);
/// <summary>
/// Create a default, unconfigured, container
/// </summary>
/// <returns>Container</returns>
protected abstract TContainer CreateContainer();
/// <summary>
/// Register the default implementations of internally used types into the container as singletons
/// </summary>
/// <param name="container">Container</param>
/// <param name="typeRegistrations">Type registrations to register</param>
protected abstract void RegisterDefaults(TContainer container, IEnumerable<TypeRegistration> typeRegistrations);
/// <summary>
/// Configure the container (register types) for the application level
/// <seealso cref="ConfigureRequestContainer"/>
/// </summary>
/// <param name="container">Container instance</param>
protected virtual void ConfigureApplicationContainer(TContainer container)
{
}
/// <summary>
/// Register the given module types into the container
/// </summary>
/// <param name="moduleRegistrationTypes">NancyModule types</param>
protected abstract void RegisterModules(IEnumerable<ModuleRegistration> moduleRegistrationTypes);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment