5

コマンドライン引数で開始される場合と開始されない場合があるWPFアプリがあります。以前は App.xaml コード ビハインドのメソッドにコンポジション ルートがありましたOnStartup(StartupEventArgs e)が、これが原因でアプリのシャットダウンの問題が発生していたため、App.xaml を (「アプリ定義」ではなく) 「ページ」に変更し、独自のProgramクラスを作成しました。独自のアプリ エントリ ポイントが含まれており、これが新しいコンポジション ルートの場所になります。

その変更以来、アプリを起動できませんでした。Ninject はアプリのプライマリ オブジェクトを解決できないようです (または、依存関係の 1 つかもしれません)。

この例外は私に多くの時間を浪費させており、スタック トレースはすべて Ninject 内部です。コードで何を修正すればよいかわかりません。現在この例外を引き起こしている型をバインドする方法は最近変更されていません。

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に応じて、そのような実装にバインドします。SilentInstallerQuietInterfaceArgumentManualInstaller

通常、Ninject は非常に便利で詳細な例外メッセージを表示しますActivationException。しかし、これInvalidCastExceptionは私を無知にさせます.私は無効なキャストを実行しているのではなく、どのタイプが関係しているのかさえ知りません. Ninjectが気に入らないコードを書いた可能性があり、IInstallerその実装にバインドする方法に関係がある可能性があることはわかっていますが、NinjectModuleの「分岐」部分をコメントアウトするとManualInstaller私が求めている特定の実装 ( ) を強制的にバインドするには、まだ this で失敗します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);

したがって、少なくとも解決しようとしているタイプの特定の依存関係に絞り込むことができます。問題は、ビュー、またはその唯一の依存関係である 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 のコメントの助けを借りて、ProcessTimeoutSecondsinのタイプProperties.Settings.Defaultが実際にはstring- に設定されていることがわかりましたint。バンオン!

4

1 に答える 1

6

定数値をWithConstructorArgumentsセットアップに渡すため、オブジェクトの型が実装クラス コンストラクター引数に対して有効であることを確認する必要があります。

string後で発見したように、セットアップでオブジェクトをコンストラクター引数として渡していましたが、コンストラクターはint. そしてそれはあなたにInvalidCastExceptionを与えました。

補足として、Ninject がより優れた例外を提供してくれるとよいのですが、これは実際にデバッグが困難です。

于 2013-06-27T17:29:42.393 に答える