连接第三方依赖注入框架与 ReactiveUI

Connect third-party dependency injection framework with ReactiveUI

我正在检查 ReactiveUI MVVM 框架。我真的很喜欢 Rx 概念,并想在我的下一个项目中开始使用和学习它。

我发现在尝试将它与 Ninject 或第三方 DI 容器一起使用时缺少文档。

我通常做的是在平台应用层设置Ninject并在那里注册依赖。然后使用它通过构造函数注入依赖项,或者在需要时通过服务位置解析它们。

我发现这种可选构造函数依赖关系的模式非常好,它使构造函数中的依赖关系成为可选的,如果使用服务位置解析为 null,则可以在单元测试时注入模拟依赖关系。

假设你有这个构造函数。

public OrdersListViewModel(IWebOrdersRepository<Order> webOrdersRepository = null)
        {
            _webOrdersRepository = webOrdersRepository ?? Locator.Current.GetService<IWebOrdersRepository<Order>>();
        }

这是使用 Splat 服务定位器,但我想使用 Ninject 构造函数注入和服务定位。

我在iOS平台项目中所做的如下。

public class NinjectConfiguration : NinjectModule
    {
        public override void Load()
        {
            BindImplementations ();
        }

        private void BindImplementations()
        {
            Bind<IWebOrdersRepository<Order>> ().To<WebOrdersRepository> ().InSingletonScope();
            Bind<OrdersListViewModel>().ToSelf();
        }
    }

在AppDelegate.cs.

NinjectKernel.Initialize(new NinjectConfiguration());

我在 UIViewController 的 ViewDidLoad 方法中创建了一个 OrdersListViewModel。

public override async void ViewDidLoad()
        {
            base.ViewDidLoad();

            ViewModel = await BlobCache.LocalMachine.GetOrCreateObject(OrdersListViewModel.Key, () => {
                return NinjectKernel.Get<OrdersListViewModel>();
            });
        }

上面应该创建一个注入依赖项的 OrdersListViewModel 实例。

运行 iOS 应用程序未在构造函数中注入依赖项,因此它始终属于服务位置解析。

我绝对可以不用 DI 实现可选构造函数模式,因为单元测试仍然很容易,但我想知道为什么它不起作用。

我在这个link,https://reactiveui.readthedocs.org/en/latest/dependency-injection/splat/,最后一段说.

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.

但是,找不到高级部分,又为什么鼓励放弃这个想法?我仍然可以拥有世界上最好的,对吧?

目前不太确定这是 Ninject 问题还是我不​​知道将它与 ReactiveUI 连接的步骤,尽管我之前没有遇到 Ninject DI 的问题.

我很难确切地说出您的解决方案有什么问题,但我想我可以为您提供一些有关将 DI 框架连接到 RxUI 的指导。

你可以找到一个good example using Autofac on Github. It all boils down to wrapping DI of your choice in a class implementing IMutableDependencyResolver (see example)然后赋值给Locator.Current 属性.

至于为什么最好使用 Splat,there is a great answer on SO by the creator of RxUI and Splat himself 关于这个话题。基本上,

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:

  1. Service Location is fast, and has almost no overhead to set up.
  2. It encapsulates several different common object lifetime models (i.e. 'create new every time', 'singleton', 'lazy'), just by writing the Func differently
  3. It's Mono Linker friendly (generally)
  4. Service Location allows us to register types in platform-specific code, but use them in PCL code.