Home All Groups Group Topic Archive Search About

Cross-AppDomain call problems

Author
28 Aug 2006 3:01 PM
Kai Iske
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

Author
29 Aug 2006 12:32 PM
David Levine
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
>
Author
31 Aug 2006 12:15 PM
Kai Iske
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
> >
Author
2 Sep 2006 10:52 AM
David Levine
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
>> >
>
Author
19 Sep 2006 7:11 AM
Kai Iske
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
> >> >
> >
Author
19 Sep 2006 9:42 AM
David Levine
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
>> >> >
>> >
>

AddThis Social Bookmark Button