Remoting and AppDomains

S

Sam Martin

Hi All,

I've got a problem where my application loads an assembly in the running
AppDomain when it shouldn't.

Ok, I've got a RemotingHost application that configs the remoting stuff and
then...
asks the user for a list of .net DLLs.
the app then copies a these assemblies to a cache folder along with my
RemotingClient app. Once copies i config a AppDomain setup and create a new
AppDomain.
Once created, i loop through the user chosen assemblies and load into the
AppDomain. I then AppDomain.ExecuteAssembly my RemotingClient.

The purpose is so that I can dynamically load and unload assemblies and
report on type information to my main app (in this case the RemotingHost).
Everything works fine in principal, however when I load the DLLs from my
cache folder the assembly is actually loaded in both AppDomains.

I know if i reference a type across AppDomain, it will cause the Framework
to load the assembly in the other AppDomain, but all i'm doing it is loading
it?

Any ideas? (please help:)

TIA
Sam Martin

(code sample below)

System.IO.Directory.CreateDirectory(Application.StartupPath+"\\cache");

// copy my RemotingClient.exe to the cache

// Set up the AppDomainSetup
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Application.StartupPath+"\\cache\\";
setup.ConfigurationFile = "";

// Set up the Evidence
System.Security.Policy.Evidence baseEvidence =
AppDomain.CurrentDomain.Evidence;
System.Security.Policy.Evidence evidence = new
System.Security.Policy.Evidence(baseEvidence);
// evidence.AddAssembly("(some assembly)");

// Create the AppDomain
AppDomain newDomain = AppDomain.CreateDomain("temp", evidence, setup);

foreach(string an in this.listBoxAsmList.Items)
{

// copy the specified assembly to cache

string asmn = an.ToLower().Replace(".dll","");

asmn = MyFuncToGetAsmDisplayName(an);
newDomain.Load(asmn);
}

newDomain.ExecuteAssembly("RemotingClient.exe);
AppDomain.Unload(newDomain);
 
K

Ken Kolda

If you're loading the assemblies using AppDomain.Load(), that function
returns an Assembly object to the AppDomain of the caller, which causes the
caller to load the assembly as well. Read the "remarks" section of the
following documentation:

http://msdn.microsoft.com/library/e...SystemAppDomainClassLoadTopic1.asp?frame=true

One way to force an assembly to be loaded into another AppDomain without it
being loaded into the current one is to use the AppDomain.DoCallback()
method to invoke a delegate that will run in the AppDomain in which you want
the assembly loaded. For example,

class Class1
{
[STAThread]
static void Main(string[] args)
{
AppDomainSetup s = new AppDomainSetup();
s.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
AppDomain d = AppDomain.CreateDomain("TestDomain",
AppDomain.CurrentDomain.Evidence, s);

d.DoCallBack(new CrossAppDomainDelegate(DomainCall));
// ...
}

public static void DomainCall()
{
AppDomain.CurrentDomain.Load("MyAssembly");
}
}

The main thing to make sure of is that your delegate does not reference an
instance method of a MarshalByRef object, or else the assembly will be
loaded in the domain in which that object resides.

Hope that helps -
Ken
 
S

Sam Martin

it all becomes clear.

thanks mate


Ken Kolda said:
If you're loading the assemblies using AppDomain.Load(), that function
returns an Assembly object to the AppDomain of the caller, which causes the
caller to load the assembly as well. Read the "remarks" section of the
following documentation:

http://msdn.microsoft.com/library/e...SystemAppDomainClassLoadTopic1.asp?frame=true

One way to force an assembly to be loaded into another AppDomain without it
being loaded into the current one is to use the AppDomain.DoCallback()
method to invoke a delegate that will run in the AppDomain in which you want
the assembly loaded. For example,

class Class1
{
[STAThread]
static void Main(string[] args)
{
AppDomainSetup s = new AppDomainSetup();
s.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
AppDomain d = AppDomain.CreateDomain("TestDomain",
AppDomain.CurrentDomain.Evidence, s);

d.DoCallBack(new CrossAppDomainDelegate(DomainCall));
// ...
}

public static void DomainCall()
{
AppDomain.CurrentDomain.Load("MyAssembly");
}
}

The main thing to make sure of is that your delegate does not reference an
instance method of a MarshalByRef object, or else the assembly will be
loaded in the domain in which that object resides.

Hope that helps -
Ken



Sam Martin said:
Hi All,

I've got a problem where my application loads an assembly in the running
AppDomain when it shouldn't.

Ok, I've got a RemotingHost application that configs the remoting stuff and
then...
asks the user for a list of .net DLLs.
the app then copies a these assemblies to a cache folder along with my
RemotingClient app. Once copies i config a AppDomain setup and create a new
AppDomain.
Once created, i loop through the user chosen assemblies and load into the
AppDomain. I then AppDomain.ExecuteAssembly my RemotingClient.

The purpose is so that I can dynamically load and unload assemblies and
report on type information to my main app (in this case the RemotingHost).
Everything works fine in principal, however when I load the DLLs from my
cache folder the assembly is actually loaded in both AppDomains.

I know if i reference a type across AppDomain, it will cause the Framework
to load the assembly in the other AppDomain, but all i'm doing it is loading
it?

Any ideas? (please help:)

TIA
Sam Martin

(code sample below)

System.IO.Directory.CreateDirectory(Application.StartupPath+"\\cache");

// copy my RemotingClient.exe to the cache

// Set up the AppDomainSetup
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Application.StartupPath+"\\cache\\";
setup.ConfigurationFile = "";

// Set up the Evidence
System.Security.Policy.Evidence baseEvidence =
AppDomain.CurrentDomain.Evidence;
System.Security.Policy.Evidence evidence = new
System.Security.Policy.Evidence(baseEvidence);
// evidence.AddAssembly("(some assembly)");

// Create the AppDomain
AppDomain newDomain = AppDomain.CreateDomain("temp", evidence, setup);

foreach(string an in this.listBoxAsmList.Items)
{

// copy the specified assembly to cache

string asmn = an.ToLower().Replace(".dll","");

asmn = MyFuncToGetAsmDisplayName(an);
newDomain.Load(asmn);
}

newDomain.ExecuteAssembly("RemotingClient.exe);
AppDomain.Unload(newDomain);
 
S

Sam Martin

ahh, one other thing. how would i specify which assembly to load from the
main appdomain
I could do something like, but even if libraryName is a static property of a
class in the main AppDomain, it's value would be null in the other AppDomain

public static void DomainCall()
{
AppDomain.CurrentDomain.Load(libraryName);
}

you see what i mean, i need to say which assembly to load into the AppDomain
from the calling AppDomain without loading the spec'd assembly.

TIA

Sam Martin

Ken Kolda said:
If you're loading the assemblies using AppDomain.Load(), that function
returns an Assembly object to the AppDomain of the caller, which causes the
caller to load the assembly as well. Read the "remarks" section of the
following documentation:

http://msdn.microsoft.com/library/e...SystemAppDomainClassLoadTopic1.asp?frame=true

One way to force an assembly to be loaded into another AppDomain without it
being loaded into the current one is to use the AppDomain.DoCallback()
method to invoke a delegate that will run in the AppDomain in which you want
the assembly loaded. For example,

class Class1
{
[STAThread]
static void Main(string[] args)
{
AppDomainSetup s = new AppDomainSetup();
s.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
AppDomain d = AppDomain.CreateDomain("TestDomain",
AppDomain.CurrentDomain.Evidence, s);

d.DoCallBack(new CrossAppDomainDelegate(DomainCall));
// ...
}

public static void DomainCall()
{
AppDomain.CurrentDomain.Load("MyAssembly");
}
}

The main thing to make sure of is that your delegate does not reference an
instance method of a MarshalByRef object, or else the assembly will be
loaded in the domain in which that object resides.

Hope that helps -
Ken



Sam Martin said:
Hi All,

I've got a problem where my application loads an assembly in the running
AppDomain when it shouldn't.

Ok, I've got a RemotingHost application that configs the remoting stuff and
then...
asks the user for a list of .net DLLs.
the app then copies a these assemblies to a cache folder along with my
RemotingClient app. Once copies i config a AppDomain setup and create a new
AppDomain.
Once created, i loop through the user chosen assemblies and load into the
AppDomain. I then AppDomain.ExecuteAssembly my RemotingClient.

The purpose is so that I can dynamically load and unload assemblies and
report on type information to my main app (in this case the RemotingHost).
Everything works fine in principal, however when I load the DLLs from my
cache folder the assembly is actually loaded in both AppDomains.

I know if i reference a type across AppDomain, it will cause the Framework
to load the assembly in the other AppDomain, but all i'm doing it is loading
it?

Any ideas? (please help:)

TIA
Sam Martin

(code sample below)

System.IO.Directory.CreateDirectory(Application.StartupPath+"\\cache");

// copy my RemotingClient.exe to the cache

// Set up the AppDomainSetup
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Application.StartupPath+"\\cache\\";
setup.ConfigurationFile = "";

// Set up the Evidence
System.Security.Policy.Evidence baseEvidence =
AppDomain.CurrentDomain.Evidence;
System.Security.Policy.Evidence evidence = new
System.Security.Policy.Evidence(baseEvidence);
// evidence.AddAssembly("(some assembly)");

// Create the AppDomain
AppDomain newDomain = AppDomain.CreateDomain("temp", evidence, setup);

foreach(string an in this.listBoxAsmList.Items)
{

// copy the specified assembly to cache

string asmn = an.ToLower().Replace(".dll","");

asmn = MyFuncToGetAsmDisplayName(an);
newDomain.Load(asmn);
}

newDomain.ExecuteAssembly("RemotingClient.exe);
AppDomain.Unload(newDomain);
 
K

Ken Kolda

In this case, you probably want to do something a bit more sophisticated
using remoting. What I would do is create a class such as:

class AssemblyLoader : MarshalByRefObject
{
public void Load(string assemblyName)
{
AppDomain.CurrentDomain.Load(assemblyName);
}
}

Then, from your main app domain, create an instance of this class in the new
app domain, e.g.

AssemblyLoader loader =
(AssemblyLoader) newDomain.CreateInstanceAndUnwrap("MyAssembly",
"MyAssembly.AssemblyLoader");
loader.Load("PluginAssembly");

The disadvantage of this technique is that your new AppDomain will have to
load the current assembly to get the definition of the AssemblyLoader class.

Hope that helps -
Ken


Sam Martin said:
ahh, one other thing. how would i specify which assembly to load from the
main appdomain
I could do something like, but even if libraryName is a static property of a
class in the main AppDomain, it's value would be null in the other AppDomain

public static void DomainCall()
{
AppDomain.CurrentDomain.Load(libraryName);
}

you see what i mean, i need to say which assembly to load into the AppDomain
from the calling AppDomain without loading the spec'd assembly.

TIA

Sam Martin

Ken Kolda said:
If you're loading the assemblies using AppDomain.Load(), that function
returns an Assembly object to the AppDomain of the caller, which causes the
caller to load the assembly as well. Read the "remarks" section of the
following documentation:
http://msdn.microsoft.com/library/e...SystemAppDomainClassLoadTopic1.asp?frame=true
One way to force an assembly to be loaded into another AppDomain without it
being loaded into the current one is to use the AppDomain.DoCallback()
method to invoke a delegate that will run in the AppDomain in which you want
the assembly loaded. For example,

class Class1
{
[STAThread]
static void Main(string[] args)
{
AppDomainSetup s = new AppDomainSetup();
s.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
AppDomain d = AppDomain.CreateDomain("TestDomain",
AppDomain.CurrentDomain.Evidence, s);

d.DoCallBack(new CrossAppDomainDelegate(DomainCall));
// ...
}

public static void DomainCall()
{
AppDomain.CurrentDomain.Load("MyAssembly");
}
}

The main thing to make sure of is that your delegate does not reference an
instance method of a MarshalByRef object, or else the assembly will be
loaded in the domain in which that object resides.

Hope that helps -
Ken



Sam Martin said:
Hi All,

I've got a problem where my application loads an assembly in the running
AppDomain when it shouldn't.

Ok, I've got a RemotingHost application that configs the remoting
stuff
and
then...
asks the user for a list of .net DLLs.
the app then copies a these assemblies to a cache folder along with my
RemotingClient app. Once copies i config a AppDomain setup and create
a
new
AppDomain.
Once created, i loop through the user chosen assemblies and load into the
AppDomain. I then AppDomain.ExecuteAssembly my RemotingClient.

The purpose is so that I can dynamically load and unload assemblies and
report on type information to my main app (in this case the RemotingHost).
Everything works fine in principal, however when I load the DLLs from my
cache folder the assembly is actually loaded in both AppDomains.

I know if i reference a type across AppDomain, it will cause the Framework
to load the assembly in the other AppDomain, but all i'm doing it is loading
it?

Any ideas? (please help:)

TIA
Sam Martin

(code sample below)

System.IO.Directory.CreateDirectory(Application.StartupPath+"\\cache");

// copy my RemotingClient.exe to the cache

// Set up the AppDomainSetup
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Application.StartupPath+"\\cache\\";
setup.ConfigurationFile = "";

// Set up the Evidence
System.Security.Policy.Evidence baseEvidence =
AppDomain.CurrentDomain.Evidence;
System.Security.Policy.Evidence evidence = new
System.Security.Policy.Evidence(baseEvidence);
// evidence.AddAssembly("(some assembly)");

// Create the AppDomain
AppDomain newDomain = AppDomain.CreateDomain("temp", evidence, setup);

foreach(string an in this.listBoxAsmList.Items)
{

// copy the specified assembly to cache

string asmn = an.ToLower().Replace(".dll","");

asmn = MyFuncToGetAsmDisplayName(an);
newDomain.Load(asmn);
}

newDomain.ExecuteAssembly("RemotingClient.exe);
AppDomain.Unload(newDomain);
 
S

Sam Martin

yeah it does unfortunately.

almost had that working, but found the host (the assembly loader) kept being
loaded too - which i don't want really. otherwise i could have just loaded
everything together in a single appdomain using another appdomain to
effectively restart the app when i wanted to use a dif set of libraries.

shit, & all because you cannot unload an assembly from an appdomain.

thanks anyway

sam

Ken Kolda said:
In this case, you probably want to do something a bit more sophisticated
using remoting. What I would do is create a class such as:

class AssemblyLoader : MarshalByRefObject
{
public void Load(string assemblyName)
{
AppDomain.CurrentDomain.Load(assemblyName);
}
}

Then, from your main app domain, create an instance of this class in the new
app domain, e.g.

AssemblyLoader loader =
(AssemblyLoader) newDomain.CreateInstanceAndUnwrap("MyAssembly",
"MyAssembly.AssemblyLoader");
loader.Load("PluginAssembly");

The disadvantage of this technique is that your new AppDomain will have to
load the current assembly to get the definition of the AssemblyLoader class.

Hope that helps -
Ken


Sam Martin said:
ahh, one other thing. how would i specify which assembly to load from the
main appdomain
I could do something like, but even if libraryName is a static property
of
a
class in the main AppDomain, it's value would be null in the other AppDomain

public static void DomainCall()
{
AppDomain.CurrentDomain.Load(libraryName);
}

you see what i mean, i need to say which assembly to load into the AppDomain
from the calling AppDomain without loading the spec'd assembly.

TIA

Sam Martin

causes
the
http://msdn.microsoft.com/library/e...SystemAppDomainClassLoadTopic1.asp?frame=true
One way to force an assembly to be loaded into another AppDomain
without
it
being loaded into the current one is to use the AppDomain.DoCallback()
method to invoke a delegate that will run in the AppDomain in which
you
want
the assembly loaded. For example,

class Class1
{
[STAThread]
static void Main(string[] args)
{
AppDomainSetup s = new AppDomainSetup();
s.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
AppDomain d = AppDomain.CreateDomain("TestDomain",
AppDomain.CurrentDomain.Evidence, s);

d.DoCallBack(new CrossAppDomainDelegate(DomainCall));
// ...
}

public static void DomainCall()
{
AppDomain.CurrentDomain.Load("MyAssembly");
}
}

The main thing to make sure of is that your delegate does not
reference
create
a into
the
from
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top