2

I'm looking for a good way to incorporate settings inside my webapp (asp mvc). I've came across a really nice implementation in NopCommerce. NopCommerce stores the values in a database table, with a name and value. The name is derived from the class and property name (e.g. customersettings.settingname1)

The exact way NopCommerce works with settings can be found in this question: Understanding how Nop Commerce settings are loaded from the database

NopCommerce uses Autofac as DI framework to bind the Settings to the ConfigurationProvider as follows (as I'm correct).

return RegistrationBuilder
                .ForDelegate((c, p) => c.Resolve<IConfigurationProvider<TSettings>>().Settings)
                .InstancePerHttpRequest()
                .CreateRegistration();

In the appropriate classes, you can now use ClientSettings as a parameter, and it's automatically filled with data from the database.

I really like this implementation, because it is very flexible. The problem however is that I'm using Ninject. I've tried several things to get the correct bindings, but can't seem to find the correct implementation. Does anyone have an idea how to get this working?

EDIT:

I found a way to bind ClientSettings directly:

kernel.Bind<ClientSettings>()
      .ToMethod(ctx => ctx.Kernel.Get<IConfigurationProvider<ClientSettings>>().Settings)
      .InRequestScope();

But is there a way to achieve this?

kernel.Bind<ISettings>()
      .ToMethod(ctx => ctx.Kernel.Get<IConfigurationProvider<ISettings>>().Settings)
      .InRequestScope();

EDIT 2

I think I'm getting close, but still run into some problems. I create a custom Binding Generator:

public class SettingsBindGenerator : IBindingGenerator
{
    static readonly MethodInfo BuildMethod = typeof(SettingsBindGenerator).GetMethod(
        "BuildRegistration",
        BindingFlags.Static | BindingFlags.NonPublic);      

    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        var obj = typeof (object).IsAssignableFrom(type);
        if (type != null && typeof(ISettings).IsAssignableFrom(type))
        {
            var buildMethod = BuildMethod.MakeGenericMethod(type);
            var methodResult = buildMethod.Invoke(null, new object[]{bindingRoot});
            var castedResult = methodResult as IBindingWhenInNamedWithOrOnSyntax<object>;
            yield return castedResult;
        }
    }


    static IBindingWhenInNamedWithOrOnSyntax<TSettings> BuildRegistration<TSettings>(IBindingRoot bindingRoot) where TSettings : ISettings, new()
    {
        return bindingRoot.Bind<TSettings>().ToMethod(
            ctx => ctx.Kernel.Get<IConfigurationProvider<TSettings>>().Settings);
    }
}

This works for 99%. However, for some reason, buildMethod.Invoke returns an BindingConfigurationBuilder, and not an IBindingWhenInNamedWithOrOnSyntax. Therefor, castedResult is always NULL. Anybody got an idea how to correct this?

LAST EDIT

I don't know why, but suddenly it works! Glad I've finally figured it out. Thanx Remo!

Community
  • 1
  • 1
Pbirkoff
  • 4,642
  • 2
  • 20
  • 18

1 Answers1

1

You have several options:

  1. Do it like NopCommerce and scan for the settings classes and call the registration method from your first edit using reflection.
  2. Use the conventions extension to register all classes implementing ISettings using a custom binding generator https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind
  3. Use the conventions extension to register all classes implementing ISettings to bind all interfaces. And add a custom IActivationStrategy to Ninject that does assigns the properties like NopCommerce does.
Remo Gloor
  • 32,665
  • 4
  • 68
  • 98