More on Assembly Binding, Strong Naming, the GAC, Publisher Policy and Dynamically Loaded Assemblies
Certainly Suzanne Cook is the definitive source for details on Assembly.Load and Binding Contexts, a black art tantamount to voodoo that few people understand. Patrick and I have been hip-deep in it lately, and have discovered/uncovered/madecleartoourselves how some of this voodoo works. Here's a (annotated) writeup from Patrick that was sent out internally. Another great resource is Mike Gunderloy's article on Binding Policy in .NET.
- Assemblies will only EVER be loaded from the GAC based on a full bind (name, version, and public key token). A partial bind with name and public key token only WON’T load from the GAC.
- If you reference an assembly with VS.NET you're asking for a full bind. If you say Assembly.Load("foo") you're asking for a partial bind.
- However, the way this usually works is
- You do a partial bind on assembly name, or name and public key token with Assembly.Load
- Fusion (the code name for the Assembly Loader/Binder) starts walking the probing path looking for an assembly that matches the partial bind.
- Counter Intuititive: If it finds one while probing (the first one) it will then attempt to use the strong name of the one it found to do a full bind against the GAC.
- If it’s in the GAC, that’s the one that gets loaded.
- Any of that loaded assemblies will try to load from the GAC first without going to the probing path, since the embedded references constitute a full bind.
- If they aren’t found in the GAC, then it will start probing.
- It’ll grab the first one it finds in the probing path. If the versions don’t match, Fusion fails. If they do match, Fusion loads that one.
- So, if you specify a partial name, and the file is in the GAC, but not the probing path, the load fails, since there’s no way to do a full bind.
All this is mostly an issue for plugins that we load dynamically. It shouldn’t be an issue for compile-time dependencies, since they use full binds. One way to make sure you get what you expect is to specify a full bind in your config files via an Assembly Qualified Name (QN) like: "Foo.Bar, Version=18.104.22.168, Culture=neutral, PublicKeyToken=59388ae2d2746794" and doing something like this:
100 public static object CreateInstance(string assemblyandtype)
102 Type type = Type.GetType(assemblyandtype);
103 object instance = null;
104 instance = type.InvokeMember(String.Empty,BindingFlags.CreateInstance, null, null, null);
105 return instance;
Thanks to Patrick for the writeup!