ComposeParts fail to compose parts

Aug 25, 2009 at 10:32 AM

I have a class which I export with

[Export("TestMEFControl")]

public class TestControl : UserControl

{

...

...

}

The Control resides in D:\Projects\TestControl\

=====

Now, I create one more(Form) class for hosting this TestControl, in D:\Projects\HostControl

public class HostControl

{

[Import("TestMEFControl")]

Public TestControl control;

 

In compose method

{

var catalog = new DirectoryCatalog(@"D:\Projects\TestControl\bin\Debug");

var container = new CompositionContainer(catalog);

container.ComposeParts(this);

}

}

I have an exception at container.ComposeParts(this)

System.ComponentModel.Composition.ChangeRejectedException was unhandled
  Message="The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.\r\n\r\n1) No exports were found that match the constraint '((exportDefinition.ContractName = \"MEFTestControl\") && (exportDefinition.Metadata.ContainsKey(\"ExportTypeIdentity\") && \"Testing_ManagedExtensibleFramework.TestMEFControl\".Equals(exportDefinition.Metadata.get_Item(\"ExportTypeIdentity\"))))'.\r\n\r\nResulting in: Cannot set import 'Testing_ManagedExtensibleFramework.TestMEFForm.TestMEFUserControl (ContractName=\"MEFTestControl\")' on part 'Testing_ManagedExtensibleFramework.TestMEFForm'.\r\nElement: Testing_ManagedExtensibleFramework.TestMEFForm.TestMEFUserControl (ContractName=\"MEFTestControl\") --> Testing_ManagedExtensibleFramework.TestMEFForm\r\n"
  Source="System.ComponentModel.Composition"
  StackTrace:
       at System.ComponentModel.Composition.CompositionResult.ThrowOnErrors(AtomicComposition atomicComposition) in e:\MEF_Preview_6\MEF_Preview_6\src\ComponentModel\System\ComponentModel\Composition\CompositionResult.cs:line 84
       at System.ComponentModel.Composition.Hosting.ComposablePartExportProvider.Compose(CompositionBatch batch) in e:\MEF_Preview_6\MEF_Preview_6\src\ComponentModel\System\ComponentModel\Composition\Hosting\ComposablePartExportProvider.cs:line 245
       at System.ComponentModel.Composition.Hosting.CompositionContainer.Compose(CompositionBatch batch) in e:\MEF_Preview_6\MEF_Preview_6\src\ComponentModel\System\ComponentModel\Composition\Hosting\CompositionContainer.cs:line 202
       at System.ComponentModel.Composition.AttributedModelServices.ComposeParts(CompositionContainer container, Object[] attributedParts) in e:\MEF_Preview_6\MEF_Preview_6\src\ComponentModel\System\ComponentModel\Composition\AttributedModelServices.cs:line 130
       at Testing_ManagedExtensibleFramework.TestMEFForm.Compose() in E:\Projects\Testing_ManagedExtensibleFramework\Testing_ManagedExtensibleFramework\TestMEFForm.cs:line 33
       at Testing_ManagedExtensibleFramework.TestMEFForm.button1_Click(Object sender, EventArgs e) in E:\Projects\Testing_ManagedExtensibleFramework\Testing_ManagedExtensibleFramework\TestMEFForm.cs:line 38
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at Testing_ManagedExtensibleFramework.Program.Main() in E:\Projects\Testing_ManagedExtensibleFramework\Testing_ManagedExtensibleFramework\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

Aug 25, 2009 at 2:12 PM
Edited Aug 25, 2009 at 2:13 PM

You should specify the Type, because your importing requires a TestControl

 

[Export("TestMEFControl", typeof(TestControl))]

public class TestControl : UserControl

{

...

...

}

Aug 25, 2009 at 2:50 PM

Do you have any example which demonstrates the catalog with DirectoryCatalog? If would be nice if you show some more insight.

 

Aug 26, 2009 at 1:14 AM

Hi raavi,
Just like this (in wpf):

Suppose we have two projects. One is called Startup, and another is called Shell. In the Startup project,we have a class called App as the entry point, which requires a Window to be imported, using the contract name "Shell".

 

 // Delete the StartupUri in xaml first
public partial class App : Application { private CompositionContainer _container; [Import("Shell")] public Window ShellWindow { get; set; } protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // At first, do composition InitializePlugins(); Start(); } private void Start() { if (this.ShellWindow == null) { MessageBox.Show("Unable to find a available Shell"); this.Shutdown(1); } else { this.ShellWindow.Show(); } } // Search the 'Plugins' directory for importing private void InitializePlugins() { var catalog = new DirectoryCatalog("Plugins"); _container = new CompositionContainer(catalog);
 _container.ComposeParts(this); } }

 

In the other project, we have a ShellWindow which exports "Shell".

// Need to specify Type here
[Export("Shell", typeof(Window))] public partial class ShellWindow : Window { public ShellWindow() { InitializeComponent(); } }

And the output directory looks like this:

Plugins
    \_Shell.dll
Startup.exe
System.ComponentModel.Composition.dll

Run 'Startup.exe', and a window will be shown.

 

Aug 26, 2009 at 9:23 AM

Thankyou very much for the sample code, but still I got "ChangeRejectedException".

I know I am doing something wrong, may be something very dumb.

Now I will try to split the part which exports to a new class library and see what happens.

Regards,

Aug 26, 2009 at 9:29 AM

Yes, it worked now. Thankyou very much for the support.

Aug 27, 2009 at 9:34 AM

I have a question regarding the security. Since MEF is very candidate for depolying in plug-in scenario there naturally arise a question about the security for the assembly.

Till now, I did not point out any methods or ways to sign the assembly or any other methods to load it with some security.

Best Regards,

Rao.

Aug 27, 2009 at 11:36 PM

If you want to restrict the set of plugins MEF will load, the best approach is to filter assemblies/types before creating the catalog, i.e. if the assembly doesn't meet the required criteria, don't add it to the catalog.

Cheers,

Nick

Aug 28, 2009 at 8:09 AM

Adding to what Nick is saying, you can create an AggregateCatalog, and then add other catalogs to it. For example if you want to filter on only assemblies that are signed, first loop through the assemblies and find the signed ones, and then for each signed assembly, create an AssemblyCatalog and add it to the AggregateCatalog. If you want to filter down to a more granular level such as the type, then look through each assembly and collect all the types, then create a TypeCatalog passing in all the types.

Glenn

 

Aug 28, 2009 at 9:30 AM

Thankyou very much indeed for the clarification. Is there any code available to demonstrate the filtering process.

With Best Regards,

Rao.

Aug 31, 2009 at 3:45 PM

Now, I can compose only the signed assemblies, which is very good indeed. Thankyou very much indeed for bringing this technology.

 

Best Regards,

Rao.