Configuring Automapper in Bootstrapper violates Open-Closed Principle?

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.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)