【发布时间】:2018-08-08 04:28:49
【问题描述】:
以下实验代码/项目在 VS2017 中使用 netcore 2.0 和 netstandard 2.0。假设我有两个版本的第三方dll v1.0.0.0 和v2.0.0.0,其中只包含一个类Constants.cs。
//ThirdPartyDependency.dll v1.0.0.0
public class Constants
{
public static readonly string TestValue = "test value v1.0.0.0";
}
//ThirdPartyDependency.dll v2.0.0.0
public class Constants
{
public static readonly string TestValue = "test value v2.0.0.0";
}
然后我创建了自己的名为 AssemblyLoadTest 的解决方案,其中包含:
Wrapper.Abstraction:没有项目引用的类库
namespace Wrapper.Abstraction
{
public interface IValueLoader
{
string GetValue();
}
public class ValueLoaderFactory
{
public static IValueLoader Create(string wrapperAssemblyPath)
{
var assembly = Assembly.LoadFrom(wrapperAssemblyPath);
return (IValueLoader)assembly.CreateInstance("Wrapper.Implementation.ValueLoader");
}
}
}
Wrapper.V1:类库,项目参考 Wrapper.Abstractions 和 dll 参考 ThirdPartyDependency v1.0.0.0
namespace Wrapper.Implementation
{
public class ValueLoader : IValueLoader
{
public string GetValue()
{
return Constants.TestValue;
}
}
}
Wrapper.V2:类库,带有项目引用 Wrapper.Abstractions 和 dll 引用 ThirdPartyDependency v2.0.0.0
namespace Wrapper.Implementation
{
public class ValueLoader : IValueLoader
{
public string GetValue()
{
return Constants.TestValue;
}
}
}
AssemblyLoadTest:带有项目引用 Wrapper.Abstraction 的控制台应用程序
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (s, e) =>
{
Console.WriteLine($"AssemblyResolve: {e.Name}");
if (e.Name.StartsWith("ThirdPartyDependency, Version=1.0.0.0"))
{
return Assembly.LoadFrom(@"v1\ThirdPartyDependency.dll");
}
else if (e.Name.StartsWith("ThirdPartyDependency, Version=2.0.0.0"))
{
//return Assembly.LoadFrom(@"v2\ThirdPartyDependency.dll");//FlagA
return Assembly.LoadFile(@"C:\FULL-PATH-TO\v2\ThirdPartyDependency.dll");//FlagB
}
throw new Exception();
};
var v1 = ValueLoaderFactory.Create(@"v1\Wrapper.V1.dll");
var v2 = ValueLoaderFactory.Create(@"v2\Wrapper.V2.dll");
Console.WriteLine(v1.GetValue());
Console.WriteLine(v2.GetValue());
Console.Read();
}
}
步骤
在 DEBUG 中构建 AssemblyLoadTest
在 DEBUG 中构建 Wrapper.V1 项目,将 Wrapper.V1\bin\Debug\netstandard2.0\ 中的文件复制到 AssemblyLoadTest\bin\Debug\netcoreapp2.0\v1\
在 DEBUG 中构建 Wrapper.V2 项目,将 Wrapper.V2\bin\Debug\netstandard2.0\ 中的文件复制到 AssemblyLoadTest\bin\Debug\netcoreapp2.0\v2\
将 AssemblyLoadTest.Program.Main 中的 FULL-PATH-TO 替换为您在步骤 3 中复制的正确 v2 绝对路径
运行 AssemblyLoadTest - Test1
注释 FlagB 行并取消注释 FlagA 行,运行 AssemblyLoadTest - Test2
注释 AppDomain.CurrentDomain.AssemblyResolve,运行 AssemblyLoadTest - Test3
我的结果和问题:
Test1 成功并按预期打印 v1.0.0.0 和 v2.0.0.0
Test2 在
v2.GetValue()处引发异常
System.IO.FileLoadException: '无法加载文件或程序集 '第三方依赖,版本=2.0.0.0,文化=中性, PublicKeyToken=null'。无法找到或加载特定文件。 (HRESULT 异常:0x80131621)'
问题1:为什么在第一个if 语句中,带绝对路径的LoadFile 可以正常工作,而带相对路径的LoadFrom 不能正常工作,而带相对路径的LoadFrom 适用于v1.0.0.0?
- Test3 在同一个地方出现上述相同的异常,这里我的理解是 CLR 使用以下优先级规则定位程序集:
规则1:检查AppDomain.AssemblyResolve是否注册(最高优先级)
Rule2:否则检查程序集是否已加载。
规则3:否则在文件夹中搜索程序集(可以在probing和codeBase中配置。
在未注册 AssemblyResolve 的 Test3 中,v1.GetValue 有效,因为 Rule1 和 Rule2 为 N/A,AssemblyLoadTest\bin\Debug\netcoreapp2.1\v1 在 Rule3 扫描候选中。执行v2.GetValue时,Rule1仍然是N/A,但是这里应用了Rule2(如果应用了Rule3,为什么会出现异常?)
问题2:为什么使用Wrapper.V2引用ThirdPartyDependency.dll也会忽略版本
<Reference Include="ThirdPartyDependency, Version=2.0.0.0">
<HintPath>..\lib\ThirdPartyDependency\2.0.0.0\ThirdPartyDependency.dll</HintPath>
</Reference>
【问题讨论】:
-
发布到 github coreclr 团队问题,link。
标签: c# .net .net-core clr .net-standard