A simple library to load and execute bootstrapper classes in referenced dlls by convention
My article on CodeProject on design and implementation of this library: https://www.codeproject.com/Articles/1162975/Bootstrapper-Loader-for-Layered-Architecture
Install-Package Sharpenter.BootstrapperLoader
This library should be configured and called during the application starts up.
Let's assume following solution structure in a typical ASP.NET/Core layered architecture:
MyCoolProject.UI
- Startup.cs
MyCoolProject.Model
- ISomeRepository
- Other model classes
MyCoolProject.Repository
- SomeRepository: implementation of ISomeRepository
- EF/NHibernate mapping to database
Ideally UI
project should have reference to only Model
project, but not Repository
project, and the dependency direction will be:
UI
-> Model
<- Repository
But if your project is using IoC container, the UI
project will either need to reference Repository
project to register dependencies to IoC container, or UI
project will need to reference another Bootstrapper
project which knows about all projects in the solution.
To solve this dependency issue, the library provides a BootstrapperLoader
that can load Bootstrapper
classes in dlls based on convention.
To get started, let's add a Bootstrapper
class to MyCoolProject.Repository
that does registration to IoC container by itself (in this case it's Autofac
):
public class Bootstrapper
{
public void ConfigureContainer(IContainerBuilder builder)
{
builder.RegisterType<SomeRepository>().As<ISomeRepository>();
}
//Configure can have any number of dependencies injected, as long as those dependencies are already registered with IoC container
public void Configure(ISomeDependency dependency)
{
//Any initialization
}
}
In Startup.cs
in MyCoolProject.UI
:
public class Startup
{
private BootstrapperLoader _bootstrapperLoader;
public Startup(IHostingEnvironment env)
{
//...
_bootstrapperLoader = new LoaderBuilder()
.Use(new FileSystemAssemblyProvider(Directory.GetCurrentDirectory(), "MyCoolProject*.dll")) //Look into current directory, grabs all dlls starting with MyCoolProject
.Build();
}
public void ConfigureServices(IServiceCollection services)
{
//Config Autofac to use with ASP.NET Core
_containerBuilder = new ContainerBuilder();
//...
_bootstrapperLoader.TriggerConfigureContainer(_containerBuilder);
//...
}
public void Configure()
{
//Use Resolve() from Autofac container as service locator
_bootstrapperLoader.TriggerConfigure(_containerBuilder.Build().Resolve);
}
}
By default, BootstrapperLoader
has following settings:
- use
FileSystemAssemblyProvider
to look for all*.dll
in current folder (Directory.GetCurrentDirectory()
) BootstrapperLoader.TriggerConfigure
looks forConfigure()
method in any class with nameBootstrapper
in dlls found aboveBootstrapperLoader.TriggerConfigureContainer
looks forConfigureContainer()
method in any class with nameBootstrapper
in dlls found above
-
WithName("SomeBootstrapper")
: look for class with nameSomeBootstrapper
instead ofBootstrapper
Example:
_bootstrapperLoader = new LoaderBuilder() .ForClass() .WithName("SomeBootstrapper") .Build();
-
HasConstructorParameter<ISomeDependency>()
: when creatingBootstrapper
instance, use constructor that takesISomeDependency
parameterExample:
_bootstrapperLoader = new LoaderBuilder() .ForClass() .HasConstructorParameter<ISomeDependency>(new SomeDependency()) .Build();
-
When(condition).CallConfigure("SomeConfigure")
: when callingBootstrapperLoader.TriggerConfigure()
, ifcondition
invocation is evaluated to true, callSomeConfigure()
method inBootstrapper
classes in addition toConfigure()
Example:
_bootstrapperLoader = new LoaderBuilder() .ForClass() .When(env.IsDevelopment) .CallConfigure("SomeConfigure") .Build();
-
When(condition).CallConfigureContainer("SomeConfigureContainer")
: when callingBootstrapperLoader.TriggerConfigureContainer()
, ifcondition
invocation is evaluated to true, callSomeConfigureContainer()
method inBootstrapper
classes in addition toConfigureContainer()
Example:
_bootstrapperLoader = new LoaderBuilder() .ForClass() .When(env.IsDevelopment) .CallConfigureContainer("SomeConfigureContainer") .Build();
-
When(condition).AddMethodNameConvention("Development")
: when callingBootstrapperLoader.TriggerConfigure()
/BootstrapperLoader.TriggerConfigureContainer()
, ifcondition
invocation is evaluated to true, callSomeConfigure()
/SomeConfigureContainer()
method inBootstrapper
classes in addition toConfigure()
/ConfigureContainer()
Example:
_bootstrapperLoader = new LoaderBuilder() .ForClass() .When(env.IsDevelopment) .AddMethodNameConvention("Development") .Build();
-
Use()
: specify an alternative assembly provider:Example:
_bootstrapperLoader = new LoaderBuilder() .Use(new FileSystemAssemblyProvider(Directory.GetCurrentDirectory(), "MyCoolProject*.dll")) //Look into current directory, grabs all dlls starting with MyCoolProject .Build();
You can also create new Assembly Provider class, to customize the source of assemblies provided to the loader. At the moment, there are 2 classes provided:
- FileSystemAssemblyProvider
- InMemoryAssemblyProvider
BootstrapperLoader
provides 3 methods to trigger methods in sub-projects Bootstrapper
class:
TriggerConfigureContainer<TArg>(TArg parameter)
This method should be used when root project is doing IoC registration. Its parameter is usually IoC container or container builder. This method will look for ConfigureContainer
method in Bootstrapper
classes and pass in the parameter, allow Bootstrapper
classes to register child projects' dependencies to IoC container
TriggerConfigure(Func<Type, object> serviceLocator = null)
This method should be used when it's the right time to do any non-IoC configuration/initialization (.e.g. AutoMapper setting up). It can be called with or without serviceLocator
parameter
This method takes Func<Type, object>
as its parameter to allow Configure
method in Bootstrapper
classes to take in any number of dependencies (as long as those dependencies can be resolved using serviceLocator func). It works in the same way with Startup.Configure
in ASP.NET Core
Func<Type, object>
is used here to ensure this library is not dependent on any specific IoC container. Most IoC container should support a method with this signature (.e.g. in Autofac
, it's Resolve()
method)
When it's called without serviceLocator
parameter, it will look for only Configure()
method (without any parameter) in Bootstrapper
classes
Trigger<TArg>(string methodName, TArg parameter)
When this method is called, it will look for methods with specified name in Bootstrapper
classes in sub-projects and invoke those, passing in provided parameter. This method is for any other situation where your project cannot use above 2 methods.