Yes, I’ve raised this with the MEF team many times. It’s easier to go and do it yourself.
The issue is that DirectoryCatalog does not guard against failures on loading types (which is quite common as soon as you start working on real projects as opposed to samples – hint hint!). So here’s a better version (in F#):
| cs | | copy code | | ? |
| 01 | |
| 02 | type DirectoryCatalogGuarded(folder) = |
| 03 | inherit ComposablePartCatalog() |
| 04 | |
| 05 | let _catalogs = List |
| 06 | let mutable _parts : ComposablePartDefinition seq = null |
| 07 | |
| 08 | let load_assembly_guarded (file:string) = |
| 09 | try |
| 10 | let name = AssemblyName.GetAssemblyName(file); |
| 11 | Assembly.Load name |
| 12 | with | ex -> null |
| 13 | |
| 14 | let guard_load_types (asm:Assembly) = |
| 15 | try |
| 16 | asm.GetTypes() |
| 17 | with | :? ReflectionTypeLoadException as exn -> exn.Types |
| 18 | |
| 19 | do |
| 20 | let files = Directory.GetFiles(folder, "*.dll") |
| 21 | for file in files do |
| 22 | let asm = load_assembly_guarded file |
| 23 | if asm <> null then |
| 24 | let types = guard_load_types(asm) |> Seq.filter (fun t -> t <> null) |
| 25 | if not (Seq.isEmpty types) then |
| 26 | _catalogs.Add (new TypeCatalog(types)) |
| 27 | _parts <- _catalogs |> Seq.collect (fun c -> c.Parts) |
| 28 | |
| 29 | override x.Parts = _parts.AsQueryable() |
| 30 | |
| 31 | override x.GetExports(definition) = |
| 32 | _catalogs |> Seq.collect (fun c -> c.GetExports(definition)) |
| 33 |
The “trick” is to catch ReflectionTypeLoadException – something I learned from David. This exception gives you a list of types it was able to load. Mind you, nulls may exists in the list hence the filtering.
The shortcoming here is that by bypassing the AssemblyCatalog, you wont be able to use CatalogReflectionContextAttribute – which I believe I’m one of the ten people on earth that knows what it’s for, so no biggy I guess?
December 27th, 2011 at 6:24 pm
I think the reason we don’t guard against this is because the problem is missing dependencies, and catching ReflectionTypeLoadExceptions from Assembly.GetTypes() won’t help you if you have a dependency in a method implementation that isn’t exposed in the public surface. In that case you will get a FileNotFoundException the first time you run the method.
December 27th, 2011 at 6:35 pm
and I believe this is just your corpus callosum coming up with an explanation for it :-)