我正在尝试构建一个小工具来比较一堆程序集中的类型。为此,我创建了两个子文件夹并将各自的dll放在那里:
..\Dlls\v1.1
..\Dlls\v1.2
其中..
是应用程序文件夹
我还创建了一个代理对象:
public class ProxyDomain : MarshalByRefObject
{
public Assembly LoadFile(string assemblyPath)
{
try
{
//Debug.WriteLine("CurrentDomain = " + AppDomain.CurrentDomain.FriendlyName);
return Assembly.LoadFile(assemblyPath);
}
catch (FileNotFoundException)
{
return null;
}
}
}
并将其用于加载以下例程,该例程应加载一个dll并获取其中声明的所有类型:
private static HashSet<Type> LoadAssemblies(string version)
{
_currentVersion = version;
var path = Path.Combine(Environment.CurrentDirectory, Path.Combine(_assemblyDirectory, version));
var appDomainSetup = new AppDomainSetup
{
ApplicationBase = Environment.CurrentDirectory,
};
var evidence = AppDomain.CurrentDomain.Evidence;
var appDomain = AppDomain.CreateDomain("AppDomain" + version, evidence, appDomainSetup);
var proxyDomainType = typeof(ProxyDomain);
var proxyDomain = (ProxyDomain)appDomain.CreateInstanceAndUnwrap(proxyDomainType.Assembly.FullName, proxyDomainType.FullName);
_currentProxyDomain = proxyDomain;
var assemblies = new HashSet<Type>();
var files = Directory.GetFiles(path, "*.dll");
foreach (var file in files)
{
try
{
var assembly = proxyDomain.LoadFile(file);
if (assembly != null)
{
assemblies.UnionWith(assembly.DefinedTypes.Where(t => t.IsPublic));
}
}
catch (Exception)
{
}
}
return assemblies;
}
到目前为止没有什么不寻常的......但在这种情况下它并没有像这样工作(可能是因为子文件夹)所以我搜索了一下,发现app.config
的设置可能会有所帮助我试图添加两条探测路径:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Dlls\v1.1;Dlls\v1.2" />
</assemblyBinding>
</runtime>
现在已经没有任何FileNotFoundExpection
了,但由于dll具有相同的名称,它只将dll从第一个子目录(v1.1
)加载到两个域中,因此我删除了它而是试图像这样实现AppDomain.CurrentDomain.AssemblyResolve
事件处理程序:
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
{
var path = Path.Combine(Environment.CurrentDirectory, Path.Combine(_assemblyDirectory, _currentVersion));
path = Path.Combine(path, e.Name.Split(',').First());
path = path + ".dll";
var assembly = _currentProxyDomain.LoadFile(path);
return assembly;
};
但不幸的是,我使用这个事件处理程序创建了一个无限循环,每次它尝试加载它找不到的dll时,调用自身。我没有更多的想法我还能尝试什么。
正如@SimonMourier建议我尝试为我的新AppDomains使用自定义.config
,并再创建两个*.config
,如:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Dlls\v1.1" />
</assemblyBinding>
</runtime>
</configuration>
我将它们命名为v1.1.config
和v1.2.config
。然后我设置 new ConfigurationFile
属性:
var appDomainSetup = new AppDomainSetup
{
ApplicationBase = Environment.CurrentDirectory,
ConfigurationFile = Path.Combine(Environment.CurrentDirectory, string.Format("{0}.config", version)),
};
我已将选项Copy to Output Directory
设为Copy always
; - )
它没有用,所以我用Google搜索并尝试了另一个建议:
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", appDomainSetup.ConfigurationFile);
但这也没有帮助。仍然FileNotFoundException
像我的自定义配置那样。
使用SetConfigurationBytes
方法也没有效果:
var domainConfig = @"
<configuration>
<startup>
<supportedRuntime version=""v4.0"" sku="".NETFramework,Version=v4.5"" />
</startup>
<runtime>
<assemblyBinding xmlns=""urn:schemas-microsoft-com:asm.v1"">
<probing privatePath=""Dlls\{0}"" />
</assemblyBinding>
</runtime>
</configuration>";
domainConfig = string.Format(domainConfig, version).Trim();
var probingBytes = Encoding.UTF8.GetBytes(domainConfig);
appDomainSetup.SetConfigurationBytes(probingBytes);
但是,如果我调用GetData
方法,新的appdomain将使用自定义.config:
Debug.WriteLine("Current config: " + AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE"));
它输出我通过ConfigurationFile
这真令人困惑。 Stack Trace显示,尽管GetData
重新调整Assembly.LoadFile
仍然使用原始.config:
===日志:此绑定在默认加载上下文中启动。日志:使用应用程序配置文件:
C:[...] \ BIN \调试\ MyApp.exe.Config
日志:使用主机配置文件:日志:使用
中的机器配置文件C:\的Windows \ Microsoft.NET \框架\ v4.0.30319 \ CONFIG \ machine.config中
。
好的,我做了一些实验,发现通过实施@SimonMourier建议确实有效。 FileNotFoundException
类中的LoadFile
方法引用了ProxyDomain
,但我的应用的Main
方法却没有引发ProxyDomain
。我猜测程序集,类型只允许在public IEnumerable<Type> LoadFile(string assemblyPath)
{
//try
{
// does't throw any exceptions
var assembly = Assembly.LoadFile(assemblyPath);
// returning the assembly itself or its types will throw an exception in the main application
return assembly.DefinedTypes;
}
//catch (FileNotFoundException)
{
// return null;
}
}
上下文中生存,并且不能像我尝试的那样转移到主域中。
private static HashSet<Type> LoadAssemblies(string version)
{
// omitted
foreach (var file in files)
{
//try
{
// the exception occurs here, when transfering types between domains:
var types = proxyDomain.LoadFile(file);
assemblies.UnionWith(types.Where(t => t.IsPublic));
}
}
// omitted
}
主域中的方法:
angular
.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.images = [
{ src : 'http://lorempixel.com/400/200/sports/1' },
{ src : 'http://lorempixel.com/400/200/sports/2' },
{ src : 'http://lorempixel.com/400/200/sports/3' },
{ src : 'http://lorempixel.com/400/200/sports/4' },
{ src : 'http://lorempixel.com/400/200/sports/5' }
];
$scope.result = 60;
$scope.computedIndex = Math.floor($scope.result / 100);
});
我现在需要重写比较算法,至少可以加载程序集; - )
答案 0 :(得分:3)
如果您不想使用不同的强名称重新编译程序集,则可以将它们加载到具有不同安装配置和不同.config文件的不同AppDomain中,就像IIS与多个网站一样,每个AppDomain中的一个,完全独立,全部只托管在一个AppPool进程中 - w3wp.exe。
答案 1 :(得分:0)
强烈的名字你的DLL。 使2 exe运行单独的应用程序域。
否则无法两次引用相同的dll名称。 您必须使用_new.dll重命名新的dll,然后您可以使用完全限定名称的起搏级方法名称格式。
意思是重命名所有v2 dll