Question

I have a NHibernate.Cfg.Configuration provider.

ConfigurationProvider

public class ConfigurationProvider : Provider<Configuration> {
    public class ConfigurationProvider(string connectionString
        , Assembly mappings) {
        ConnectionString = connectionString;
        Mappings = mappings;
    } 

    protected override Configuration CreateInstance(IContext context) {
        var c = new Configuration().Configure();
        c.AddAssembly(Mappings);
        c.Properties["connection.connection_string"] = ConnectionString;
        return c;
    }

    private readonly string ConnectionString;
    private readonly Assembly Mappings;
}

Which the connection string comes from the Configurationservice.BuildConnectionString() of my application.

ConfigurationService

public class ConfigurationService {
    public ConfigurationService(ICurrentUser user) { CurrentUser = user; }

    public string BuildConnectionString() {
        return string.Format(DefaultConnectionString
            , CurrentUser.DatabaseInstanceName
            , CurrentUser.Login
            , CurrentUser.Password);
    }

    private readonly ICurrentUser CurrentUser;
}

That in turn depends on the CurrentUser to impersonate.

CurrentUser

public class CurrentUser : ICurrentUser {
    public CurrentUser(string dbinstance, string login, string password) { 
        DatabaseInstanceName = dbinstance;
        Login = login;
        Passwword = password;
    }

    public readonly string DatabaseInstanceName;
    public readonly string Login;
    public readonly string Password;
}

So manually injecting my dependency would look like:

string dbInstance = authenticationDialog.DatabaseInstanceName;
string login = authenticationDialog.Login;
string password = authenticationDialog.Password;

var nHibernateConfigurationProvider = 
    new ConfigurationProvider(
        new ConfigurationService(
            new CurrentUser(dbInstance, login, password)).BuildConnectionString()
        , Assembly.GetExecutingAssembly());

The problem is that I don't know how to bind, using Ninject, the ConfigurationService.BuildConnectionString() method to resolve the string used as constructor argument in the ConfigurationProvider.ctor().

Pushing it even further, how do I tell Ninject to actually bind these types only once the user is authenticated?

Here's what I have so far

// Wait until user is authenticated before continuing to bind???
Bind<string>().ToMethod(ctx => ctx.Request.???.BuildConnectionString()).WhenInjectedInto<ConfigurationProvider>().InSingletonScope();
Bind<Assembly>().ToConstant<Assembly>(Assembly.GetExecutingAssembly().WhenInjectedInto<ConfigurationProvider>();
Was it helpful?

Solution

Here is my suggestion on how you can achieve this.

Since you don't have the data beforehand and only when your ICurrentUser is created via the credentials and parameters you need, it means that you need to "save it" into a globally accessible location once it has been created.

If we think about a web .NET application, that would tipically involve binding the ICurrentUser with InRequestScope() using a static reference to a HttpContext.

As this is not your case, I've chosen to bind ICurrentUser as a singleton and initialize it passing the values. When you need your other classes that depend on it, the container will pass the already-initialized instance, since it is bound with InSingletonScope().

I've also tried to mimic your current dependencies. For instance, instead of passing in the connectionString to ConfigurationProvider, my way of doing it would be declare a direct dependency on ConfigurationService in order to obtain the information.

// Do your stuff to collect credentials

// User now authenticated, initialize ICurrentUser instance singleton
// You could have used a ICurrentUserFactory or static member, this is just a sample implementation
kernel.Get<ICurrentUser>(new ConstructorArgument("dbInstance", dbInstance),
    new ConstructorArgument("login", login),
    new ConstructorArgument("password", password));

// You can now access your NHibernate configuration properly
var config = kernel.Get<Configuration>();

And the bindings:

Bind<Configuration>().ToProvider<ConfigurationProvider>();
Bind<ConfigurationProvider>()
    .ToMethod(
        ctx => new ConfigurationProvider(ctx.Kernel.Get<ConfigurationService>().BuildConnectionString()));

Bind<ICurrentUser>().To<CurrentUser>().InSingletonScope();

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top