I'm building an application (Xamarin.Forms, PCL and iOS, in case it's relevant) that uses Simple Injector for dependency injection throughout. So far, it's been great to work with, and with the recent release of Simple Injector 3 I'm updating my code to work with the new API. Unfortunately, I'm having a little trouble with one particular registration.
Here's the basic flow:
ISQLitePlatform
(Windows, iOS, Android, etc) to handle the platform-specific bits (SQLite API, file I/O etc.)The app can then use the data access provider to open transactions on the database - the IDataAccessProvider
interface just has one method, NewTransaction()
, which returns a unit-of-work object with generic CRUD methods. The IDataAccessProvider
also implements IDisposable
, and the Dispose()
methods handle the cleanup, closing of open connections/transactions, etc.
The issue is with these registrations:
container.RegisterSingleton<ISQLitePlatform, SQLitePlatformIOS>();
container.RegisterSingleton<ILocalDataBootstrapper, SQLiteDataBootstrapper>();
container.RegisterSingleton<IDataAccessProvider>(
() => container.GetInstance<ILocalDataBootstrapper>().DataAccessProvider);
For some reason, on startup I get the diagnostic warning that SQLiteDataAccessProvider
is IDisposable
and has been registered as transient. I can handle this - the disposal is being handled in the correct place - but what's confusing me is that it's definitely not being registered as transient, given that I'm using RegisterSingleton()
.
Is this a quirk of using RegisterSingleton()
with a creation lambda instead of an instance? Is it a bug? Or am I missing something I'm supposed to do?
The most likely reason why this is happening is that somewhere in your code you make the following call:
container.GetInstance<SQLiteDataAccessProvider>();
Or you have a constructor that depends on this concrete type instead of the abstraction (in which case you can expect other warnings about this as well).
Since SQLiteDataAccessProvider
is not registered 'as itself' (but merely by its IDataAccessProvider
abstraction), Simple Injector will resolve this type for you and by default Simple Injector will make this type transient.
By doing so, a new registration is added to Simple Injector; you will be able to see that in the debugger. There is a singleton registration for IDataAccessProvider
and a transient registration for SQLiteDataAccessProvider
.
Now because there is a transient registration for SQLiteDataAccessProvider
, Simple Injector will warn you that this instance will not get disposed automatically.
The solution is to remove the GetInstance<SQLiteDataAccessProvider>()
call (or changge the ctor argument to use the abstraction) and replace it with a call to GetInstance<IDataAccessProvider>()
.