我正在将巨大的32位桌面(winforms)代码库从.NetFramework462迁移到.Net6。当从VisualStudio运行时,代码本身在迁移后运行良好。我们有大约150个csprojs,其中一些dll在多个可执行文件中共享,因此在安装过程中,我们将共享程序集放在C:ProgramFiles (x86)MyProgramAssemblies
中,而不是将每个程序集复制到每个程序的子文件夹中。
我们有自定义的MyAssemblyLoader
,如果应用程序根文件夹中缺少程序集,它可以正确地从Assemblies
文件夹加载程序集。我们在程序的静态构造函数中注册我们的程序集加载器来处理AssemblyResolve
事件,如下所示:
static class Program
{
private static MyAssemblyResolver _assemblyResolver = new MyAssemblyResolver();
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => _assemblyResolver.AssemblyResolve(args.Name);
}
// Main() and other code is here
}
问题是,当我在.NetFramework462下构建程序并从binDebug
文件夹中删除一个依赖dll时,它会正确地从Assemblies
文件夹中加载它。我可以在静态构造函数中设置一个断点,并查看它是否被调用。在.Net 6中的相同场景中,我甚至在运行静态构造函数之前就得到了System.IO.FileNotFoundException: 'Could not load file or assembly'
。异常没有堆栈跟踪,也根本不进入静态构造函数,就像异常在调用之前就被抛出一样。
我试图加载一些其他程序集,这些程序集对于项目从Assemblies
文件夹和即时窗口中的.Net6中的MyAssembliesLoader
运行是不必要的,它运行得很好。
以下是关于如何在csprojs中引用它的详细信息(我认为这对运行时解析器来说并不重要):在.Net6中,我有SDK csprojs,通过一个共享项目引用了缺失的dll(dll在csproj中没有直接引用)
<ProjectReference Include="OneOfSharedProjects.csproj" />
和在OneOfSharedProjects.csproj
中
<ProjectReference Include="MissingDLL.csproj" />
在.NetFramework462中,该项目直接引用
<ProjectReference Include="MissingDLL.csproj">
<Project>{12345678-FFBC-419B-AEAB-3A9B1A4D4847}</Project>
<Name>MissingDLL</Name>
</ProjectReference>
Assemblies
文件夹路径是在运行时解析的,所以我希望避免在配置文件中硬编码路径。如何从.Net 6中的自定义文件夹加载引用的库?
PS:
- 我们的库没有在GAC中注册,所以情况并非如此
- 将
AssemblyResolve
赋值从静态构造函数移到Main()
没有帮助。代码的行为与以前一样(调用Main()
之前的异常)
好的,我发现了问题。看起来问题是直接引用了Main()
方法中缺少库的类。让我们假设类C
在丢失的库中。有这样的主要:
class Program
{
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += (s, e) => _assemblyResolver.AssemblyResolve(e.Name);
}
static void Main()
{
C c = new C();
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
将不起作用,因为在添加程序集解析器作为事件处理程序之前,.Net6尝试加载包含C
定义的库。但如果不直接使用缺失库中的类,问题就消失了。示例:
class Program
{
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += (s, e) => _assemblyResolver.AssemblyResolve(e.Name);
}
static void Main()
{
NewMethod();
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
private static void NewMethod()
{
C c = new C();
}
}
现在,即使dll被移动到AssemblyResolver可以找到它的其他地方,代码也会很好地工作