I would argue that you are violating two principles: the single responsibility principle (SRP) and the open/closed principle (OCP).
You are violating the SRP because the bootstrapping class have more than one reason to change: if you alter model binding or the auto mapper configuration.
You would be violating the OCP if you were to add additional bootstrapping code for configuring another sub-component of the system.
How I usually handle this is that I define the following interface.
public interface IGlobalConfiguration
{
void Configure();
}
For each component in the system that needs bootstrapping I would create a class that implements that interface.
public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
private readonly IConfiguration configuration;
public AutoMapperGlobalConfiguration(IConfiguration configuration)
{
this.configuration = configuration;
}
public void Configure()
{
// Add AutoMapper configuration here.
}
}
public class ModelBindersGlobalConfiguration : IGlobalConfiguration
{
private readonly ModelBinderDictionary binders;
public ModelBindersGlobalConfiguration(ModelBinderDictionary binders)
{
this.binders = binders;
}
public void Configure()
{
// Add model binding configuration here.
}
}
I use Ninject to inject the dependencies. IConfiguration
is the underlying implementation of the static AutoMapper
class and ModelBinderDictionary
is the ModelBinders.Binder
object. I would then define a NinjectModule
that would scan the specified assembly for any class that implements the IGlobalConfiguration
interface and add those classes to a composite.
public class GlobalConfigurationModule : NinjectModule
{
private readonly Assembly assembly;
public GlobalConfigurationModule()
: this(Assembly.GetExecutingAssembly()) { }
public GlobalConfigurationModule(Assembly assembly)
{
this.assembly = assembly;
}
public override void Load()
{
GlobalConfigurationComposite composite =
new GlobalConfigurationComposite();
IEnumerable<Type> types =
assembly.GetExportedTypes().GetTypeOf<IGlobalConfiguration>()
.SkipAnyTypeOf<IComposite<IGlobalConfiguration>>();
foreach (var type in types)
{
IGlobalConfiguration configuration =
(IGlobalConfiguration)Kernel.Get(type);
composite.Add(configuration);
}
Bind<IGlobalConfiguration>().ToConstant(composite);
}
}
I would then add the following code to the Global.asax file.
public class MvcApplication : HttpApplication
{
public void Application_Start()
{
IKernel kernel = new StandardKernel(
new AutoMapperModule(),
new MvcModule(),
new GlobalConfigurationModule()
);
Kernel.Get<IGlobalConfiguration>().Configure();
}
}
Now my bootstrapping code adheres to both SRP and OCP. I can easily add additional bootstrapping code by creating a class that implements the IGlobalConfiguration
interface and my global configuration classes only have one reason to change.