Diagnosing Composition Problems

Rejection-Related Problems

One of the implications of Stable Composition is that the rejected parts will simply never show up.

Because parts are interdependent, one broken part can cause a chain of other dependent parts to be rejected as well.

image_2.png

Finding the root cause of a ‘cascading rejection’ like this can be tricky.

Included in the samples under /Samples/CompositionDiagnostics is a prototype diagnostic library that can be used to track composition problems down.

The two basic functions that are implemented allow the rejection state of a part to be inspected, and the contents of an entire catalog to be dumped along with status and root cause analysis information.

Dump Composition State

For comprehensive diagnostics, the complete composition can be dumped in text format:

image_4.png
Dim cat = New AssemblyCatalog(GetType(Program).Assembly)
Using container As New CompositionContainer(cat)
  Dim ci = new CompositionInfo(cat, container)
  CompositionInfoTextFormatter.Write(ci, Console.Out)
End Using

The output contains many interesting things, including ‘primary rejection’ guesses and analysis of common problems like mismatched type identity, mismatched creation policy, and missing required metadata:

image_6.png

There’s enough information here to correctly diagnose most common issues.

Find Likely Root Causes

The dump technique above is comprehensive but verbose, and if you have access to the running process in a debugger, the following is more likely to be convenient:

image_8.png
Dim fooInfo = ci.GetPartDefinitionInfo(GetType(Foo))

The return value of CompositionInfo.GetPartDefinitionInfo() is an object that gives quick access to all of the same analytical information as the text dump, but relating to the part Foo. The API exposes:

* The part’s rejection state (IsRejected)
* Whether it is a primary cause of rejection, or if it is rejected because of other cascading rejections (IsPrimaryRejection)
* Which parts are likely to be the root causes of the part’s rejection (PossibleRootCauses)
* The state of all imports (ImportDefinitions)
* For each import, which exports would satisfy the imports (ImportDefinitions..Actuals)
* For each import, which other exports with the same contract name were not matched, and the reason for each (ImportDefinitions..UnsuitableExportDefinitions)

Debugger Proxies

MEF types like ComposablePartCatalog can be inspected under the debugger:

dd1.png

The mefx Command-Line Analysis Tool

In Preview 7 and later there is an included utility that makes use of the diagnostics routines to print information about parts directly from the command-line.

C:\Users\...\CompositionDiagnostics> mefx /?

  /?

      Print usage.

  /causes

      List root causes - parts with errors not related to the rejection of other parts.

  /dir:C:\MyApp\Parts

      Specify directories to search for parts.

  /exporters:MyContract

      List exporters of the given contract.

  /exports

      Find exported contracts.

  /file:MyParts.dll

      Specify assemblies to search for parts.

  /importers:MyContract

      List importers of the given contract.

  /imports

      Find imported contracts.

  /parts

      List all parts found in the source assemblies.

  /rejected

      List all rejected parts.

  /type:MyNamespace.MyType

      Print details of the given part type.

  /verbose

      Print verbose information on each part.

The /parts switch list all parts in a composition:

C:\Users\...\CompositionDiagnostics> mefx /dir:..\MefStudio /parts

Designers.CSharp.Commands

Designers.BasicComponentFactory

Designers.CSharpFormFactory

...

While the /rejected and /causes switches will print information about rejected parts and suspected root causes respectively.

By specifying the /verbose switch, detailed information about parts can be retrieved:

C:\Users\...\CompositionDiagnostics> mefx /dir:..\MefStudio /type:Designers.BasicComponentFactory /verbose

[Part] Designers.BasicComponentFactory from: DirectoryCatalog (Path="..\MefStudio")

  [Export] Designers.BasicComponentFactory (ContractName="Contracts.HostSurfaceFactory")

  [Import] Contracts.HostSurfaceFactory.propertyGrid (ContractName="Contracts.IPropertyGrid")

    [Actual] ToolWindows.PropertyGridWindow (ContractName="Contracts.IPropertyGrid") from: ToolWindows.PropertyGridWindow from: DirectoryCatalog (Path="..\MefStudio")

  [Import] Contracts.HostSurfaceFactory.Commands (ContractName="System.Void(Contracts.HostSurface)")

    [Actual] Designers.CSharp.Commands.Cut (ContractName="System.Void(Contracts.HostSurface)") from: Designers.CSharp.Commands from: DirectoryCatalog (Path="..\MefStudio")

    [Actual] Designers.CSharp.Commands.Copy (ContractName="System.Void(Contracts.HostSurface)") from: Designers.CSharp.Commands from: DirectoryCatalog (Path="..\MefStudio")

    [Actual] Designers.CSharp.Commands.Paste (ContractName="System.Void(Contracts.HostSurface)") from: Designers.CSharp.Commands from: DirectoryCatalog (Path="..\MefStudio")

It is important to realise that the utility can only analyze MEF assemblies built against a compatible version of MEF; for example, mefx.exe built against the CodePlex drops will not be able to analyze assemblies built against the signed .NET Framework version of MEF, and vice-versa.

Tracing

Diagnostic information produced during composition can be viewed in the Output window of the debugger, or by attaching to the "System.ComponentModel.Composition" trace source.

Last edited Aug 9, 2010 at 6:43 PM by haveriss, version 7

Comments

clodewyks Sep 23, 2013 at 11:11 AM 
Hi I would like to log the composition but i cannot find CompositionInfo or CompositionInfoTextFormatter. In what namespace are they located? I am using .net 4 VS 2012.

DanyR Aug 27, 2011 at 9:46 PM 
There might be a confusion with generic Interfaces:

class Test {
[ImportMany(typeof(IAddinView<IViewModel>))]
private IEnumerable<IAddinView<IViewModel>> m_Addins;
...}

[Export(typeof(IAddinView<IViewModel>))]
class MyClass : IAddinView<IMyViewModel>{ } with an Interface IMyViewModel : IViewModel { }

CompositionInfo says that (no "My" in the generic arguments at all)
[Import] Test.frmMain.m_AddinViews (ContractName="Test.IAddinView(Test.IViewModel)")
[SatisfiedBy] Test.MyClass (ContractName="Test.IAddinView(Test.IViewModel)") from: Test.MyClass from: AssemblyCatalog (Assembly="Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

But compositionContainer.ComposeParts(this) gives this error

CompositionException - The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) The export 'IBR.Translator2010.GUI.UserControls.TranslationsContainer (ContractName="Test.IAddinView(Test.IViewModel)")' is not assignable to type Test.IAddinView`1[[Test.IViewModel, Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.

Resulting in: Cannot set import 'Test.MyClass.m_Addins (ContractName="Test.IAddinView(Test.IViewModel)")' on part 'Test.MyClass'.
Element: Test.MyClass.m_Addins (ContractName="Test.IAddinView(Test.IViewModel)") --> Test.MyClass

So the error message is true because in ContractServices.TryCast() the line
if (contractType.IsInstanceOfType(value))
will not be satisfied due to the inequality between IAddinView<IViewModel> and IAddinView<IMyViewModel> (note the "My" in the second generic argument).
Thus CompositioInfo should give the same error in this case ([SatisfiedBy] is wrong).

amarpanda Sep 17, 2010 at 2:35 PM 
public static string GetCompositionInfo()
{
// return null;
//#if false //TODO: Reintroduce CompositionInfo. (Removed due to .NET4 upgrade)
if (_container == null)
return null;
var sb = new StringBuilder();
using (var writer = new StringWriter(sb, CultureInfo.InvariantCulture))
{
// var ci = new CompositionInfo(_container.Catalog, _container.Providers[1]);
var ci = new CompositionInfo(_container.Catalog, _container);
CompositionInfoTextFormatter.Write(ci, writer);
return sb.ToString();
}
//#endif
}

this method gives error as shown below.......



Error 20 Argument 1: cannot convert from 'System.ComponentModel.Composition.Primitives.ComposablePartCatalog [c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.ComponentModel.Composition.dll]' to 'System.ComponentModel.Composition.Primitives.ComposablePartCatalog' C:\Program Files\Gecko\EphorteOutlook\Trunk\EphorteOutlook\Source\Container\Gecko.Container.Mef\MefContainer.cs 142 44 Gecko.Container.Mef

rickrat Apr 26, 2010 at 1:49 PM 
Diagnostics is on codeplex. http://mef.codeplex.com/

habakuk Apr 14, 2010 at 4:27 PM 
I have .Net 4 and I don't find the Namespace 'Microsoft.ComponentModel.Composition.Diagnostics' which is needed for mefx and the "Dump Composition State". Is there a debugging included?

Is there a document which lists the difference between this project and the MEF in .Net 4?

Ciao!
Stefan

nblumhardt Sep 12, 2009 at 12:24 AM 
Hi Theo,

It is included in Preview 7 under the /Samples/CompositionDiagnostics folder. I don't believe it is included in the 'Silverlight' zip.

Cheers,
Nick

Theo67 Sep 1, 2009 at 11:33 AM 
Hi, I didn't find the mefx.exe in the 7 preview, nor the sources. Should we download it from somewhere else?