尝试执行构造函数注入时 Prism + DryIoc 崩溃?

Prism + DryIoc crashes when trying to perform constructor injection?

我在使用 DryIoc 将构造函数注入到使用 Prism 和 Xamarin 的 ViewModel 时遇到问题。我正在使用 Nuget 包 Prism.DryIoc.Forms.

在我的项目中,我在 AuthenticatePage.xaml.g.cs

中收到以下错误
Unable to resolve Object {RequiredServiceType=Project.ViewModels.AuthenticatePageViewModel} with 1 arg(s) 
in wrapper Func<Xamarin.Forms.Page, Object> {RequiredServiceType=Project.ViewModels.AuthenticatePageViewModel} with 1 arg(s) 
from container
with normal and dynamic registrations:
MainPage, {ID=44, ImplType=Project.Views.MainPage}}
NavigationPage, {ID=43, ImplType=Xamarin.Forms.NavigationPage}}
AuthenticatePage, {ID=45, ImplType=Project.Views.AuthenticatePage}}

具体来说,它指向的是

private void InitializeComponent() {
        global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(AuthenticatePage));
    }

值得注意的是,如果我在 App.OnInitialized 中调用以下内容,对象解析良好:

c.Register<INegotiator, Negotiator>(Reuse.Singleton);
var n = c.Resolve<INegotiator>();
n.ResumeSessionAsync(); // This works fine, no problems.
await NavigationService.NavigateAsync("NavigationPage/AuthenticatePage"); // Error thrown here

如果我从我的 ViewModel 中删除构造函数注入,它工作正常(除了保留默认的 navigationService 注入,它工作正常)。即使尝试注入像 ILogger 这样的基本 class(无依赖项)也会失败。

public AuthenticatePageViewModel(INavigationService navigationService, ILogger logger) : base (navigationService)
{
    Title = "Authentication Page...";
}

我会继续调查,但是如果我从根本上做错了什么,这里的人会很明显吗?如果非要我猜的话,我会说这与内置于 Ioc 容器和 DryIoc 中的 Prisms 发生冲突?

编辑:

我使用的是 NuGet (7.0.0.396) 上可用的最新版本 Prism.DryIoc.Forms,其中包含 DryIoc 2.12.26。到目前为止,我只是简单地遵循了 Visual Studio 可用的模板,其中列出了如下设置导航:

protected override async void OnInitialized()
{
    InitializeComponent();

    var c = new Container();
    c.Register<ILogger, LoggerConsole>(Reuse.Singleton);

    c.RegisterMany(new[] { Assembly.Load("Project.UWP") },
                   serviceTypeCondition: type => type == typeof (ILocalFileHandler));

    c.Register<INegotiator, Negotiator>(Reuse.Singleton);
    // var n = c.Resolve<INegotiator>(); 
    // n.ResumeSessionAsync(); // <- This will run fine. Negotiator class has ILogger and ILocalFileHandler injected into it.

    await NavigationService.NavigateAsync("NavigationPage/AuthenticatePage");

}

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<NavigationPage>();
    containerRegistry.RegisterForNavigation<MainPage>();
    containerRegistry.RegisterForNavigation<AuthenticatePage>();
}

我在 if/how 上找不到任何在线信息 我应该使用 Prism.DryIoc.DryIocContainerExtensions 来设置导航吗?即使修改示例应用程序以包含基本构造注入也会导致同一 xaml.g.cs 文件中的错误 "Value Cannot Be Null"?

Prism 7.0 及以下版本允许异常冒泡,为了诊断问题的根本原因你想更好地诊断这个问题我建议你做一点 try/catch 看看是什么和在哪里确实是错误。

protected override void OnInitialized()
{
    try
    {
        // Check if there is an initialization exception
        var page = new AuthenticationPage();

        // Validate that the page resolves ok
        var page2 = Container.Resolve<object>("AuthenticationPage");

        // Validate that your ILogger interface is registered and resolves ok
        var logger = Container.Resolve<ILogger>();

        // Check for Registration/initialization exceptions
        var vm = Container.Resolve<AuthenticationPageViewModel>();
    }
    catch(Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex);
        System.Diagnostics.Debugger.Break();
    }
}

您没有指定在什么时候出现此错误,但通常在启用 XAML 编译的情况下,您会在编译期间而不是运行时在 {pageName}.xaml.g.cs 中看到异常。无论哪种方式,鉴于您的异常来自 class 后面生成的 XAML 代码,这告诉我这很可能是您的 XAML 的问题。验证这一点的一种非常简单的方法是删除 AuthenticationPage 中的所有 XAML 内容,以便您拥有一个空页面。

鉴于您作为问题的一部分提供的代码,我会说您没有注册 ILogger 接口,这可能会引发异常,从而导致您遇到的问题。不管 what/where 错误是什么,上面显示的 try/catch 将是确定根本原因的最简单方法。

按照@Dan S. 的诊断建议以及阅读本文 (http://brianlagunas.com/whats-new-in-prism-for-xamarin-forms-7-0/),我意识到我应该一直使用 Prism.Ioc.ContainerRegistry 抽象层来与 DryIoc 交互。在此之前,我一直在直接使用 DryIoc 的 类.

一旦我修改我的注册码以使用Prism.Ioc.IContainerRegistry,它就完美地工作了。

protected override void RegisterTypes(IContainerRegistry cr)
{
    cr.Register<ILogger, LoggerConsole>();

    cr.GetContainer().RegisterMany(new[] { Assembly.Load("Project.UWP") },
                   serviceTypeCondition: type => type == typeof(ILocalFileHandler));

    cr.Register<INegotiator, Negotiator>();


    cr.RegisterForNavigation<NavigationPage>();
    cr.RegisterForNavigation<MainPage>();
    cr.RegisterForNavigation<AuthenticatePage>();
}