Search code examples
.netmef

CompositionOptions.DisableSilentRejection not working


I'm having trouble figuring out what the MEF DisableSilentRejection option does. I thought that using this option would improve the clarity of composition errors, especially in the case where a dependency is missing several levels below the requested object. However, it does not seem to have any effect on error messages.

I'm using this test case to investigate how MEF reports errors. I have a dependency chain Foo1 -> Foo2 -> Foo3:

[Export]
public class Foo1
{
    [ImportingConstructor]
    public Foo1(Foo2 foo2)
    {
    }
}

[Export]
public class Foo2
{
    [ImportingConstructor]
    public Foo2(Foo3 foo3)
    {
    }
}

[Export]
public class Foo3
{
}

And this code to request a Foo1 object from the MEF container:

try
{
    using (var exportProvider = new CatalogExportProvider(
            new TypeCatalog(typeof(Foo1), typeof(Foo2))))
    using (var container = new CompositionContainer(
            CompositionOptions.DisableSilentRejection, exportProvider))
    {
        exportProvider.SourceProvider = container;
        container.GetExportedValue<Foo1>();
    }
 }
 catch (Exception e)
 {
     Console.WriteLine(e.Message);
     Console.WriteLine(e.StackTrace);
 }

The code above will print a composition exception, because Foo3 is missing in the TypeCatalog. That's what I expected.

However, the error message still complains that the Foo1 export is missing, instead of providing a clear error about the Foo2-Foo3 dependency. Isn't this what DisableSilentRejection was supposed to fix? What am I missing?


Solution

  • Turns out that the ExportProvider constructor also takes composition options:

    using (var exportProvider = new CatalogExportProvider(
            new TypeCatalog(typeof(Foo1), typeof(Foo2)),
            CompositionOptions.DisableSilentRejection)) // Added composition options here!
    using (var container = new CompositionContainer(
            CompositionOptions.DisableSilentRejection,
            exportProvider))
    {
        exportProvider.SourceProvider = container;
        container.GetExportedValue<Foo1>();
    }
    

    Or, alternatively, I could just have used the CompositionContainer constructor which takes a catalog directly:

    using (var container = new CompositionContainer(
            new TypeCatalog(typeof(Foo1), typeof(Foo2)),
            CompositionOptions.DisableSilentRejection))
    {
        container.GetExportedValue<Foo1>();
    }
    

    (In my actual use case I need to prioritize exports from one export provider over the other, which is why I was taking the more complicated route.)