|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Cross-AppDomain call problemsI have seen a couple of threads dealing with similar questions, but I haven't found one to answer my question, so here I go: I have a service application that loads a couple of tasks (Plug-Ins you might want to call them). When a task gets executed it will be executed in its own AppDomain to allow a) Easy unloading of DLLs b) Version / Assembly independance to the controlling service The service exposes a support object that implements a specific interface. This object supports (for example) sending emails and relies on a third party component for performing the SMTP tasks. The interface reference to this object is passed to the tasks when being executed (so we have one cross-appdomain call here). The tasks perform their actions and might call back on the supplied interface (cross-appdomain again). However some tasks might require more improved email functionality. So they link against that SMTP component themselves which might be different to the version used by the service. Problem is when one of these tasks actually calls back into the supplied support object, the CLR comes back to me with a version / assembly manifest mismatch exception. I would have thought that when I return to the service AppDomain from my Task AppDomain I would be in "safe land" as the object would be executed with any of its local assemblies (no assembly is installed in the GAC), However to me it seems that when the task calls back to the service, CLR attempts to bind to the task's version of the SMTP component rather than the service's component. Is there any easy way I could get around this? Thanks Kai When you pass an assembly reference across appdomains it forces that
assembly (and possibly all the assemblies that it in turn references) to get loaded in both appdomains. You have to break the chain of aseembly references to avoid the problem you ran into. The easiest way I've found to do this is by defining an inteface assembly that itself has no external dependencies; give it a version number that never changes. Put a copy of this assembly where both appdomains can access it - duplicate copies are ok so long as they are both the same version number. Create a remoted object that implements this interface in the other appdomain and make calls on it. Make all calls to the other appdomain via this interface and be careful to not pass any assembly references through it. For example, if you need to refer to a specific assembly on both sides then pass a string of the assembly name or path as an argument and explicitly load it on both sides. Show quote "Kai Iske" <kai.i***@web.de> wrote in message news:1156777268.744466.88980@b28g2000cwb.googlegroups.com... > Hi, > > I have seen a couple of threads dealing with similar questions, but I > haven't found one to answer my question, so here I go: > > I have a service application that loads a couple of tasks (Plug-Ins you > might want to call them). When a task gets executed it will be executed > in its own AppDomain to allow > > a) Easy unloading of DLLs > b) Version / Assembly independance to the controlling service > > The service exposes a support object that implements a specific > interface. This object supports (for example) sending emails and relies > on a third party component for performing the SMTP tasks. > > The interface reference to this object is passed to the tasks when > being executed (so we have one cross-appdomain call here). The tasks > perform their actions and might call back on the supplied interface > (cross-appdomain again). > > However some tasks might require more improved email functionality. So > they link against that SMTP component themselves which might be > different to the version used by the service. > > Problem is when one of these tasks actually calls back into the > supplied support object, the CLR comes back to me with a version / > assembly manifest mismatch exception. I would have thought that when I > return to the service AppDomain from my Task AppDomain I would be in > "safe land" as the object would be executed with any of its local > assemblies (no assembly is installed in the GAC), However to me it > seems that when the task calls back to the service, CLR attempts to > bind to the task's version of the SMTP component rather than the > service's component. > > Is there any easy way I could get around this? > > Thanks > > Kai > David,
thanks for your feedback, but actually this is exactly what I'm doing. I have a simple interface assembly that defines all the types the two appdomains need to being able to talk to each other without actually knowing about each other. One of the methods accepts an Exception instance though. It could be that if there's an inner Exception in there that I'm passing assembly references accross appdomains?! Kai David Levine wrote: Show quote > When you pass an assembly reference across appdomains it forces that > assembly (and possibly all the assemblies that it in turn references) to get > loaded in both appdomains. You have to break the chain of aseembly > references to avoid the problem you ran into. > > The easiest way I've found to do this is by defining an inteface assembly > that itself has no external dependencies; give it a version number that > never changes. Put a copy of this assembly where both appdomains can access > it - duplicate copies are ok so long as they are both the same version > number. Create a remoted object that implements this interface in the other > appdomain and make calls on it. Make all calls to the other appdomain via > this interface and be careful to not pass any assembly references through > it. > > For example, if you need to refer to a specific assembly on both sides then > pass a string of the assembly name or path as an argument and explicitly > load it on both sides. > > "Kai Iske" <kai.i***@web.de> wrote in message > news:1156777268.744466.88980@b28g2000cwb.googlegroups.com... > > Hi, > > > > I have seen a couple of threads dealing with similar questions, but I > > haven't found one to answer my question, so here I go: > > > > I have a service application that loads a couple of tasks (Plug-Ins you > > might want to call them). When a task gets executed it will be executed > > in its own AppDomain to allow > > > > a) Easy unloading of DLLs > > b) Version / Assembly independance to the controlling service > > > > The service exposes a support object that implements a specific > > interface. This object supports (for example) sending emails and relies > > on a third party component for performing the SMTP tasks. > > > > The interface reference to this object is passed to the tasks when > > being executed (so we have one cross-appdomain call here). The tasks > > perform their actions and might call back on the supplied interface > > (cross-appdomain again). > > > > However some tasks might require more improved email functionality. So > > they link against that SMTP component themselves which might be > > different to the version used by the service. > > > > Problem is when one of these tasks actually calls back into the > > supplied support object, the CLR comes back to me with a version / > > assembly manifest mismatch exception. I would have thought that when I > > return to the service AppDomain from my Task AppDomain I would be in > > "safe land" as the object would be executed with any of its local > > assemblies (no assembly is installed in the GAC), However to me it > > seems that when the task calls back to the service, CLR attempts to > > bind to the task's version of the SMTP component rather than the > > service's component. > > > > Is there any easy way I could get around this? > > > > Thanks > > > > Kai > > There must be something in one of the objects defined in the interface that
is causing the assembly to get loaded. An inner exception would not be it unless it was a custom exception type defined in that assembly, and that would only occur when the exception object was created with the inner custom exception I would look at all the arguments defined in the interface to ensure that none of the types are leaking across the appdomain boundary. If you could post a code snippet that duplicates the problem it would help. Show quote "Kai Iske" <kai.i***@web.de> wrote in message news:1157026523.056546.66380@m73g2000cwd.googlegroups.com... > David, > > thanks for your feedback, but actually this is exactly what I'm doing. > I have a simple interface assembly that defines all the types the two > appdomains need to being able to talk to each other without actually > knowing about each other. > > One of the methods accepts an Exception instance though. It could be > that if there's an inner Exception in there that I'm passing assembly > references accross appdomains?! > > Kai > > David Levine wrote: >> When you pass an assembly reference across appdomains it forces that >> assembly (and possibly all the assemblies that it in turn references) to >> get >> loaded in both appdomains. You have to break the chain of aseembly >> references to avoid the problem you ran into. >> >> The easiest way I've found to do this is by defining an inteface assembly >> that itself has no external dependencies; give it a version number that >> never changes. Put a copy of this assembly where both appdomains can >> access >> it - duplicate copies are ok so long as they are both the same version >> number. Create a remoted object that implements this interface in the >> other >> appdomain and make calls on it. Make all calls to the other appdomain via >> this interface and be careful to not pass any assembly references through >> it. >> >> For example, if you need to refer to a specific assembly on both sides >> then >> pass a string of the assembly name or path as an argument and explicitly >> load it on both sides. >> >> "Kai Iske" <kai.i***@web.de> wrote in message >> news:1156777268.744466.88980@b28g2000cwb.googlegroups.com... >> > Hi, >> > >> > I have seen a couple of threads dealing with similar questions, but I >> > haven't found one to answer my question, so here I go: >> > >> > I have a service application that loads a couple of tasks (Plug-Ins you >> > might want to call them). When a task gets executed it will be executed >> > in its own AppDomain to allow >> > >> > a) Easy unloading of DLLs >> > b) Version / Assembly independance to the controlling service >> > >> > The service exposes a support object that implements a specific >> > interface. This object supports (for example) sending emails and relies >> > on a third party component for performing the SMTP tasks. >> > >> > The interface reference to this object is passed to the tasks when >> > being executed (so we have one cross-appdomain call here). The tasks >> > perform their actions and might call back on the supplied interface >> > (cross-appdomain again). >> > >> > However some tasks might require more improved email functionality. So >> > they link against that SMTP component themselves which might be >> > different to the version used by the service. >> > >> > Problem is when one of these tasks actually calls back into the >> > supplied support object, the CLR comes back to me with a version / >> > assembly manifest mismatch exception. I would have thought that when I >> > return to the service AppDomain from my Task AppDomain I would be in >> > "safe land" as the object would be executed with any of its local >> > assemblies (no assembly is installed in the GAC), However to me it >> > seems that when the task calls back to the service, CLR attempts to >> > bind to the task's version of the SMTP component rather than the >> > service's component. >> > >> > Is there any easy way I could get around this? >> > >> > Thanks >> > >> > Kai >> > > That's exactly it: It might be that I pass a custom exception accross
appdomains. I just checked my code again and in some cases could happen that I pass custom assemblies accross. I have now changed it to only pass the raw base types (Message, StackTrace etc.) accross using my own wrapper. Thanks for the help / hint Kai David Levine wrote: Show quote > There must be something in one of the objects defined in the interface that > is causing the assembly to get loaded. An inner exception would not be it > unless it was a custom exception type defined in that assembly, and that > would only occur when the exception object was created with the inner custom > exception > > I would look at all the arguments defined in the interface to ensure that > none of the types are leaking across the appdomain boundary. > > If you could post a code snippet that duplicates the problem it would help. > > > > "Kai Iske" <kai.i***@web.de> wrote in message > news:1157026523.056546.66380@m73g2000cwd.googlegroups.com... > > David, > > > > thanks for your feedback, but actually this is exactly what I'm doing. > > I have a simple interface assembly that defines all the types the two > > appdomains need to being able to talk to each other without actually > > knowing about each other. > > > > One of the methods accepts an Exception instance though. It could be > > that if there's an inner Exception in there that I'm passing assembly > > references accross appdomains?! > > > > Kai > > > > David Levine wrote: > >> When you pass an assembly reference across appdomains it forces that > >> assembly (and possibly all the assemblies that it in turn references) to > >> get > >> loaded in both appdomains. You have to break the chain of aseembly > >> references to avoid the problem you ran into. > >> > >> The easiest way I've found to do this is by defining an inteface assembly > >> that itself has no external dependencies; give it a version number that > >> never changes. Put a copy of this assembly where both appdomains can > >> access > >> it - duplicate copies are ok so long as they are both the same version > >> number. Create a remoted object that implements this interface in the > >> other > >> appdomain and make calls on it. Make all calls to the other appdomain via > >> this interface and be careful to not pass any assembly references through > >> it. > >> > >> For example, if you need to refer to a specific assembly on both sides > >> then > >> pass a string of the assembly name or path as an argument and explicitly > >> load it on both sides. > >> > >> "Kai Iske" <kai.i***@web.de> wrote in message > >> news:1156777268.744466.88980@b28g2000cwb.googlegroups.com... > >> > Hi, > >> > > >> > I have seen a couple of threads dealing with similar questions, but I > >> > haven't found one to answer my question, so here I go: > >> > > >> > I have a service application that loads a couple of tasks (Plug-Ins you > >> > might want to call them). When a task gets executed it will be executed > >> > in its own AppDomain to allow > >> > > >> > a) Easy unloading of DLLs > >> > b) Version / Assembly independance to the controlling service > >> > > >> > The service exposes a support object that implements a specific > >> > interface. This object supports (for example) sending emails and relies > >> > on a third party component for performing the SMTP tasks. > >> > > >> > The interface reference to this object is passed to the tasks when > >> > being executed (so we have one cross-appdomain call here). The tasks > >> > perform their actions and might call back on the supplied interface > >> > (cross-appdomain again). > >> > > >> > However some tasks might require more improved email functionality. So > >> > they link against that SMTP component themselves which might be > >> > different to the version used by the service. > >> > > >> > Problem is when one of these tasks actually calls back into the > >> > supplied support object, the CLR comes back to me with a version / > >> > assembly manifest mismatch exception. I would have thought that when I > >> > return to the service AppDomain from my Task AppDomain I would be in > >> > "safe land" as the object would be executed with any of its local > >> > assemblies (no assembly is installed in the GAC), However to me it > >> > seems that when the task calls back to the service, CLR attempts to > >> > bind to the task's version of the SMTP component rather than the > >> > service's component. > >> > > >> > Is there any easy way I could get around this? > >> > > >> > Thanks > >> > > >> > Kai > >> > > > Glad I could help
Show quote "Kai Iske" <kai.i***@web.de> wrote in message news:1158649917.151657.6150@m73g2000cwd.googlegroups.com... > That's exactly it: It might be that I pass a custom exception accross > appdomains. I just checked my code again and in some cases could happen > that I pass custom assemblies accross. I have now changed it to only > pass the raw base types (Message, StackTrace etc.) accross using my own > wrapper. > > Thanks for the help / hint > > Kai > > David Levine wrote: >> There must be something in one of the objects defined in the interface >> that >> is causing the assembly to get loaded. An inner exception would not be it >> unless it was a custom exception type defined in that assembly, and that >> would only occur when the exception object was created with the inner >> custom >> exception >> >> I would look at all the arguments defined in the interface to ensure that >> none of the types are leaking across the appdomain boundary. >> >> If you could post a code snippet that duplicates the problem it would >> help. >> >> >> >> "Kai Iske" <kai.i***@web.de> wrote in message >> news:1157026523.056546.66380@m73g2000cwd.googlegroups.com... >> > David, >> > >> > thanks for your feedback, but actually this is exactly what I'm doing. >> > I have a simple interface assembly that defines all the types the two >> > appdomains need to being able to talk to each other without actually >> > knowing about each other. >> > >> > One of the methods accepts an Exception instance though. It could be >> > that if there's an inner Exception in there that I'm passing assembly >> > references accross appdomains?! >> > >> > Kai >> > >> > David Levine wrote: >> >> When you pass an assembly reference across appdomains it forces that >> >> assembly (and possibly all the assemblies that it in turn references) >> >> to >> >> get >> >> loaded in both appdomains. You have to break the chain of aseembly >> >> references to avoid the problem you ran into. >> >> >> >> The easiest way I've found to do this is by defining an inteface >> >> assembly >> >> that itself has no external dependencies; give it a version number >> >> that >> >> never changes. Put a copy of this assembly where both appdomains can >> >> access >> >> it - duplicate copies are ok so long as they are both the same version >> >> number. Create a remoted object that implements this interface in the >> >> other >> >> appdomain and make calls on it. Make all calls to the other appdomain >> >> via >> >> this interface and be careful to not pass any assembly references >> >> through >> >> it. >> >> >> >> For example, if you need to refer to a specific assembly on both sides >> >> then >> >> pass a string of the assembly name or path as an argument and >> >> explicitly >> >> load it on both sides. >> >> >> >> "Kai Iske" <kai.i***@web.de> wrote in message >> >> news:1156777268.744466.88980@b28g2000cwb.googlegroups.com... >> >> > Hi, >> >> > >> >> > I have seen a couple of threads dealing with similar questions, but >> >> > I >> >> > haven't found one to answer my question, so here I go: >> >> > >> >> > I have a service application that loads a couple of tasks (Plug-Ins >> >> > you >> >> > might want to call them). When a task gets executed it will be >> >> > executed >> >> > in its own AppDomain to allow >> >> > >> >> > a) Easy unloading of DLLs >> >> > b) Version / Assembly independance to the controlling service >> >> > >> >> > The service exposes a support object that implements a specific >> >> > interface. This object supports (for example) sending emails and >> >> > relies >> >> > on a third party component for performing the SMTP tasks. >> >> > >> >> > The interface reference to this object is passed to the tasks when >> >> > being executed (so we have one cross-appdomain call here). The tasks >> >> > perform their actions and might call back on the supplied interface >> >> > (cross-appdomain again). >> >> > >> >> > However some tasks might require more improved email functionality. >> >> > So >> >> > they link against that SMTP component themselves which might be >> >> > different to the version used by the service. >> >> > >> >> > Problem is when one of these tasks actually calls back into the >> >> > supplied support object, the CLR comes back to me with a version / >> >> > assembly manifest mismatch exception. I would have thought that when >> >> > I >> >> > return to the service AppDomain from my Task AppDomain I would be in >> >> > "safe land" as the object would be executed with any of its local >> >> > assemblies (no assembly is installed in the GAC), However to me it >> >> > seems that when the task calls back to the service, CLR attempts to >> >> > bind to the task's version of the SMTP component rather than the >> >> > service's component. >> >> > >> >> > Is there any easy way I could get around this? >> >> > >> >> > Thanks >> >> > >> >> > Kai >> >> > >> > > |
|||||||||||||||||||||||