Yesterday, I showed an alternate to the shim method of gracefully failing from an assembly using an AppDomainManager. However, as David pointed out this method isn't particularly useful if you're going to be using it to detect failure to load your main assembly. The reasoning is that AppDomainManagers need FullTrust to run. If your application supplied AppDomainManager has FullTrust then either you're in a FullTrust location, or you were able to run some sort of setup to get the AppDomainManager trusted. And if you were able to run a setup, why not just trust your application?
So it looks like the shim is still the best way to go if you need to detect your main assembly's failure to load. That being said, the AppDomainManager approach can be used for all of the other assemblies that your application uses. Using an AppDomainManager instead of putting try ... catch blocks around each assembly load has several advantages.
In order to pull this off, we'll need to make some modifications to yesterday's AppDomainManager. The technique that yesterday's version used was to search through all unhandled exceptions to see if the exception being thrown was that the entry assembly could not be loaded. That was a rather indirect way of getting the information, a more sensible approach would be to check each assembly as it loads to see if we are granting enough permissions.
In order to do this, we need to have some code execute whenever we're determine the PermissionSet that will be granted to an assembly. From looking at our HostSecurityManager, it seems that HostSecurityMnaager::ResolvePolicy is exactly what we need. ResolvePolicy gives us some evidence, and we give it back a permission set.
Most overrides of ResolvePolicy will be interested in modifying the permission set that's granted to an assembly .... however we don't care about that, we can just rely on the default implementation to do the actual policy resolution. Instead, once we've gotten the PermissionSet that will be granted, we need to figure out if that's enough. In order to do that, we need to know the minimum set of permissions the assembly requires to load. That information is conveniently bundled up for us in a PermissionRequestEvidence object attached to the evidence.
So all we need to do is loop over the evidence looking for the PermissionRequestEvidence and the Url (so we know what assembly we're talking about). If we find PermissionRequestEvidence, and it has a minimum request set, then we need to check if it's a subset of the permissions that were granted. If it is, then we're fine. However, if it isn't this assembly won't load, exactly the case we're interested in.
The simple UnableToLoadHostSecurityManager below simply prints an error message and quits in this instance, however that's probably not the route that a real application would want to take. Instead, you might show the user a dialog box explaining what happened, and maybe fire an event that would let the rest of the application know the problem.
The code to pull this off is actually pretty straightforward: