views:

113

answers:

1

I have set up a NInject (using version 1.5) binding like this:

Bind<ISessionFactory>().ToMethod<ISessionFactory>(ctx => 
{
    try
    {
        // create session factory, might fail because of database issues like wrong connection string
    }
    catch (Exception e)
    {
        throw new DatabaseException(e);
    }
}).Using<SingletonBehavior>();

As you can see, this binding uses a singleton behavior but can also throw exception when something is not configured correctly, like a wrong connection string to the database.

Now, when the creation of a session factory fails at first (throwing a database exception), NInject doesn't try to create the object again but always returns null.

I would need NInject to check for null first and recreate when the instance is null, but of course not when there already is an instance successfully constructed (keeping it singleton). Like this:

var a = Kernel.Get<ISessionFactory>(); // might fail, a = null
// ... change some database settings
var b = Kernel.Get<ISessionFactory>(); // might not fail anymore, b = ISessionFactory object

Would I need to write a custom behavior or am I missing something else?

+1  A: 

This doesnt make much sense.

Firstly, the point of a singleton is that everything depending on that item should see exactly the same thing - this is very hard to achieve if your factory method is going to change its mind.

Also, if you're talking about an NHibernate ISessionFactory (are you?), it's not going to have transient failures of this nature that can be recovered (or if it can, can you explain why - I'm no expert on it). I appreciate that the creation of a Session might fail (but you wouldnt be keeping it as a singleton), but that's a completely different to the creation of a factory failing (if you cant rely on your factories to have dumb constructors, what can you rely on?).

In terms of the NInject angle on this, the creation method (be it Factory or Provider) is separate to the scoping, so I doubt there's going to be a way to manage what you're looking to do cleanly (even if you can resolve the opening two questions). I highly recommend looking at the source - it's short and clean so if there's an answer, it'll jump right out at you. It'll take you no more than a minute to download - go do it!

Finally, a good article on managing NHibernate sessions (Which IIRC doesnt make any provision for session factory creation failure)

Now, to actually answer the question regardless of whether its a bad one - if it was possible for a failure to happen in the creation of the factory, and you couldnt adjust the factory in order not to do that (how many retry looks have you seen for creating factories?), the answer is that you'd move the retry logic (for creating the Factory) into a Provider or Method that's responsible for creating Sessions, which can then retry in a manner that you see fit.

Ruben Bartelink
I am talking about NHibernate. It's not the SessionFactory itself that fails, it's a little more complicated (using unhaddins). to create the sessionfactory, it needs an ISessionFactoryProvider, which in turn needs an IConfigurationProvider, which creates an NHibernate configuration which might fail because it can't connect to the database... so in the end, my SessionFactory IS coupled to the configuration, at least when using unhaddins. I don't want to enforce a strict singleton behavior. Source: http://code.google.com/p/testbat/source/browse/trunk/TestBat.GuyWire.Modules/ModelModule.cs
Maximilian Csuk
In a nutshell, this is what gets called: SessionFactory sf = new Configuration().configure().buildSessionFactory();And the configure()-part fails, so no SessionFactory is created when the configuration is wrong. But the application should give the user the opportunity to change the configuration and try to create the SessionFactory again.
Maximilian Csuk
@Maximilian Csuk: I had an idea it was that sort of thing alright. I'd stand by the general principle of my response though: You need some things to remain stable. If you support/want/need retry logic, you have a factory, not a simple singleton. The way to do that is to Bind `Session` to a Method or a Provider which can then pass on the failure. Ninject does not concern itself with retry logic in the same way NHibernate doesnt have any default policies in that direction either.
Ruben Bartelink
Most people would say things should fail fast though. If my website is not able to connect to the database, I want to know now - when I start the site - it's not really alive if I cant get a session factory. This is not just a matter of retrying and hoping for the best; this is a problem. The other way to look at this is that you want to let the site come up but be in 'site down mode' - i.e., have each request retry initialisation each time and a) cache it if it succeeds or b) let the problem bubble up [to ELMAH].
Ruben Bartelink
If you really feel happy you need to start managing this, I suggest you look at the hook points in your Ninject/platform integration (what is your platform?). If there isnt a clear answer ther (for instance from my recollection the MVC support wouldnt handle this too cleanly), then you have a question worthy of the Ninject mailing list. Ian and the guys over there are very responsive and eat this sort of stuff for breakfast.
Ruben Bartelink
One final thing though - I'm still not yet convinced this is a transient failure though. If your configure() fails, you need to reconfigure. If thats a matter of editing a web.config, your AppDomain is going to restart anyway so no point in having it semi-alive after failure to initialise anyway. Try to see if you can find others doing this (retrying creation of SessionFactory) before worrying about whether Ninject is going to support you in your quest.
Ruben Bartelink
Thanks for your answers so far! The thing is, it is not a web application, but a desktop (WPF) application backed up by a database. I have already created an interface for the user where he can enter/change database informations. For a website of course, I'd set the DB-infos once and (almost) never change them. But this application is installed on different machines and should be configurable by the user, hence the UI for entering the informations in the first place.I will try to find some answers in the NInject community though, thanks again! :-)
Maximilian Csuk
It may be helpful to use Modules to separate stuff that assumes presence of a session factory (in the normal way) from the 'pick your connection' Area of your application during which one wants to dynamically manage the retries etc. and then only bring up the rest of the system (i.e., create the Module and the Kernel (container) that relies on the session factory separately as an explicit point in the workflow of your app starting). You dont want to spread this sort of "ooh, better check just in case" logic too far into your system - this is largely a startup concern.
Ruben Bartelink