Reputation: 8624
I'm checking the ReactiveUI MVVM framework. I really like the Rx concept and want to start using and learn it for my next project.
I found though a lack of documentation when trying to use it with Ninject, or a third party DI container.
What I usually do is setup Ninject in the platform application layer and register the dependencies there. Then use it to inject the dependencies via constructor or resolve them via service location if needed.
I found this pattern of optional constructor dependencies very good, making the dependency in the constructor optional and if null resolve using service location, works injecting mock dependencies when unit testing.
So let's say you have this constructor.
public OrdersListViewModel(IWebOrdersRepository<Order> webOrdersRepository = null)
{
_webOrdersRepository = webOrdersRepository ?? Locator.Current.GetService<IWebOrdersRepository<Order>>();
}
This is using Splat service locator, but I want to use Ninject constructor injection and service location.
What I do in the iOS platform project is the following.
public class NinjectConfiguration : NinjectModule
{
public override void Load()
{
BindImplementations ();
}
private void BindImplementations()
{
Bind<IWebOrdersRepository<Order>> ().To<WebOrdersRepository> ().InSingletonScope();
Bind<OrdersListViewModel>().ToSelf();
}
}
In the AppDelegate.cs.
NinjectKernel.Initialize(new NinjectConfiguration());
I create a OrdersListViewModel in the UIViewController ViewDidLoad method.
public override async void ViewDidLoad()
{
base.ViewDidLoad();
ViewModel = await BlobCache.LocalMachine.GetOrCreateObject(OrdersListViewModel.Key, () => {
return NinjectKernel.Get<OrdersListViewModel>();
});
}
The above should create a OrdersListViewModel instance injecting the dependencies.
Running the iOS app is not injecting the dependency in the constructor so it always fall in service location resolution.
I can definitely live without DI implementing the optional constructor pattern, since Unit Testing is still easy but I wonder why it is not working.
I found in this link, https://reactiveui.readthedocs.org/en/latest/dependency-injection/splat/, the last paragraph saying.
The Advanced section of the guide describes how to connect third-party dependency injection frameworks. However, the reader is highly encouraged to abandon this idea and use the default resolver.
But, can't find the advanced section, and also why is it encouraged to abandon the idea? I still can have best from all the worlds, right?
At this point not so sure if it's a Ninject issue or I don't know the step to hook it up with ReactiveUI, though I didn't have problems with Ninject DI before.
Upvotes: 1
Views: 1306
Reputation: 1962
It is hard for me to tell exactly what is wrong with your solution, but I think I may offer you some directions regarding connecting a DI framework to RxUI.
You can find a good example using Autofac on Github. It all boils down to wrapping DI of your choice in a class implementing IMutableDependencyResolver
(see example) and then assign it to Locator.Current
property.
As for why you had better use Splat, there is a great answer on SO by the creator of RxUI and Splat himself regarding this topic. Basically,
I generally think a lot of the advice around IoC/DI is pretty bad in the domain of 'cross-platform mobile applications', because you have to remember that a lot of their ideas were written for web apps, not mobile or desktop apps.
For example, the vast majority of popular IoC containers concern themselves solely with resolution speed on a warm cache, while basically completely disregarding memory usage or startup time - this is 100% fine for server applications, because these things don't matter; but for a mobile app? Startup time is huge.
Splat's Service Location solves a number of issues for RxUI:
- Service Location is fast, and has almost no overhead to set up.
- It encapsulates several different common object lifetime models (i.e. 'create new every time', 'singleton', 'lazy'), just by writing the Func differently
- It's Mono Linker friendly (generally)
- Service Location allows us to register types in platform-specific code, but use them in PCL code.
Upvotes: 2