Loading the Same Assembly with Different Evidence

Assembly.Load provides overloads that take an Evidence object in addition to the name of the assembly to load.  This leads to the question -- what happens if you were to load the same assembly multiple times with different Evidence.

It's easy enough to figure that out with a few lines of code:

Evidence myComputer = new Evidence(
    new object[] { new Zone(SecurityZone.MyComputer) },
    new object[] { });
Evidence intranet = new Evidence(
    new object[] { new Zone(SecurityZone.Intranet) },
    new object[] { });

Assembly intranetAsm = Assembly.Load("TestAssembly", intranet);
Assembly myComputerAsm = Assembly.Load("TestAssembly", myComputer);

Console.WriteLine(
    "myComputerAsm ReferenceEquals intranetAsm? {0}",
    Object.ReferenceEquals(myComputerAsm, intranetAsm));

Console.WriteLine();
Console.WriteLine("myComputerAsm Evidence");
foreach(object o in myComputerAsm.Evidence)
    if(o is Zone)
       Console.WriteLine(o);

Console.WriteLine();
Console.WriteLine("localIntranetAsm Evidence");
foreach(object o in intranetAsm.Evidence)
    if(o is Zone)
        Console.WriteLine(o);

This program loads TestAssembly twice, first with evidence saying it came from the intranet, and then with evidence saying it belongs to the MyComputer zone.  After loading the assembly, we then check to see if we've got the same Assembly instance from each load, and dump out any Zone evidence that we find.

Running this program shows:

myComputerAsm ReferenceEquals intranetAsm? True

myComputerAsm Evidence
<System.Security.Policy.Zone version="1">
<Zone>Intranet</Zone>
</System.Security.Policy.Zone>

localIntranetAsm Evidence
<System.Security.Policy.Zone version="1">
<Zone>Intranet</Zone>
</System.Security.Policy.Zone>

The results may be somewhat surprising.  Even though we explicitly specified that the assembly be loaded with two different sets of evidence, we actually ended up with the exact same Assembly objects.  Obviously, since they were the same objects, they also both have the same Evidence which matches the first Evidence we applied.

Why is this?  Well, an assembly can only be loaded once into each AppDomain.  The CLR doesn't support the concept of having two copies of an assembly floating around a domain with different grant sets.  Given that an assembly can only be loaded once, the Evidence is applied and evaluated for the first Load; further attempts to load the same assembly just return the already loaded version without evaluating policy.

Why doesn't the CLR notice that the evidence objects are different and throw an exception warning the user?  There's actually no real good way for us to do that.  Since Evidence is basically just a collection of Object, we have no way of compelling any object that's being used as evidence to create a useful override of Equals.  That means internally the CLR doesn't have a good way of actually determining if two sets of Evidence are equivalent or not.  Using the default Equals implementation won't work, since we don't want to disallow loading an assembly twice with different instances of equivalent evidence objects.

All that being said, remember that assemblies can in fact have different permission sets in different AppDomains.  So if you really want to have an assembly be loaded into your process with multiple grant sets, you'll just need to ensure that each time you load the Assembly with a new grant set you place it in a new AppDomain.