首先,我需要强调的是,这与this thread中的问题略有不同。此外,安装KB2468871也无济于事。
我试图尽可能地简化这个问题。一般来说,它是关于使用Assembly.LoadFile(...)在桌面应用程序中加载PCL程序集。
假设有一个.NET 4.0控制台应用程序(称为“C”)。它引用了.NET 4.0程序集(称为“N4”)和PCL程序集(称为“PCL”)。
其中N4看起来像这样:
using System.Linq;
namespace N4
{
public class ClassInN4
{
public static string Greet()
{
return new string(
"hello from N4"
.ToCharArray()
.Select(char.ToUpper)
.ToArray()
);
}
}
}
PCL看起来像这样:
using System.Linq;
namespace PCL
{
public class ClassInPCL
{
public static string Greet()
{
return new string(
"hello from pcl"
.ToCharArray()
.Select(char.ToUpper)
.ToArray()
);
}
}
}
和C看起来像这样:
using System;
using System.IO;
using System.Reflection;
using N4;
using PCL;
namespace C
{
internal class Program
{
private static void Main(string[] args)
{
Test();
Console.ReadLine();
}
private static void Test()
{
Test("N4", ClassInN4.Greet);
Test("PCL", ClassInPCL.Greet);
}
private static void Test(
string title,
Func<string> generator)
{
try
{
Console.WriteLine(
"{0}: {1}", title, generator());
}
catch (Exception e)
{
Console.WriteLine(
"{0}: {1} -> {2}", title, e.GetType(), e.Message);
}
}
}
}
运行此应用程序时,您将获得绝对正确的结果:
N4: HELLO FROM N4
PCL: HELLO FROM PCL
让我们在Program.Main中将AssemblyResolve事件添加到CurrentDomain:
AppDomain.CurrentDomain.AssemblyResolve += (_, a) => {
var fileName = Path.GetFullPath(
new AssemblyName(a.Name).Name + ".data");
Console.WriteLine("Probing '{0}'", fileName);
return
File.Exists(fileName)
? Assembly.LoadFile(fileName)
: null;
};
那么,如果无法找到程序集,它会尝试从“.data”文件加载它。
让我们去应用程序文件夹并将“N4.dll”重命名为“N4.data”并运行“C.exe”。
Probing 'C:\xxx\C\bin\Debug\N4.data'
N4: HELLO FROM N4
PCL: HELLO FROM PCL
所以它通过AssemblyResolve并最终加载“N4.data”并且和原始版本一样好。
让我们将“N4.data”还原为“N4.dll”并将“PCL.dll”重命名为“PCL.data”并...
Probing 'C:\xxx\C\bin\Debug\PCL.data'
N4: HELLO FROM N4
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
PCL: System.IO.FileNotFoundException -> Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The system cannot find the file specified.
请注意PCL程序集加载得很好,问题是,它只能找不到它的依赖项(System.Core)了。
就像Assembly.LoadFile(fileName)一样,如果加载的程序集是可移植的,则为no-no。
有人有这个问题吗?有人解决了这个问题吗?
您可以找到所有文件here。
修改 感谢leppie强迫我检查其他选项。当我回答“是的,是的,我试过”时,我其实想确定我不会撒谎。显然值得一试。
来自Suzanne Cook's .NET CLR Notes:
小心 - 这些不是一回事。
LoadFrom()经过Fusion,可以重定向到另一个路径,但是如果已经在LoadFrom上下文中加载了相同的身份,则可以使用相同的身份。 LoadFile()根本没有通过Fusion绑定 - 加载器只是继续并正好加载*调用者请求的内容。它不使用Load或LoadFrom上下文。
答案 0 :(得分:5)
当被要求提供System.Core
版本时,您可以从version 4.0.0.0 for .NET Framework 4.0
事件返回您平台的AssemblyResolve
大会(例如2.0.5.0
)。
我正在通过Load(byte[])
加载存储为资源的所有引用程序集,这些程序集也无法解析2.0.5.0
程序集,我从System
检索了System.Core
和AppDomain.CurrentDomain.GetAssemblies()
{1}}。
答案 1 :(得分:3)
我认为你得到这些问题是因为:
您收到异常是因为您没有获得最新的.NET更新。
请注意WSUS部分 - 您可能认为您拥有最新的更新,但不会导致您的WSUS服务器过期。
这个补丁可能有所帮助,但你最好只获得所有.net更新:
http://support.microsoft.com/kb/2468871
(来自上面的评论)
尝试使用LoadFrom(...)而不是LoadFile(...)/ Load(byte [])并查看是否可以解决您的问题? :)
答案 2 :(得分:1)
我遇到了同样的问题并最终得到了以下解决方案:在动态加载PCL程序集之前调用以下代码。
Assembly.Load("System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");
Assembly.Load("System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");
如果在加载PCL程序集时缺少任何其他依赖项,则只需在上面的代码中添加一行。 出于某些奇怪和不可理解的原因,它有效。