Introduction
I was toying around with loading and inspecting assemblies in .NET dynamically. I wanted to create a service that could return a binary stream with assembly data that I could store on disk in my demo application and than use normally from within my demo.
When you want to skip the steps I took follow this link.
My steps into AppDomain
I need to load the assembly in memory and inspect the assembly’s manifest. Here I can use AppDomain.Load(byte[]). I tried the following:
byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
Assembly assembly = AppDomain.CurrentDomain.Load(assemblyBuffer);
This is all oke. I can load and inspect my assembly. But when I inspect all assemblies loaded into the current AppDomain (via AppDomain.CurrentDomain.GetAssemblies()) my asembly is also loaded. This is not what I want. I want to load the assembly, inspect the manifest and when I’m done, remove the assembly from memory. You need an extra AppDomain for that. I changed the code to:
byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
AppDomain tempAppDomain = AppDomain.CreateDomain("MyTempAppDomain");
Assembly assembly = tempAppDomain.Load(assemblyBuffer);
When I executed the code I got the following exception:
System.IO.FileNotFoundException: Could not load file or assembly 'Luminis.Samples.AppDomainSample.MyDynamicAssembly, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) at System.Reflection.Assembly.Load(String assemblyString) at System.UnitySerializationHolder.GetRealObject(StreamingContext context) at System.AppDomain.Load(Byte[] rawAssembly) at Luminis.Samples.AppDomainSample.AppDomainSample.Program.Test2() in C:\User s\Alex\Projects\Luminis\.NET\Samples\AppDomainSample\Luminis.Samples.AppDomainSample.AppDomainSample\Program.cs:line 45
Where does this FileNotFoundException come from? When I dug deeper into this exception I figured out that .NET was still looking for the assembly-file on disk. I changed the code:
byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
AppDomain tempAppDomain = AppDomain.CreateDomain("MyTempAppDomain");
File.WriteAllBytes(@"C:\TEMP\MyTempAssembly.dll", assemblyBuffer);
Assembly assembly = tempAppDomain.Load(assemblyBuffer);
Actually this is really not what I want. But what the heck, let’s try this first.
Oke, the assembly is loaded correctly but when I look closer I see that my assembly is loaded into the temp AppDomain, but also in the curren AppDomain. Also when I try to delete the temporary assembly file get an UnauthorizedAccessException:
System.UnauthorizedAccessException: Access to the path 'C:\Users\Alex\Projects\Luminis\.NET\Samples\AppDomainSample\Luminis.Samples.AppDomainSample.AppDomainSample\bin\Debug\Luminis.Samples.AppDomainSample.MyDynamicAssembly.dll' is denied.
I cannot delete th file because it is still locked by the current AppDomain. I need another trick.
I need to load the assembly in the temp AppDomain without interfering with the current AppDomain. I created the following code:
byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
AppDomain tempAppDomain = AppDomain.CreateDomain("MyTempAppDomain");
object anObject = tempAppDomain.CreateInstanceAndUnwrap("....AssemblyInspectorImplementation", "...AssemblyInspectorImplementation.AssemblyInspector");
IAssemblyInspector assemblyInspector = anObject as IAssemblyInspector;
result = assemblyInspector.GetAssemblyInfo(assemblyBuffer);
I created an interface IAssemblyInspector. I dynamically create an implemetation-object for this interface in the temp AppDomain (via CreateInstanceAndUnwrap()) and I call the GetAssemblyInfo() method.
Here is the code GetAssemblyInfo() method in the AssemblyInspector implementation class.
public string[] GetAssemblyInfo(byte[] assemblyBuffer)
{
List result = new List();
Assembly assembly = AppDomain.CurrentDomain.Load(assemblyBuffer);
object[] fileVersionAttributes = assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true);
if (fileVersionAttributes.Length == 1)
{
AssemblyFileVersionAttribute fileVersion = fileVersionAttributes[0] as AssemblyFileVersionAttribute;
result.Add(fileVersion.Version);
}
Module manifest = assembly.ManifestModule;
result.Add(manifest.ScopeName);
return result.ToArray();
}
What I see now is that although I created the AssemblyInspector in the temp AppDomain my assembly is still loaded into the current AppDomain.
The last trick I found is that I need to extend from System.MarshalByRefObject.
public class AssemblyInspector : MarshalByRefObject, IAssemblyInspector
{
#region IAssemblyInspector Members
public string[] GetAssemblyInfo(byte[] assemblyBuffer)
{
...
}
}
This way in the main I get a handle to a so called TransparentProxy that uses .NET Remoting to transfer the GetAssemblyInfo()-methodcall to AssemblyInspector.
This AssemblyInspector is loaded into the temp AppDomain and will load the assembly also into that AppDomain without interfering with the current AppDomain.
When you want to dynamically load an assembly and be able to control the unloading of the assembly you need:
- Create a new AppDomain via AppDomain.CreateDomain().
- Use appDomain.CreateInstanceAndUnwrap() to create an object in the new AppDomain.
- Extend MarshalByRefObject to use .NET Remoting to access objects in the new AppDomain.
When you want to download the code in this sample, click here.

#1 door Rosh om 14 september 2011
Greet…i am really looking such info for last 6 month.