c# - How can I load two versions of same assemblies into two different domains from two different subfolders? -
i'm trying build small tool comparing types in bunch of assemblies. purpose created 2 subfolders , put respective dlls there:
..\dlls\v1.1
..\dlls\v1.2
where ..
application folder
i created proxy object:
public class proxydomain : marshalbyrefobject { public assembly loadfile(string assemblypath) { try { //debug.writeline("currentdomain = " + appdomain.currentdomain.friendlyname); return assembly.loadfile(assemblypath); } catch (filenotfoundexception) { return null; } } }
and used loading in following routine should load dll , types declared in it:
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; }
so far nothing unusual... didn't work in case (probably because of subfolders) searched bit , found settting in app.config
might tried add 2 probing paths:
<runtime> <assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatepath="dlls\v1.1;dlls\v1.2" /> </assemblybinding> </runtime>
now there wasn't filenotfoundexpection
s anymore dlls have same names loaded dlls first subdirectory (v1.1
) both domains removed , instead tried implement appdomain.currentdomain.assemblyresolve
event handler that:
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; };
but unfortunatelly event handler created infinite loop , calls itself each time tries load dll cannot find. have no more ideas else try.
update-1
as @simonmourier suggested tried use custom .config
new appdomains , created 2 more *.config
s like:
<?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>
i named them v1.1.config
, v1.2.config
. set new configurationfile
property:
var appdomainsetup = new appdomainsetup { applicationbase = environment.currentdirectory, configurationfile = path.combine(environment.currentdirectory, string.format("{0}.config", version)), };
i've set option copy output directory
copy always
;-)
it didn't work googled , tried suggestion:
appdomain.currentdomain.setdata("app_config_file", appdomainsetup.configurationfile);
but didn't either. still filenotfoundexception
custom configs weren't there.
using setconfigurationbytes
method instead had no effect:
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);
however if call getdata
method new appdomain uses custom .config:
debug.writeline("current config: " + appdomain.currentdomain.getdata("app_config_file"));
it outputs path set via configurationfile
update-2
this confusing. stack trace reveals despite of getdata
returs assembly.loadfile
still uses original .config:
=== log: bind starts in default load context. log: using application configuration file:
c:[...]\bin\debug\myapp.exe.config
log: using host configuration file: log: using machine configuration file from
c:\windows\microsoft.net\framework\v4.0.30319\config\machine.config.
update-3
ok, did more experimenting , found out implementing @simonmourier suggestion indeed worked. filenotfoundexception
wasn't thrown loadfile
method in proxydomain
class in main
method of app. gues assembly , types allowed live within proxydomain
context , cannot transfered main domain have tried.
public ienumerable<type> loadfile(string assemblypath) { //try { // does't throw exceptions var assembly = assembly.loadfile(assemblypath); // returning assembly or types throw exception in main application return assembly.definedtypes; } //catch (filenotfoundexception) { // return null; } }
method in main domain:
private static hashset<type> loadassemblies(string version) { // omitted foreach (var file in files) { //try { // exception occurs here, when transfering types between domains: var types = proxydomain.loadfile(file); assemblies.unionwith(types.where(t => t.ispublic)); } } // omitted }
i'll need rewrite comparison algorithm @ least assemblies can loaded ;-)
if don't want recompile assemblies different strong name, can load them different appdomains, different setup configuration, , different .config files, iis multiple web sites, each 1 in 1 appdomain, independent, hosted in 1 apppool process - w3wp.exe.
Comments
Post a Comment