Sunday, 11 January 2009

Evidence for the AppDomain: The resolution

To recap what has been a continuing saga: I discovered that attempts to get Streams on PackageParts in an OpenXML Package were failing because of an issue in the .Net framework. Under the hood, a MemoryStream was overflowing to disk. The framework examines the evidence of the assembly and then examines the evidence of the AppDomain. Our managed COM component was getting created in the DefaultDomain and didn't have the evidence (a SecurityZone of MyComputer) that was needed to satisfy the framework.

As I discussed here, I resolved this by having the COM interface act as a shim. It created a second AppDomain that had the evidence necessary to satisfy the framework.

Further testing did not reveal any more show-stoppers but it was obvious that performance was not great. Large blobs of XML were being marshaled across AppDomain boundaries (from the child AppDomain to the DefaultDomain) and then marshalled again across the COM boundary to the Win32 application.

I briefly considered hosting the CLR so that I could explicitly create the AppDomain of my dreams but decided I'd really rather not.

Fortunately help came in the form of this post. (Can I just say how great it is that everyone with a keyboard in Microsoft seems to be blogging these days. Shawnfa's posts have been a great help.)

To summarize: you don't have to do all the work of hosting the CLR. You can just write (in managed code) an AppDomainManager and tell the CLR (by setting two environment variables) to use it.

This was almost the complete answer to my problem: when an AppDomain gets created I can add the Evidence I need, namely a SecurityZone of MyComputer. Sure enough, when I set the environment variables and my managed COM component gets called, I see a new instance of my AppDomainManager get called. But the CreateDomain() method never gets called. The CLR is just loading my COM component into the DefaultDomain; it's not making a new AppDomain.

It's almost the solution though. It's apparent that my AppDomainManager is getting called, and that the HostSecurityManager property is being used by the framework to make decisions. All I need is for that property to return my own subclass of a HostSecurityManager with the evidence set. In my subclass, I override the method ProvideAppDomainEvidence to provide the Evidence that I need.

Now my COM component works like a charm! Performance has improved too. We are marshaling large XML blobs across COM boundaries but at least we aren't also marshaling across the boundary to a second AppDomain.

No comments: