簡體   English   中英

kernel.Get上的InvalidCastException <type>

[英]InvalidCastException at kernel.Get<type>

我有一個WPF應用程序,可能會或可能不會啟動命令行args。 我曾經在App.xaml代碼隱藏中的OnStartup(StartupEventArgs e)方法中使用了我的組合根,但這導致應用程序關閉問題,所以我將App.xaml變成了“頁面”(而不是“應用程序定義”)並編寫了我自己的Program類,其中包含我自己的app入口點,這將成為我的新組合根位置。

由於這個改變,我一直無法啟動應用程序,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方法/ app入口點:

[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於這樣或這樣的實現,依賴於提供的命令行參數(例如SilentInstallerQuietInterfaceArgument被指定時, ManualInstaller時,它不是,等等)。

通常Ninject提供非常有用和詳細的異常消息 - 當它是ActivationException生活是好的。 但是這個InvalidCastException讓我一無所知,我不是那個執行無效演員的人,我甚至不知道涉及哪些類型。 我只知道我可能已經編寫了一些Ninject不喜歡的代碼,並且這可能與我將IInstaller綁定到它的實現的方式有關,但是如果我注釋掉了“分支”的一部分。 NinjectModule強制綁定我所ManualInstaller的特定實現( ManualInstaller ),它仍然因此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);

所以我至少可以將它縮小到我試圖解決的類型的一個特定依賴:問題是View或者它的唯一依賴,ViewModel。 所以我這樣做了:

// 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>();

顯然,這是IProcessHelper實現的問題 - 再次:

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

現在我不再獲得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;
}

以及NinjectModule如何綁定它:

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

**重新編輯**

在@jure的評論的幫助下,我發現Properties.Settings.DefaultProcessTimeoutSeconds的類型實際上設置為string - 顯然它想要一個int 砰!

在將常量值傳遞給WithConstructorArguments設置時,需要確保對象的類型對於實現類構造函數參數有效。

正如您后來發現的那樣,您在設置中傳遞string對象作為構造函數參數,但構造函數需要一個int 這給了你InvalidCastException

作為旁注,如果Ninject給你一些更好的例外會很好,這確實很難調試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM