Sometimes it almost seems that they don't want you to get the code to work...

I’ve spent some time over the last few days playing around with my CLR hosting socket server example. I had stalled on a piece of client work, I’ve got a bit of a head cold at the moment and my brain just wasn’t in the right place for what I was supposed to be doing so I picked up one of more interesting the items on my todo list and took a look at that instead… The bulk of the work flowed nicely but then, just at the end things stopped working for no apparent reason… I’d done what was suggested in the book, the code compiled, the CLR called into my host in the right way and then I got a security policy exception… Hmmm.

I’m looking at having my CLR hosting server control how assemblies are loaded by the CLR. This involves implementing a few COM interfaces (who said .Net killed COM?), mainly IHostAssemblyManager and IHostAssemblyStore. These allow you to jump through some hoops and eventually control how assemblies are loaded… I’d got to the bit where the CLR was finally calling IHostAssemblyStore.ProvideAssembly() on my host and I was checking the binding info and returning an IStream that contained the contents of the assembly file. This is how SQL Server hosts code that lives in the database and it works quite nicely (once you’re trained to jump through the required hoops without asking too many questions).

So, I was returning a valid IStream which contained the correct assembly but my code still didn’t run and I was getting security policy exceptions. I double checked my reference book, “Customizing the Microsoft.NET Framework Common Language Runtime” by Steven Pratschner, and I seemed to be doing everything that I needed to be doing… I did a Google search and someone else had been having a similar problem and his final comment was that the book did mention the issue that he had but he hadn’t noticed it… I checked things out and finally found the problem mentioned in a different chapter, some way further on from the actual code that dealt with assembly store customisation… It seems that if you provide your own assembly store then you also have to provide a managed HostSecurityManager which adds some “evidence” onto the assembly that you’ve loaded so that the CAS stuff works properly… The chapter where this is explained goes on to show how to create custom evidence and all kinds of clever things that I have no interest in and then, right at the end, subtly includes a comment about how the security manager implementation needs to add more evidence (in addition to all the custom stuff that the rest of the chapter had been dealing with). If this additional evidence isn’t added then the new custom evidence wont work… The good thing is, for me at least, just adding the standard evidence works well enough for now. The loaded assemblies will have full trust but that’s fine for my example.

So, the minimal managed security manager implementation that you need to get your custom assembly store working is something like this:

   public class SecurityManager : HostSecurityManager
   {
      public override HostSecurityManagerOptions Flags
      {
         get
         {
            return (HostSecurityManagerOptions.HostAssemblyEvidence | 
               HostSecurityManagerOptions.HostPolicyLevel);
         }
      }

      public override Evidence ProvideAssemblyEvidence(
         Assembly loadedAssembly, 
         Evidence inputEvidence)
      {
         if (loadedAssembly.HostContext == 42)
         {
            inputEvidence.AddHost(new Zone(SecurityZone.MyComputer));
         }

         return inputEvidence;
      }
   }

And now that I’ve worked around the fact that you can’t reuse the IStream that you give out in one call to IHostAssemblyStore.ProvideAssembly() in another call (probably due to the cursor in the stream being wrong), everything seems to be working nicely.