# Why does AppDomain.CreateInstanceAndUnwrap(..) work and AppDomain.CreateInstanceFrom(...).UnWrap doesn't?

### Question

• Why does AppDomain.CreateInstanceAndUnwrap(..) work and AppDomain.CreateInstanceFrom(...).UnWrap doesn't?

I'm trying to load an assembly in a AppDomain. The AppDomain.CreateInstanceAndUnwrap works but only when the assembly is in the GAC. I do not want to use the GAC so I've tried to use the AppDomain.CreateInstanceFrom and then use the ObjectHandle.Unwrap() to ge the Object but this fails when I try to cast it to my Object with:

Unable to cast transparent proxy to type 'Configuration.CompileProxy.Compiler'.

Here's the code:

AppDomain ad = AppDomain.CreateDomain("Temp Domain"); // create a new
try
{
//Configuration.CompileProxy.Compiler galaxyCompiler = (Configuration.CompileProxy.Compiler)ad.CreateInstanceAndUnwrap("Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2", "Configuration.CompileProxy.Compiler");//GAC version

//Configuration.CompileProxy.Compiler galaxyCompiler = ((Configuration.CompileProxy.Compiler)ad.CreateInstanceFrom("C:\\GalaxyCompileProxy\\bin\\Debug\\Configuration.CompileProxy.dll", "Avaeon.Configuration.CompileProxy.Compiler").Unwrap());//Direct version

Wednesday, August 23, 2006 3:14 PM

• Solution found.
The solution is to subscribe to the AssemblyResolve Event for the first AppDomain (this is if you use the CreateInstanceAndUnWrap() which also requires you to set the AppBase of your new AppDomain to the location of your assemblies).

(I did notice an infinite loop when subscribing to this event before, maybe it was because I was using CreateInstanceFromAndUnWrap()).

[CODE] private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string shortAssemblyName = args.Name.Substring(0, args.Name.IndexOf(','));
string fileName = Path.Combine(projectDir, shortAssemblyName + ".dll");
if (File.Exists(fileName))
{
Assembly result = Assembly.LoadFrom(fileName);
return result;
}
else
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;

}
[/CODE]

this sets the location to be that of the current VS project, because this is launched from a build task it is required to locate the current project.

Tuesday, August 29, 2006 3:12 PM

### All replies

• I don't understand this, if I drop all the dependant assemblies into the VS installation dir , C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies , then all works fine using

AppDomain ad = AppDomain.CreateDomain("Compiling");
Configuration.CompileProxy.Compiler compiler = (Configuration.CompileProxy.Compiler)ad.CreateInstanceAndUnwrap("Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2", "Configuration.CompileProxy.Compiler");

And the same applies if I simple add the assembly, Configuration.CompileProxy.dll, to the GAC on it's own.

I've tried appending the paths of the AppDomain too using

and dropping all the depentant assemlies into that current directory but that doesn't work either!!!!

Any one have any idea what the problem is. I've looked at various articals and all use the example above or something similar. :confused:

Thursday, August 24, 2006 2:59 PM
• Probably because you're using a path when loading the assembly. http://www.gotdotnet.com/team/clr/LoadFromIsolation.aspx You can use fuslogvw.exe to see exactly what happens.
Monday, August 28, 2006 11:47 AM
• Hi Lucian, you're the first to reply and I am grateful,  i thought I was alone here for the past week.
I've come across the article before, so if I use CreateInstanceFromAndUnWrap() it behaves like LoadFrom() and I cannot perform a cast on the result, is that correct? so how else can I invoke the method in an instance of my remote object is the assembly is not in the GAC?

I've tried setting the AppBase to the location of my assemblies, but no good, still get the type cast error

AppDomainSetup appSetup = new AppDomainSetup();
appSetup.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory;
AppDomain ad = AppDomain.CreateDomain("Compiling Gravity", null, appSetup);
Avaeon.Configuration.CompileProxy.Compiler galaxyCompiler = (Avaeon.Configuration.CompileProxy.Compiler)ad.CreateInstanceAndUnwrap("Avaeon.Configuration.CompileProxy", "Avaeon.Configuration.CompileProxy.Compiler");

I've been playing with the fuslogvw this morning, here is the log, there are 5 log entries in total, here are the last 2, the others appear as Visual Studio type logs

Again the error is
Error: Unable to cast transparent proxy to type 'Avaeon.Configuration.CompileProxy.Compiler'.

LOG # 1
*** Assembly Binder Log Entry  (8/28/2006 @ 3:20:44 PM) ***The operation was successful.Bind result: hr = 0x0. The operation completed successfully.Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dllRunning under executable  C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe--- A detailed error log follows. === Pre-bind state information ===LOG: User = AVAEON\nfallonLOG: DisplayName = Avaeon.Configuration.CompileProxy (Partial)LOG: Appbase = file:///C:/safewaygalaxy/MetadataLOG: Initial PrivatePath = C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\LOG: Dynamic Base = NULLLOG: Cache Base = NULLLOG: AppName = NULLCalling assembly : (Unknown).===LOG: This bind starts in default load context.LOG: Using application configuration file: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe.ConfigLOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy.DLL, because the location falls outside of the appbase.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy/Avaeon.Configuration.CompileProxy.DLL, because the location falls outside of the appbase.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy.EXE, because the location falls outside of the appbase.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy/Avaeon.Configuration.CompileProxy.EXE, because the location falls outside of the appbase.LOG: Attempting download of new URL file:///C:/safewaygalaxy/Metadata/Avaeon.Configuration.CompileProxy.DLL.LOG: Assembly download was successful. Attempting setup of file: C:\safewaygalaxy\Metadata\Avaeon.Configuration.CompileProxy.dllLOG: Entering run-from-source setup phase.LOG: Assembly Name is: Avaeon.Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2LOG: A partially-specified assembly bind succeeded from the application directory. Need to re-apply policy.LOG: Using application configuration file: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe.ConfigLOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.LOG: Post-policy reference: Avaeon.Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2LOG: GAC Lookup was unsuccessful.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy.DLL, because the location falls outside of the appbase.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy/Avaeon.Configuration.CompileProxy.DLL, because the location falls outside of the appbase.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy.EXE, because the location falls outside of the appbase.WRN: Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy/Avaeon.Configuration.CompileProxy.EXE, because the location falls outside of the appbase.LOG: Binding succeeds. Returns assembly from C:\safewaygalaxy\Metadata\Avaeon.Configuration.CompileProxy.dll.------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------LOG # 2*** Assembly Binder Log Entry  (8/28/2006 @ 3:20:44 PM) ***The operation failed.Bind result: hr = 0x80070002. The system cannot find the file specified.Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dllRunning under executable  C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe--- A detailed error log follows. === Pre-bind state information ===LOG: User = AVAEON\nfallonLOG: DisplayName = Avaeon.Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2 (Fully-specified)LOG: Appbase = file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/LOG: Initial PrivatePath = NULLLOG: Dynamic Base = NULLLOG: Cache Base = NULLLOG: AppName = NULLCalling assembly : (Unknown).===LOG: This bind starts in default load context.LOG: Using application configuration file: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe.ConfigLOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.LOG: The same bind was seen before, and was failed with hr = 0x80070002.ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).LOG: Assembly is loaded in default load context.

Monday, August 28, 2006 2:32 PM
• Your custom AppDomain can find the assembly and your setting of PrivateBinPath is not useful and is ignored: LOG: Appbase = file:///C:/safewaygalaxy/Metadata Not probing location file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/Avaeon.Configuration.CompileProxy.DLL, because the location falls outside of the appbase.

LOG: Binding succeeds. Returns assembly from C:\safewaygalaxy\Metadata\Avaeon.Configuration.CompileProxy.dll

The VS AppDomain cannot find the assembly: LOG: Appbase = file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/, LOG: The same bind was seen before, and was failed with hr = 0x80070002.

So you either use the same Appbase for both AppDomains or you put the assembly in each Appbase directory and let the CLR find them.

Monday, August 28, 2006 2:46 PM
• Thanks again Lucian,
I haven't changed the AppBase a second time, it is the same AppDomain!

Adding the assemblies to the file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/ is not an option.
Using the
Avaeon.Configuration.CompileProxy
LOG: DisplayName = Avaeon.Configuration.CompileProxy
But it creates a second log file for what looks like a version of the same assembly
LOG: DisplayName = Avaeon.Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2I don't understand what's happening here, why there are 2 log entries, this is the one call to cast the typeAvaeon.Configuration.CompileProxy.Compiler galaxyCompiler = (Avaeon.Configuration.CompileProxy.Compiler)ad.CreateInstanceAndUnwrap("Avaeon.Configuration.CompileProxy", "Avaeon.Configuration.CompileProxy.Compiler");
Monday, August 28, 2006 2:58 PM
• Maybe I'm mising your point but you do have 2 appdomains, as you can see from the log, each with a different appbase. Each appdomain needs to find the assembly it uses. You can also print somehow the appdomain id to verify this. Assemblies with strong names should be in the GAC.
Monday, August 28, 2006 3:04 PM
• This all happening in the same AppDomain, I see that the AppBase changes for the second log/assembly, I don't know why!!! The code I posted is complete

I don't know why there are 2 logs it's the one call to create the instance.

The assemblies are signed, for other reasons. I've removed the signing for now but now noticed that the log still reports the assembly with the strong name!!! I've removed all references to the dll on my harddrive but still it persists, any idea whats picking up this strong name?

GAC is not an option either.

Monday, August 28, 2006 3:38 PM
• If I break up the instance creation into 2 seperate calls I can see where the 2 logs are coming from
System.Runtime.Remoting.ObjectHandle objh = ad.CreateInstance("Avaeon.Configuration.CompileProxy", "Avaeon.Configuration.CompileProxy.Compiler");

Avaeon.Configuration.CompileProxy.Compiler galaxyCompiler = (Avaeon.Configuration.CompileProxy.Compiler)objh.Unwrap();

The first is successfull and uses the correct weak named version of the assembly.
However it is the call to UnWrap() that causes the problem, it uses a different AppBase and also tries to unwrap to the strong named version (which no longer exists) !!!!
Actually it's the fullname or something that it UnWrap returns
"DisplayName = Avaeon.Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
notice the PublicToken is null.

Monday, August 28, 2006 4:13 PM
• So Suzanne touched on something in one of her blogs http://blogs.msdn.com/suzcook/archi...5/29/57143.aspx, "Thanks, Yiru! For your question: say your AppDomain's ApplicationBaseis C:\foo, and you've done a LoadFrom(@"C:\bar\A.dll"). So, assembly Ais in the LoadFrom context. If you serialize A, and then deserialize itin that appdomain, deserialization will call Load("A, [...]"). (Notethat path info is not included in that call.) If A is not available inthe Load context, you'll get an exception, even though A is alreadyloaded in the appdomain. You would have to subscribe to theAssemblyResolve event to resolve it. But, worse, if another copy of Ais available in the GAC or beneath the ApplicationBase, then Load()will load that instead of the one in the C:\bar dir. Then, both A.dll'swill be loaded in the same appdomain, and their types will not becastable to each other."This looks like my problem. I'm loading assemblies from a specificlocation other than the one where the actual application is startingfrom. I can try to instantiate the assemblies by either using changingthe AppBase and caling CreateInstanceAndUnWrap() or by callingCreateInstanceFromAndUnWrap(), both result in the same problem, theUnWrap part of the call results in cast failure. This is what Suzanneis referring to I think, the assembly first loaded is not the same asthe assembly being UnWrapped.The reason why my case is unique I think is because of the way in whichthe application is being launched, it's a BuildTask, the BaseDirectoryof the app is C:\Program Files\Microsoft Visual Studio 8\Common7\IDE, Ichange the ApplicationBase to my own location but it appears to beignored once the UnWrap comes into play, I think the UnWrap only usesthe Load Context, which is the GAC or ApplicationBase, I do not knowwhy the ApplicationBase reverts to the initial ApplicationBase of theoriginal AppDomain, anyone??I've verified that my code is good as these assemblies load withoutissue if I run this code from a test console application and not aBuildTask.Here's the log from the Fusion Logger (This is at the UnWrap):*** Assembly Binder Log Entry  (8/29/2006 @ 12:06:42 PM) ***The operation failed.Bind result: hr = 0x80070002. The system cannot find the file specified.Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dllRunning under executable  C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe--- A detailed error log follows. === Pre-bind state information ===LOG: User = AVAEON\nfallonLOG: DisplayName = Avaeon.Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null (Fully-specified)LOG: Appbase = file:///C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/LOG: Initial PrivatePath = NULLLOG: Dynamic Base = NULLLOG: Cache Base = NULLLOG: AppName = NULLCalling assembly : (Unknown).===LOG: This bind starts in default load context.LOG: Using application configuration file: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe.ConfigLOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).LOG: The same bind was seen before, and was failed with hr = 0x80070002.ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).
Tuesday, August 29, 2006 11:37 AM
• Solution found.
The solution is to subscribe to the AssemblyResolve Event for the first AppDomain (this is if you use the CreateInstanceAndUnWrap() which also requires you to set the AppBase of your new AppDomain to the location of your assemblies).

(I did notice an infinite loop when subscribing to this event before, maybe it was because I was using CreateInstanceFromAndUnWrap()).

[CODE] private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string shortAssemblyName = args.Name.Substring(0, args.Name.IndexOf(','));
string fileName = Path.Combine(projectDir, shortAssemblyName + ".dll");
if (File.Exists(fileName))
{
Assembly result = Assembly.LoadFrom(fileName);
return result;
}
else
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;

}
[/CODE]