Skip to content

Instantly share code, notes, and snippets.

@grumpydev
Created January 17, 2011 12:50
Show Gist options
  • Save grumpydev/782816 to your computer and use it in GitHub Desktop.
Save grumpydev/782816 to your computer and use it in GitHub Desktop.
Default types are now protected fields which, when the bootstrapper GetEngine is called, are turned into TRegisterType, TImplementation type combos which are then passed into the bootstrapper for the container to register. Changing a default implementatio
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TinyIoC;
using Nancy.BootStrapper;
using Nancy.Routing;
namespace Nancy
{
/// <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 override INancyEngine GetEngineInternal()
{
return _Container.Resolve<INancyEngine>();
}
/// <summary>
/// Get the moduleKey generator
/// </summary>
/// <returns>IModuleKeyGenerator instance</returns>
protected sealed override IModuleKeyGenerator GetModuleKeyGenerator()
{
return _Container.Resolve<IModuleKeyGenerator>();
}
/// <summary>
/// Configures the container using AutoRegister followed by registration
/// of default INancyModuleCatalog and IRouteResolver.
/// </summary>
/// <param name="container"></param>
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.AutoRegister();
}
public virtual void ConfigureRequestContainer(TinyIoCContainer container)
{
}
/// <summary>
/// Creates a new container instance
/// </summary>
/// <returns>New container</returns>
protected override TinyIoCContainer CreateContainer()
{
_Container = new TinyIoCContainer();
return _Container;
}
/// <summary>
/// Registers all modules in the container as multi-instance
/// </summary>
/// <param name="moduleRegistrations">NancyModule registration types</param>
protected override void RegisterModules(IEnumerable<ModuleRegistration> moduleRegistrations)
{
foreach (var registrationType in moduleRegistrations)
{
_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 override void RegisterDefaults(TinyIoCContainer container, IEnumerable<TypeRegistration> typeRegistrations)
{
container.Register<INancyModuleCatalog>(this);
foreach (var typeRegistration in typeRegistrations)
{
container.Register(typeRegistration.RegistrationType, typeRegistration.ImplementationType).AsSingleton();
}
}
/// <summary>
/// Get all NancyModule implementation instances
/// </summary>
/// <returns>IEnumerable of NancyModule</returns>
public IEnumerable<NancyModule> GetAllModules()
{
var childContainer = _Container.GetChildContainer();
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 = _Container.GetChildContainer();
ConfigureRequestContainer(childContainer);
return childContainer.Resolve<NancyModule>(moduleKey);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nancy.Routing;
using System.Threading;
namespace Nancy.BootStrapper
{
/// <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(string moduleKey)"/> are per-request scoped.
/// </summary>
/// <typeparam name="TContainer">Container tyope</typeparam>
public abstract class NancyBootStrapperBase<TContainer> : INancyBootStrapper
where TContainer: class
{
// Defaults
protected Type DefaultRouteResolver = typeof(DefaultRouteResolver);
protected Type DefaultTemplateEngineSelector = typeof(DefaultTemplateEngineSelector);
protected Type DefaultNancyEngine = typeof(NancyEngine);
protected Type DefaultModuleKeyGenerator = typeof(DefaultModuleKeyGenerator);
protected Type DefaultRouteCache = typeof(DefaultRouteCache);
protected Type DefaultRouteCacheProvider = typeof(DefaultRouteCacheProvider);
/// Gets the configured INancyEngine
/// </summary>
/// <returns>Configured INancyEngine</returns>
public INancyEngine GetEngine()
{
var container = CreateContainer();
RegisterDefaults(container, BuildDefaults());
RegisterModules(GetModuleTypes(GetModuleKeyGenerator()));
ConfigureApplicationContainer(container);
return GetEngineInternal();
}
private IEnumerable<TypeRegistration> BuildDefaults()
{
return new TypeRegistration[]
{
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),
};
}
/// <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.IsDynamic
from type in assembly.GetExportedTypes()
where !type.IsAbstract
where moduleType.IsAssignableFrom(type)
select new ModuleRegistration(type, moduleKeyGenerator.GetKeyForModuleType(type));
return locatedModuleTypes;
}
/// <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="moduleTypes">NancyModule types</param>
protected abstract void RegisterModules(IEnumerable<ModuleRegistration> moduleRegistrationTypes);
}
}
using System;
namespace Nancy.BootStrapper
{
/// <summary>
/// Represents a type to be registered into the container
/// </summary>
public sealed class TypeRegistration
{
/// <summary>
/// Registration type i.e. IMyInterface
/// </summary>
public Type RegistrationType { get; private set; }
/// <summary>
/// Implementation type i.e. MyClassThatImplementsIMyInterface
/// </summary>
public Type ImplementationType { get; private set; }
/// <summary>
/// Represents a type to be registered into the container
/// </summary>
/// <param name="registrationType">Registration type i.e. IMyInterface</param>
/// <param name="implementationType">Implementation type i.e. MyClassThatImplementsIMyInterface</param>
public TypeRegistration(Type registrationType, Type implementationType)
{
RegistrationType = registrationType;
ImplementationType = implementationType;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment