0

メソッドを公開するWCFサービスがあります。クライアントがこのメソッドを呼び出すと、次のようになります。

  1. メソッドはいくつかの処理を行います
  2. アセンブリがすでに存在する場合は、アセンブリをロードしようとします
  3. 上記のdllが存在しない場合は、C#コードを生成し、CSharpCodeProviderのCompileAssemblyFromSourceAPIを使用してコンパイルします。
  4. 次に、生成されたばかりのアセンブリをロードします

今問題。このメソッドが最初に呼び出されたときは、ポイント3)でアセンブリが生成され、CompilerResults.CompiledAssemblyを介してアセンブリ参照を返そうとすると、ファイルが見つからないという例外がスローされます。ただし、アセンブリが指定された場所で生成されていることがはっきりとわかり、他のアプリケーションで開くことができます。

クライアントを介してメソッドを再度呼び出すと、アセンブリをロードでき(前の呼び出しの結果として正常に生成されました)、残りの一連のタスクを実行します。アセンブリがそこになく、アセンブリが生成されてすぐにロードされる場合にのみ、その例外が発生します。何か案は?web.configをいじって、偽装をtrue/falseに変更してみました。このWebアプリケーションを実行するための個別のアプリプールがあり、アプリプールのIDをローカルサービスからローカルシステムに変更しようとしました。管理者権限はあるが運がないWindowsログオンクレデンシャルも与えました。

どんな助けでも大歓迎です。

4

2 に答える 2

1

アセンブリを生成していますか?生成されたが見つからないことを除いて、同じ問題があります.dll。最初はフォルダに書き込めなかったのではないかと思ったので、今度はCreateDirectoryテキストファイルを呼び出してドロップし、フォルダが書き込み可能であることを示します。

とにかく、同じ問題、成功しません。他の誰もこの問題を抱えていないのは本当ですか?

サーバーをリモートデバッグして、MicrosoftのPDBをステップスルーできるかどうかを確認します...

- 編集 -

Microsoftのコードをステップスルーする必要はありません。私はCompilerResultsのErrorsコレクションを調べましたが、そこに1つの項目がありました:「メタデータファイル'c:\ Windows \ System32\aaclient.dll'を開くことができませんでした-'でプログラムをロードしようとしました不正な形式。'"

Directory.GetCurrentDirectory()を取得して他のDLLを取得すると、WindowsSystem32ディレクトリが使用されます...

- 編集 -

実行中のアセンブリのフォルダから参照を追加することで、これを解決しました。

CompilerParameters compilerParameters = new CompilerParameters
    {
        OutputAssembly = Path.Combine(GeneratedAssembliesFolder, string.Format("{0}.Generated.dll", typeName))
    };
string executingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string[] dllFiles = Directory.GetFiles(executingDirectory, "*.dll");
compilerParameters.ReferencedAssemblies.AddRange(dllFiles.Select(f => Path.Combine(executingDirectory, f)).ToArray());
IEnumerable<string> exeFiles =Directory.GetFiles(executingDirectory, "*.exe").Where(f => !f.Contains(".vshost."));
compilerParameters.ReferencedAssemblies.AddRange(exeFiles.Select(f => Path.Combine(executingDirectory, f)).ToArray());

堅牢性を高めるために、有効なマネージコードアセンブリであるバイナリのチェックを追加する必要があります。このコードは、2つのGetFiles呼び出しの間にLinq.Unionを使用して短縮することもできます。

書き込むのに適したフォルダを見つけるには:

private static string generatedAssembliesFolder;

private static string GeneratedAssembliesFolder
{
    get
    {
        if (generatedAssembliesFolder == null)
        {
            string[] candidateFolders = new[]
                {
                    Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Process),
                    Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.Process),
                    Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.User),
                    Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.User),
                    Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Machine),
                    Environment.GetEnvironmentVariable("TMP", EnvironmentVariableTarget.Machine),
                    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
                };
            foreach (string candidateFolder in candidateFolders)
            {
                try
                {
                    if (!Directory.Exists(candidateFolder)) Directory.CreateDirectory(candidateFolder);
                    string testFileName = Path.Combine(candidateFolder, Path.GetRandomFileName());
                    File.WriteAllBytes(testFileName, new byte[0]);
                    File.Delete(testFileName);
                }
                catch (Exception ex)
                {
                    continue;
                }
                generatedAssembliesFolder = candidateFolder;

                break;
            }
        }
        return generatedAssembliesFolder;
    }
}
于 2013-01-30T15:10:47.523 に答える
0

ご入力いただきありがとうございますuser1796307。この問題は解決しましたが、更新するのを忘れました。みんなの利益のためにそれを共有する。.NETFusionが登場しました。アセンブリのロードパスをキャッシュし、同じ場所からの以前のロードの試行が失敗した場合でも、アセンブリのロードを試行しません。言い換えると:

if (Assembly.Load("C:\xyz.dll") == null)
 {
    Compile("C:\xyz.dll"); // Now the dll exists
    Assembly.Load("C:\xyz.dll"); // this will still fail
 }


The solution is to change it as:

    if (!File.Exists("C:\xyz.dll")
{
  Compile("C:\xyz.dll"); // Now the dll exists
  Assembly.Load("C:\xyz.dll"); // this will now work

}
于 2014-03-24T11:05:06.943 に答える