c# - Resolving an assemblies with different versions -


i'm having assembly resolve issue that's driving me nuts.

so company's product can have many plug in services. team works on these services. have bunch of reusable code in utility assembly (utility.dll).

from time time make improvements or add new features utility.dll. have strict backward compatibility testing make sure new version of assembly works older plug in services.

the problem having resolving deployed version of utility.dll.

let me give example.

utility.dll @ version 1.0.0.0

we create service servicea built referencing utility.dll version 1.0.0.0

we update utility.dll , update version 2.0.0.0

next create service serviceb uses utility.dll 2.0.0.0.

utility.dll version 2.0.0.0 compatible both servicea , serviceb.

i launch our application. deployed version of utility.dll gets loaded.

i launch serviceb. implementation of appdomain.currentdomain.assemblyresolve event gets fired , utility.dll 2.0.0.0 gets returned.

i launch servicea. appdomain.currentdomain.assemblyresolve never gets fired filenotfoundexception utility.dll 1.0.0.0. @ point want resolve utility 2.0.0.0. if version 1.0.0.0 isn't found why doesn't assemblyresolve event fired?

also, can in reverse order launching servicea first , assemblyresolve gets fired , utilty.dll 2.0.0.0 resolved servicea(that built utilty.dll 1.0.0.0). however, if launch serviceb (which built utilty.dll 2.0.0.0) assemblyresolve event never gets fired , filenotfoundexception thrown utility.dll version 1.0.0.0.

what going on? want use deployed version of utility.dll services.

******updated******

public class utilityloader {     private iservicecontext context;      public utilityloader(iservicecontext context)     {         this.context = context;         appdomain.currentdomain.assemblyresolve += currentdomain_assemblyresolve;     }      private bool loaded     {                 {             context.application.log.writeinfo("checking utility...");             assembly asmfound = appdomain.currentdomain.getassemblies().firstordefault(asm => asm.fullname.contains("utility"));             context.application.log.writeinfo(string.format("utility {0} loaded.{1}", asmfound == null ? "is not" : "is", asmfound == null ? string.empty : string.format(" version: {0}", asmfound.getname().version)));              return asmfound != null;         }     }      public bool load()     {         if (loaded)             return true;          string utilitypath = path.combine(session.datadirectory, "utility.dll");          if (file.exists(utilitypath))         {             context.application.log.writeinfo(string.format("utility.dll found."));             filestream stream = file.openread(utilitypath);             byte[] assemblydata = new byte[stream.length];             stream.read(assemblydata, 0, assemblydata.length);             stream.close();              try             {                 assembly.load(assemblydata);             }             catch (exception ex)             {                 context.application.log.writeinfo(string.format("could not load utility: {0}", ex.message));                 throw;             }              return true;         }          return false;     }        private assembly currentdomain_assemblyresolve(object sender, resolveeventargs args)     {         assemblyname asmname = new assemblyname(args.name);          if (asmname.name == "utility")         {             context.application.log.writeinfo("resolving utility");             assembly nuasm = appdomain.currentdomain.getassemblies().firstordefault(asm => asm.fullname.contains("utility"));             context.application.log.writeinfo(string.format("utility {0} loaded.", nuasm == null ? "is not" : "is"));             return nuasm;         }          return null;     }  } 

i calling in each of service plugins.

public void execute(iservicecontext context, serviceparameters serviceparams) {     utilityloader loader = new utilityloader(context);     if (!loader.load())     {         messagebox.show("utility not loaded.", "error", messageboxbuttons.ok, messageboxicon.error);         return;     }      startservice(context, serviceparams); } 

the first service plugin gets called loads fine other service plugin built referencing same version of utility.dll first service plugin loaded. if service plugin called built different version of utility.dll fileloadexception thrown.

another example

servicea built utility 1.0.0.0 serviceb built utility 1.0.0.0 serviceb built utility 2.0.0.0

utility 2.0.0.0 deployed.

user launches servicea first. utility 2.0.0.0 loaded. assemblyresolve event fired. assembly resolved. service launches.

user, within same session, launches serviceb. service b uses same version of utility servicea. service b launches.

user, within same session, launches servicec. servicec built different version of utility. servicec fails load.

user restarts application , attempts load servicec first. servicec loads fine. then, within same session, user tries loan servicea or serviceb , both fail.

for reason when service loaded after initial 1 doesn't fire assemblyresolve again when assembly can't resolved. if event fired handler return loaded version of utility.

difficult know whats going out without more details (are service , service b independent .dll?, or in same .exe assembly?) but, make in way:

1) use appdomain.currentdomain.assemblyresolve mechanism failure detecting. try first without using .net appdomain logic.

mydomain.assemblyresolve += new resolveeventhandler(loader_assemblyresolve);  if (system.io.file.exists(pathtoassembly) == false) {   system.io.file.copy(knownpathtolastversion, pathtoassembly) }  _assembly = assembly.load(assemblyname.getassemblyname(pathtoassembly)); 

2) in loader_assemblyresolve use best known practices time learn web page, right now, shameful lazy url (welcome contributions!):

 private assembly loader_assemblyresolve(object sender, resolveeventargs args)     {         assembly assembly = null;         //1. disconnect event assemblyresolve         _domain.assemblyresolve -= new resolveeventhandler(loader_assemblyresolve);         try         {             //2. not try file without looking first             //   in memory. assemblyresolve fire when             //   assembly loaded             assembly = system.reflection.assembly.load(args.name);             if (assembly != null)             {                 _domain.assemblyresolve += new resolveeventhandler(loader_assemblyresolve);                 return assembly;             }         }         catch         { // ignore load error          }          //3. try file         string filename=getfilename(args.name);         try         {             assembly = system.reflection.assembly.loadfrom(filename);             if (assembly != null)             {                 _domain.assemblyresolve += new resolveeventhandler(loader_assemblyresolve);                 return assembly;             }         }         catch         { // ignore load error          }                     //be sure reconnect event         _domain.assemblyresolve += new resolveeventhandler(loader_assemblyresolve);          return assembly;     } 

i hope helps you.


Comments