A “decent” DirectoryCatalog implementation

December 27th, 2011

Warning: file(http://svn.wp-plugins.org/devformatter/branches/langs/cs.php): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in C:\websites\castle\blogs\hammett_castleblog\wp-content\plugins\devformatter\devgeshi.php on line 100 Warning: implode(): Invalid arguments passed in C:\websites\castle\blogs\hammett_castleblog\wp-content\plugins\devformatter\devgeshi.php on line 100 Warning: file(http://svn.wp-plugins.org/devformatter/branches/langs/cs.php): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in C:\websites\castle\blogs\hammett_castleblog\wp-content\plugins\devformatter\devgeshi.php on line 100 Warning: implode(): Invalid arguments passed in C:\websites\castle\blogs\hammett_castleblog\wp-content\plugins\devformatter\devgeshi.php on line 100 Warning: file(http://svn.wp-plugins.org/devformatter/branches/langs/cs.php): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in C:\websites\castle\blogs\hammett_castleblog\wp-content\plugins\devformatter\devgeshi.php on line 100 Warning: implode(): Invalid arguments passed in C:\websites\castle\blogs\hammett_castleblog\wp-content\plugins\devformatter\devgeshi.php on line 100

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?

Categories: MEF | Top Of Page | 2 Comments » |

2 Responses to “A “decent” DirectoryCatalog implementation”

Daniel Plaisted Says:

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.

hammett Says:

and I believe this is just your corpus callosum coming up with an explanation for it :-)

Leave a Reply