尝试执行构造函数注入时 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>();
}
我在使用 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>();
}