Wednesday, July 13, 2011

MEF DirectoryCatalog Fails to Load Assemblies

I had an interesting problem with the Managed Extensibility Framework yesterday. I’m using the DirectoryCatalog to load assemblies from a given directory. Pretty standard stuff. When I tested my host on my developer machine, it got the works on my machine badge, but when I ran the host on one of our servers, it ignored all the assemblies.

Nothing loaded …

Hmm …

It turns out, after much digging and help from my Twitter crew,  that the assembly loader that MEF’s DirectoryCatalog uses ignores any files that have a URL Zone set. I described these zones in detail in my previous post here:

http://mikehadlow.blogspot.com/2011/07/detecting-and-changing-files-internet.html

Because we copy our plugins from a file share, Windows was marking them as belonging to the Intranet Zone. Thus the odd only-when-deployed behaviour.

How you deal with this depends on whether you think that files marked in this way represent a security threat or not. If you do, the best policy is to detect any assemblies in your DirectoryCatalogue directory that have a Zone set and log them. You can do that with the System.Security.Policy.Zone class:

var zone = Zone.CreateFromUrl("file:///C:/temp/ZoneTest.doc");
if (zone.SecurityZone != SecurityZone.MyComputer)
{
Console.WriteLine("File is blocked");
}
Console.Out.WriteLine("zone.SecurityZone = {0}", zone.SecurityZone);

If you don’t consider files copied from elsewhere a security concern, but rather a feature of your operating procedure, then you can clear the Zone flags from all the assemblies in the directory with the help of Richard Deeming’s Trinet.Core.IO.Ntfs library. I wrote a little class using this:

public class UrlZoneService
{
public static void ClearUrlZonesInDirectory(string directoryPath)
{
foreach (var filePath in Directory.EnumerateFiles(directoryPath))
{
var fileInfo = new FileInfo(filePath);
fileInfo.DeleteAlternateDataStream("Zone.Identifier");
}
}
}

I just run this before initiating my DirectoryCatalogue and now network copied assemblies load as expected.

2 comments:

Unknown said...

This should be a quadroople rant!!!! I just spent all day trying to figure out why one of my plugins wasn't loading on a remote site. I was copying over the latest plugins via. ftp. It worked on the ASP.NET app since I was doing impersonation, but in the Windows service, since it was only running as local service, it wouldn't load the damn plugin! Thank you for this, I never would have figured this out.

Rafitchas said...

I had this error running the MEF Sample Code (Calculator Sample). Was getting a lot of frustration until I saw your post and remembered that when you unzip a file using windows extractor, it maintains the files "blocked". Using 7zip it worked. :D