kernel.Get <type> </type>的InvalidCastException

时间:2013-06-27 14:34:44

标签: c# wpf ninject

我有一个WPF应用程序,可能会也可能不会以命令行参数启动。我曾经在App.xaml代码隐藏中的OnStartup(StartupEventArgs e)方法中使用了我的组合根,但这导致应用程序关闭问题,因此我将App.xaml转换为“页面”(而不是“应用程序定义”)并编写了我自己的Program类,其中包含我自己的应用程序入口点,这将成为我新的组合根位置。

由于这个改变,我一直无法启动应用程序,Ninject似乎无法解析应用程序的主要对象(或者它可能是它的依赖项之一?)。

这个异常让我浪费了很多时间,堆栈跟踪都是Ninject-internal,我不知道在我的代码中要修复什么,我绑定的方式现在导致这个异常没有最近改变了:

at DynamicInjector54d92ac63a2e47fda5ffbcc19b9942a9(Object[] )
at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent)
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent)
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at Ninject.Planning.Targets.Target`1.GetValue(Type service, IContext parent)
at Ninject.Planning.Targets.Target`1.ResolveWithin(IContext parent)
at Ninject.Activation.Providers.StandardProvider.GetValue(IContext context, ITarget target)
at Ninject.Activation.Providers.StandardProvider.<>c__DisplayClass4.<Create>b__2(ITarget target)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at Ninject.Activation.Providers.StandardProvider.Create(IContext context)
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass10.<Resolve>b__c(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters)
at MyProgram.Program.Main(String[] args) in C:\Dev\MyProject\MyProject.WinPresentation\Program.cs:ligne 40
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

以下是Main方法/应用入口点:

[STAThread]
public static void Main(string[] args)
{
    var module = new MyAppNinjectModule(args);
    var kernel = new StandardKernel(module);

    var argsHelper = module.CommandLineArgs;

    var logProvider = kernel.Get<ILogProvider>();
    var logger = logProvider.GetLogger(typeof(Program).Name);

    if (argsHelper.LoggingDisabledArgument.IsSpecified()) logProvider.DisableLogging();
    logger.Info(log.LogAppStart);

    var installer = kernel.Get<IInstaller>(); // >>> InvalidCastException here

    if (argsHelper.QuietInterfaceArgument.IsSpecified())
    {
        // running with -quiet command-line switch: just execute and exit.
        installer.Execute();
    }
    else
    {
        // instantiate a new App object (WPF), and run it.
        // installer.Execute() may or may not be executed, depending on user actions.
        var app = new App(installer);
        app.Run();
    }
}

NinjectModule将IInstaller绑定到此类或此类实现,具体取决于提供的命令行参数(例如SilentInstaller指定QuietInterfaceArgument时,ManualInstaller指定ActivationException等等)。

通常Ninject会提供非常有用且详细的异常消息 - 当InvalidCastException生命是好的时候。但是这个IInstaller让我一无所知,我不是那个执行无效演员的人,我甚至不知道涉及哪些类型。我只知道我可能已经编写了一些Ninject不喜欢的代码,这可能与我将ManualInstaller绑定到它的实现的方式有关,但是如果我注释掉“分支” “NinjectModule的一部分强制绑定我所追求的特定实现(InvalidCastException),它仍然以public ManualInstaller(IView<MainWindowViewModel> view, IProcessHelper processHelper, ISettingsHelper settingsHelper, ILogProvider logProvider, ISetupBootstrapper installer, bool notifySuccess) : base(notifySuccess, processHelper, settingsHelper, logProvider, installer) 失败。

实现的构造函数:

ActivationException

相应的绑定代码(其余的依赖关系已经绑定,没有var msg = string.Empty; if (CommandLineArgs.CompletionMessageArgument.IsSpecified()) msg = CommandLineArgs.CompletionMessageArgument.ParameterValue(); Bind<MainWindowViewModel>().ToSelf().WithConstructorArgument("completionMessage", msg); Bind<IView<MainWindowViewModel>>().To<MainWindow>(); Bind<IInstaller>().To<ManualInstaller>() .WithConstructorArgument("notifySuccess", notifySuccess); 所以不确定这与我的问题有多相关):

// resolve installer dependencies:
var view = kernel.Get<IView<MainWindowViewModel>>(); // >>> InvalidCastException here
var processHelper = kernel.Get<IProcessHelper>();
var settingsHelper = kernel.Get<ISettingsHelper>();
var bootstrapper = kernel.Get<ISetupBootstrapper>();
var installer = new ManualInstaller(view, processHelper, settingsHelper, logProvider, bootstrapper, true);

如果需要其他任何东西来了解发生的事情,请随时告诉我......

修改

单独解决安装程序的依赖关系会产生更多信息:

// resolve ViewModel dependencies:
var processHelper = kernel.Get<IProcessHelper>(); // >>> InvalidCastException here
var settingsHelper = kernel.Get<ISettingsHelper>();
var messenger = kernel.Get<INetworkMessenger>();
var factory = kernel.Get<IBuildServerFactory>();
var dialogs = kernel.Get<ICommonDialogs>();

所以我至少可以将它缩小到我试图解决的类型的一个特定依赖项:问题是View或者它的唯一依赖项ViewModel。所以我这样做了:

// resolve ProcessHelper dependencies:
var processWrapper = kernel.Get<IProcessWrapper>();
var wmiWrapper = kernel.Get<IWindowsManagementInstrumentationWrapper>();
var helper = new ProcessHelper(processWrapper, wmiWrapper, logProvider, 300);

显然,这是有问题的IProcessHelper实现 - 再次:

InvalidCastException

现在我不再获得private readonly ILogProvider _logProvider; private readonly IProcessWrapper _process; private readonly IWindowsManagementInstrumentationWrapper _wmi; public int TimeoutSeconds { get; private set; } public ProcessHelper(IProcessWrapper process, IWindowsManagementInstrumentationWrapper wmiWrapper, ILogProvider logProvider, int timeout) { _logProvider = logProvider; _process = process; _wmi = wmiWrapper; TimeoutSeconds = timeout; }

这是有问题的类'构造函数和字段:

Bind<IProcessHelper>().To<ProcessHelper>()
                      .WithConstructorArgument("timeout", Properties.Settings.Default.ProcessTimeoutSeconds);

NinjectModule如何绑定它:

ProcessTimeoutSeconds

**重新编辑**

在@ jure评论的帮助下,我发现Properties.Settings.Defaultstring的类型实际设置为int - 显然它需要{{1}} 。等一下!

1 个答案:

答案 0 :(得分:6)

当您将常量值传递给WithConstructorArguments设置时,您需要确保对象的类型对于实现类构造函数参数有效。

正如您后来发现的那样,您在设置中传递string对象作为构造函数参数,但构造函数期望int。这给了你InvalidCastException

作为旁注,如果Ninject给你一些更好的例外会很好,这确实很难调试。