0

I have a WCF service that exposes a method. When a client calls this method, the following occurs:

  1. the method does some processing
  2. it tries to load an assembly if its already there
  3. if the above dll isn't there, it generates C# code, compiles it using CSharpCodeProvider's CompileAssemblyFromSource api
  4. It then loads the just generated assembly

Now the problem. The first time the method it called, it generates the assembly at point 3), and when it tries to return the assembly reference via CompilerResults.CompiledAssembly it throws a file not found exception. However, I can clearly see that the assembly has been generated at the specified location and I can open it with other applications.

If I call the method again via a client, it is able to load the assembly (it was successfully generated as a result of the previous call) and goes ahead to do the remaining set of tasks. Only when the assembly isnt there and it generates it and goes ahead to load it immediately, I get that exception. Any ideas? I have tried playing around with the web.config, changing impersonation to true/false. I have a seperate app pool to run this web application and I tried changing the identity of the app pool from local service to local system, even gave my windows logon credentials which has admin rights but no luck.

Any help would be much appreciated.

4

2 回答 2

1

你确定它正在生成程序集吗?我有同样的问题,除了我找不到生成的.dll. 我首先怀疑它无法写入文件夹,所以它现在调用CreateDirectory并删除一个文本文件以证明该文件夹是可写的。

无论如何,同样的问题,没有成功。真的没有其他人遇到过这个问题吗?

我将远程调试服务器并查看是否可以逐步通过 Microsoft 的 PDB...

- 编辑 -

无需单步执行 Microsoft 的代码。我查看了 CompilerResults 的 Errors 集合,其中有 1 项:“无法打开元数据文件 'c:\Windows\System32\aaclient.dll' -- '试图加载一个程序格式不正确。'"

当我让 Directory.GetCurrentDirectory() 获取其他 DLL 时,它使用的是 Windows System32 目录...

- 编辑 -

通过从执行程序集的文件夹中添加引用解决了这个问题:

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

为了获得更大的健壮性,可以添加对二进制文件是否是有效的托管代码程序集的检查。此代码可以通过在两个 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 的输入。我已经解决了这个问题,但忘记更新了。分享给大家,让大家受益。这是 .NET Fusion 在起作用。它缓存程序集加载路径,如果之前从同一位置加载的尝试失败,它甚至不会尝试加载程序集。换句话说:

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 回答