It is a desktop application which is obliged to impersonate the current user when accessing the underlying data source.
How can I tell Ninject not to bind the dependency until the property of a parent object is not null?
- Application forces user authentication upon startup
- Once authenticated, a reference to the current user credentials is kept within the
IMembershipService
- Accessing the underlying datasource obliges to have a user authenticated so that the commection string states the credentials to impersonate
I am actually using NHibernate, and I need to dynamically create the connection string based on the user credentials provided upon authentication.
So I would like to achieve:
public class DataModule : NinjectModule {
public override void Load() {
Bind<ISessionFactory>().ToProvider<SessionFactoryProvider>()
.When( // IMembershipService.CurrentUser != null );
}
}
Since the SessionProviderFactory
depends on the IMembershipService.CurrentUser
.
I am aware this might not be the design of the century, beside I need it to work this way for now so that I can deliver my piece of potentially shippable product. I'll be glad to refactor afterwards.
SessionFactoryProvider
public class SessionFactoryProvider : Provider<ISessionFactory> {
public class SessionFactoryProvider(IMembershipService service) {
membershipService = service;
}
protected override ISessionFactory CreateInstance(IContext context) {
Configuration nhconfig = new Configuration().Configure();
nhconfig.AddAssembly(Assembly.GetExecutingAssembly());
nhconfig.Properties["connection.connection_string"] = buildConnectiongString();
return nhconfig.BuildSessionFactory();
}
private string buildConnectionString() {
return string.Format(membershipService.GetDefaultConnectionString()
, membershipService.CurrentUser.DatabaseInstanceName
, membershipService.CurrentUser.Login
, membershipService.CurrentUser.Password);
}
private readonly IMembershipService membershipService;
}
SessionProvider
public class SessionProvider : Provider<ISession> {
public class SessionProvider(ISessionFactory factory) {
sessionFactory = factory;
}
protected override ISession CreateInstance(IContext context) {
return sessionFactory.OpenSession();
}
private readonly ISessionFactory sessionFactory;
}
The fact is that I can't instantiate the IMembershipService.CurrentUser
upon application startup. The user has first to authenticate to the system, hence the ActivationException
.
Error activating ISession
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency ISession into parameter session of constructor of type InquiriesRepository
2) Injection of dependency IInquiriesRepository into parameter repository of constructor of type InquiriesManagementPresenter
1) Request for InquiriesManagementPresenter
Suggestions:
1) Ensure that you have defined a binding for ISession.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
So, how can I make it?
Any design improvement suggestions welcome. But keep in mind that I need it to work badly. I'll refactor for the next delivery.
EDIT
It looks like I perhaps could use contexts/scope dependency injection.
How to use the additional Ninject Scopes of NamedScope
And still, I cannot figure out how to make it work here in my scenario.
UPDATE
Through my readings, I begin to doubt that perhaps contextual binding would be more suitable for my needs than conditional binding.
Any thoughts?
Each article which relates on conditional binding is talking about conditional type binding, not conditional state binding.
In my scenario, it specifically believe it is a conditional state binding, hence the thoughts about context binding.
Then, I would have two bindings.
- Before the user is authenticated
- After the user is authenticated
So perhaps I either have to use lazy injection, which would resolve my problem, as an instance of the ISessionFactory
isn't required on application startup.
I'm a bit loss here...
Lazy<ISession>
injection or create instances only when everything which is required to run it is available. Another approach would be to proxy theISession
and exchange the underlying implementation when it becomes available. If a call is made to the proxy before the session is available, throw an exception. But i think i would prefer only building the affected path of the object tree when everything required for it is available. – Degraded