CodedOmproviderを使用してメモリにコンパイルされた場合、アセンブリは参照アセンブリを見つけることができません
-
25-10-2019 - |
質問
CodedOmproviderを使用して、実行時にメモリにコードをコンパイルしようとしています。
私がコンパイルしているコードには、コードをコンパイルするときに使用されるパラメーターに含める外部アセンブリへの参照があります。
メモリにコンパイルし、ビジュアルスタジオアドインで生成されたアセンブリで反射を使用しようとすると、参照されるアセンブリが見つからないという例外がスローされます。
(例外)
「要求されたタイプの1つ以上をロードできません。詳細については、LoaderExceptionsプロパティを取得します。」
(loaderexception)
"{"ファイルまたはアセンブリ 'dynamo.jiss.task、version = 1.0.0.0、culture = neutral、publickeytoken = null'またはその依存関係の1つ。システムは指定されたファイルを見つけることができません。 ":" dynamo.jiss.task、version = 1.0.0.0、culture = neutral、publickeytoken = null "}"
絶対パスを使用して、さまざまな場所からアセンブリを参照してみました。
コンソールアプリケーションから実行されている場合、まったく同じコードが正常に機能します。また、メモリにコンパイルしない場合は、アドインでも正常に機能します。
外部アセンブリへの参照と参照コードを削除することは、メモリにコンパイルするときにも機能するため、おそらく例外が説明するように、参照されるアセンブリのロードの問題です。
なぜメモリにコンパイルし、アセンブリを参照するのかという考えはありますか?
それが実行しているAppDomain内にいくつかの制限がありますか、それとも私が知っておくべきことはありますか? (現在私の最高の推測)
特定のフォルダーにある必要がありますか?相対パスを使用して参照されていますか?セキュリティ設定?署名する必要がありますか?何か案は?
私が達成しようとしているのは、プロジェクトに特定の拡張機能を備えたファイルを配置し、Addinが自動的にコンパイルする方法であり、ITASKインターフェイスを実装する場合(外部アセンブリから)、それを作成するセットアップ()メソッドを呼び出しますコードがビジュアルスタジオイベントに接続し、さまざまなイベントを聞きながらタスク/スクリプトを実行することができます。これにより、別のファイルが変更された場合にテキストテンプレートを簡単に実行するか、さまざまなイベント(ドキュメント保存、ビルドなど)でファイルを組み合わせてマニー化できます。
このようなものはすでに存在していますか(痛みから私を和らげるために)? :)
解決
これは、メモリ内のアセンブリを生成するようにCodedomに伝えているために起こる可能性が最も高くなります(これは、ディスクに一時的に生成し、ロードしてからファイルを削除するため、本当に嘘です)。ポイントは、Codedom Assemblyのコンパイルディレクトリがコンパイルするために使用しているものと同じではないことです。つまり、Bin debugで実行されている場合、Codedomアセンブリは%TEMP%に生成されています。
あなたは私が考えることができる2つの方法のいずれかでこれを解決することができます:
アセンブリの実行と同じパスにコードドームアセンブリをコンパイルします。
myCodeProvider.GenerateInMemory = false; // may not be necessary...haven't tried this in a while myCodeProvider.OutputAssembly = string.Format(@"{0}\{1}", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location, "mydll.dll");
AssemblyResolveイベントを処理し、要求された参照アセンブリをコードドームアセンブリに提供します。
AppDomain.CurrentDomain.AssemblyResolve += OnCurrentDomainAssemblyResolve private static Assembly OnCurrentDomainAssemblyResolve(object sender, ResolveEventArgs args) { // this is absurdly expensive...don't do this more than once, or load the assembly file in a more efficient way // also, if the code you're using to compile the CodeDom assembly doesn't/hasn't used the referenced assembly yet, this won't work // and you should use Assembly.Load(...) foreach (Assembly @assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (@assembly.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase)) { return @assembly; } } }