MEF not loading parts for some users

Nov 1, 2010 at 5:47 PM

I've been using MEF in my project for some time now and I've never had any problems with it. I recently upgraded my project to .NET 4.0, updating my reference to MEF from an assembly to the version that ships with the framework. Everything works fine for me, and the vast majority of my users, however a few (2 to be exact) are having huge problems. I added a bunch of logging code to the application and it seems that MEF is not loading *any* of the plugins, despite the fact that it can quite clearly see the assembly which contains them. What might cause this to happen on some users systems while working fine for most?

Here's a brief description of my setup:

I have one assembly which contains the contracts PluginInterfaces.dll (which contains IPlugin among others).
I have the main application executable which composes the container using a directory catalogue, and has a reference to PluginInterfaces.dll
I have the plugins in a seperate assembly, DefaultPluginLibrary.dll, which contains several classes implementing IPlugin.

Here's the Compose method (taken largely from the documentation)

        private void Compose()
        {
            Trace.WriteLine("Composing IOC container...", "CORE");

            try
            {
                using (var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()))
                {
                    using (var pluginsCatalog = new DirectoryCatalog("Plugins"))
                    {
                        Trace.WriteLine("Loading plugins...", "CORE");

                        using (new TraceIndenter())
                        {
                            pluginsCatalog.LoadedFiles.ToList().ForEach(f => Trace.WriteLine("Assembly: " + f));
                        }

                        using (var catalog = new AggregateCatalog(assemblyCatalog, pluginsCatalog))
                        {
                            this.CompositionContainer = new CompositionContainer(catalog);

                            var batch = new CompositionBatch();

                            batch.AddPart(this);

                            this.CompositionContainer.Compose(batch);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.Message);

                throw;
            }
        }

And here is an example of one of the properties which I'm expecting to be set:

        private IEnumerable<IModifierPlugin> _modifierPlugins;

        /// <summary>
        /// Gets or sets the modifier plugins.
        /// </summary>
        /// <value>The modifier plugins.</value>
        [ImportMany(typeof(IModifierPlugin), AllowRecomposition = true)]
        public IEnumerable<IModifierPlugin> ModifierPlugins
        {
            get
            {
                return this._modifierPlugins;
            }
            set
            {
                this._modifierPlugins = value;

                if (this.ModifierPlugins != null)
                {
                    Trace.WriteLine("Found modifier plugins...", "CORE");

                    using (new TraceIndenter())
                    {
                        this.ModifierPlugins.ToList().ForEach(p => Trace.WriteLine("Plugin: " + p.Name));
                    }
                }
            }
        }
As you can see there's a fairly verbose amount of logging in there. This is an example of the log output for a normal user (me):
CORE: Composing IOC container...
CORE: Loading plugins...
  assembly:C:\...\PLUGINS\PROJECTMERCURY.CONTENTPIPELINE.DLL
  assembly:C:\...\PLUGINS\PROJECTMERCURY.EFFECTEDITOR.DEFAULTPLUGINLIBRARY.DLL
CORE: Found emitter plugins...
  plugin: Cone Emitter
  plugin: Mask Emitter
  plugin: Polygon Emitter
  plugin: Line Emitter
  plugin: Basic Emitter
  plugin: Rect Emitter
  plugin: Circle Emitter
CORE: Found modifier plugins...
  plugin: Opacity Oscillator
  plugin: Scale Merge Modifier
  plugin: Damping Modifier
  plugin: Rectangle Constraint Deflector
  plugin: Scale Interpolator
  plugin: Radial Force Modifier
  plugin: Linear Gravity Modifier
  plugin: Hue Shift Modifier
  plugin: Radial Gravity Modifier
  plugin: Force Interpolator
  plugin: Colour Merge Modifier
  plugin: Scale Oscillator
  plugin: Scale Modifier
  plugin: Rotation Modifier
  plugin: Opacity Interpolator
  plugin: Colour Modifier
  plugin: Opacity Fast Fader
  plugin: Opacity Modifier
  plugin: Velocity Clamp Modifier
  plugin: Trajectory Rotation Modifier
  plugin: Rotation Rate Modifier
  plugin: Colour Interpolator
  plugin: Sine Force Modifier
  plugin: Rectangle Force Modifier
CORE: Found serialization plugins...
  plugin: Default Effect Serializer
  plugin: Mercury 3 Format Importer
And this is the log output for a user who's reporting the error:
CORE: Composing IOC container...
CORE: Loading plugins... 
 assembly:C:\...\PLUGINS\PROJECTMERCURY.CONTENTPIPELINE.DLL  
 assembly:C:\...\PLUGINS\PROJECTMERCURY.EFFECTEDITOR.DEFAULTPLUGINLIBRARY.DLL
CORE: Found emitter plugins...
CORE: Found modifier plugins...
CORE: Found serialization plugins...

Clearly none of the plugins are being detected, what could cause this to work on one machine but fail on another? Any help with this would be appreciated, I've been tearing my hair out with this one. Unfortunately this error renders my application completely useless for the affected users :(

Cheers!
Matt

Nov 1, 2010 at 8:54 PM

Interesting problem. The first thing I'd try to do is checking if your DirectoryCatalog is actually loading anything. Add trace for its Parts property and see if there is something there.

If it's empty it may be a directory problem (pass a full directory name) or assembly loading issue (missing dependent assemblies).

Nov 3, 2010 at 11:18 AM
Edited Nov 3, 2010 at 11:20 AM

Hi haveriss, thanks for your response.

I've added the following logging code:

    using (new TraceIndenter())
    {
        foreach(var part in pluginsCatalog.Parts)
        {
            Trace.WriteLine("Part:" + part);

            using (new TraceIndenter())
            {
                part.ExportDefinitions.ToList().ForEach(e => Trace.WriteLine("Implementing: " + e.ContractName));
            }
        }
    }


I'm just waiting for one of my affected users to submit a log to me, then I'll post it here (alongside mine for comparison). Please standby :)

On a side note, does MEF output any trace messages when it rejects parts? If so how do I modify my app config to make sure these get written to my listener?

Cheers!
Matt

Nov 3, 2010 at 7:30 PM

Yes, you can enable tracing in your configuration file:

<configuration> 
    <system.diagnostics> 
        <sources> 
            <source name="System.ComponentModel.Composition"
                    switchValue="All"> 
                <listeners> 
                    <add name="fileListener"
                         type="System.Diagnostics.TextWriterTraceListener"
                         initializeData="composition.log" /> 
                </listeners> 
            </source> 
        </sources> 
        <trace autoflush="true" indentsize="4" /> 
    </system.diagnostics> 
</configuration>

For more check this blog post http://blogs.msdn.com/b/dsplaisted/archive/2010/07/13/how-to-debug-and-diagnose-mef-failures.aspx?wa=wsignin1.0

Nov 5, 2010 at 12:14 PM
Edited Nov 5, 2010 at 12:26 PM

Thanks haveriss, I added the config as you suggested and my user has submitted this Composition.log file to me:

System.ComponentModel.Composition Warning: 3 : The catalog 'DirectoryCatalog (Path="C:\Users\Dan\Desktop\mpe-79368\ProjectMercury (4.0)\ProjectMercury.EffectEditor\bin\Debug\Plugins")' could not load assembly 'C:\USERS\DAN\DESKTOP\MPE-79368\PROJECTMERCURY (4.0)\PROJECTMERCURY.EFFECTEDITOR\BIN\DEBUG\PLUGINS\PROJECTMERCURY.CONTENTPIPELINE.DLL'. Could not load file or assembly 'ProjectMercury.ContentPipeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
System.ComponentModel.Composition Warning: 3 : The catalog 'DirectoryCatalog (Path="C:\Users\Dan\Desktop\mpe-79368\ProjectMercury (4.0)\ProjectMercury.EffectEditor\bin\Debug\Plugins")' could not load assembly 'C:\USERS\DAN\DESKTOP\MPE-79368\PROJECTMERCURY (4.0)\PROJECTMERCURY.EFFECTEDITOR\BIN\DEBUG\PLUGINS\PROJECTMERCURY.EFFECTEDITOR.DEFAULTPLUGINLIBRARY.DLL'. Could not load file or assembly 'ProjectMercury.EffectEditor.DefaultPluginLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.IInterfaceProvider' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.GraphicsDeviceControl' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.Core' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.AboutWindow' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.CoreOperationEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.EmitterEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TextureReferenceChangedEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TextureReference' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.ModifierEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TraceIndenter' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.ServiceContainer' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.SerializeEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewEmitterEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.OptionsWindow' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewTextureReferenceEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TreeNodes.ParticleEffectTreeNode' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.CoreOperationResult' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewEmitterDialog' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.CloneEmitterEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.Properties.Resources' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewModifierEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.GraphicsDeviceService' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TreeNodes.ModifierTreeNode' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.Properties.Settings' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.EmitterReinitialisedEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.SerializeEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewEmitterEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.CloneEmitterEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.EmitterEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewModifierEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.CloneModifierEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.ModifierEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.EmitterReinitialisedEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.NewTextureReferenceEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TextureReferenceChangedEventHandler' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.HouseglassCursor' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TreeNodes.EmitterTreeNode' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.TextureReferenceBrowser' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.ImageOptions' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.ParticleEffectPreviewControl' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.CloneModifierEventArgs' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.Program' was ignored because it contains no exports.
System.ComponentModel.Composition Information: 6 : The ComposablePartDefinition 'ProjectMercury.EffectEditor.Controllers.EditorSupportController' was ignored because it contains no exports.

It looks like this is the interesting line: Could not load file or assembly 'ProjectMercury.EffectEditor.DefaultPluginLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)

A quick google of that HRESULT code found this link on msdn, which explains everything :)

I'm still waiting for one of my affected users to get back to me and confirm that this is the cause (since I still can't reproduce it locally), but I'm quite sure that unblocking the zip file before extracting it will resolve the issue :)

Thanks for your help!

Cheers!
Matt

Nov 5, 2010 at 2:32 PM

Confirmed, unblocking the archive resolved the issue :)