MEF Composition .NET 4.0 - mef

Thanks in advance for your assistance. I have the following exported part:
[Export (typeof(INewComponent))] // orignally tried just [Export} here and importing NewComponent below
public class NewComponent : INewComponent
{
// does stuff including an import
}
The Console test program imports the above:
public class Program
{
[Import] // have tried variations on importing "NewComponent NewComponent" etc
public INewComponent NewComponent
{
get;
set;
}
public static void Main(string[] args)
{
var p = new Program();
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(p);
}
The Composition fails with these CompositionExceptions (I removed the namespace to protect the guilty :)):
1) No valid exports were found that match the constraint
'((exportDefinition.ContractName == "INewComponent") AndAlso
(exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso
"INewComponent".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))',
invalid exports may have been rejected.
The Composition works successfully if I do the composition in the main program like this:
public class Program
{
public static void Main(string[] args)
{
INewComponent newComponent = new NewComponent();
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(newComponent);
}
}
Thank You

Is your Exported part contained in the same Assembly as Program? If it is in a separate DLL, you need to include that Assembly in your catalog as well, like this:
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(NewComponent).Assembly));
var container = new CompositionContainer(aggregateCatalog);
// etc...
If that's doesn't work, then there is a nice open source tool called Visual MEFx that can help you analyze your catalog. Here is a short article about setting it up:
Getting Started With Visual MEFx

In your NewComponent class you wrote this:
// does stuff including an import
If there is a problem with that unshown import, then MEF will complain about the Program.NewComponent import instead of the actual deeper cause. This is called "stable composition". Stable composition can be useful, but it also complicates the debugging of a failed composition.
You can follow the instructions in the MEF documentation about Diagnosing Composition Errors to home in on the actual cause.
In a small program, you can also try to call container.GetExportedValue<ISomeExport>() for a few exports until you find the one that is causing problems.

Related

MEF does not load all expected components

I have a core MEF implementation that gives me a bad headache...
In each of three separate assemblies I created an IService implementation.
All three classes looks similar like this:
[Export(typeof(IService))]
public class ClassX : IService {}
Now I have an implementaton that tries loading all three of them.
The loader assembly is in the same folder as all three service implementations
The code that loads the 3 parts looks like:
public class ClassLoader
{
[ImportMany(typeof(IService))]
public IEnumerable<IService> Services { get; set; }
public async Task<bool> LoadAsync(CancellationTokenSource cts, string path)
{
var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly)
.Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)
.Where(s => s.GetTypes().Where(p => typeof(IService).IsAssignableFrom(p)).Any())
.Select(a => new AssemblyCatalog(a)).ToList();
var catalog = new AggregateCatalog();
assemblies.ForEach(a => catalog.Catalogs.Add(a));
var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);
container.ComposeParts(this);
....
}
}
This code only loads 2 of three assemblies.
My question is, any suggestions why on of them is not loaded?
But maybe more helpfull are their ways to find out why a particular type is not loaded. I hoped that the compositionoption gave me an error, but I didn't in this case.
What are the best debugging possibilities?
Thanks already for sharing any ideas.

GWT Arrays.asList not working on interface types

Working on a GWT project (2.7.0), i have experienced a very odd client code behaviour.
The following code throws the error "SEVERE: (ReferenceError) : Ljava_io_Serializable_2_classLit_0_g$ is not definedcom.google.gwt.core.client.JavaScriptException: (ReferenceError) : Ljava_io_Serializable_2_classLit_0_g$ is not defined".
The error occurs, when calling Arrays.asList() with a parameter, that has an interface type.
Is this expected behaviour or a GWT bug?
// Working
Integer n1 = 1;
Arrays.asList(n1);
// Not working
Serializable n2 = 1;
Arrays.asList(n2);
GWT 2.7's Super Dev Mode (and from the _g$ in your class literal field, I think that is what you are using) has been observed having other issues like this, but when compiled the issues go away.
If this is indeed what you are seeing, the issue seems to be fixed in 2.8, not yet released: https://groups.google.com/d/topic/google-web-toolkit/RzsjqX2gGd4/discussion
This behavior is definitely not expected, but if you can confirm that this works correctly when compiled for production and in GWT 2.8, then we at least know the bug is fixed.
Well, the typical use of Arrays.asList would be
Object myObj = new Object();
List theList = Arrays.asList(new Object[] {myObj});
This works in GWT with any kind of interface/class/enum you throw at it.
EDIT : I've tested this with GWT 2.5.1 :
public class Foo implements EntryPoint {
public static interface MyInterface {
}
public static class MyObject implements MyInterface {
}
public void onModuleLoad() {
MyInterface myObject = new MyObject();
List<MyInterface> myList = Arrays.asList(myObject);
}
}
Isn't it possible that the problem lies somewhere else?

MSTest fails when I do run all, but works otherwise

So I have a Testclass using MSTest and every test works great if I run them one and one, however if I select 2 tests, namely can_register and cannot_Register_existing_username then the second fails (cannot_register_existing_username).
I have let my testclass inherit from an abstract class that looks like this:
public abstract class RollbackCapabilities
{
private TransactionScope _transactionScope;
[TestInitialize]
public virtual void TestInitialize()
{
_transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { Timeout = new TimeSpan(0, 10, 0) });
}
[TestCleanup]
public virtual void TestCleanup()
{
Transaction.Current.Rollback();
_transactionScope.Dispose();
}
}
If I comment this file out then it works (but now the data remains in the test-db which I don't want).
With this file above active the second test fails, the tests look like this
[TestMethod]
public void Can_Register()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password= "TestPassword";
model.ConfirmPassword = "TestPassword";
//Act
ActionResult result = ac.Register(model);
//Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
Assert.AreEqual("Home", ((RedirectToRouteResult)result).RouteValues["controller"]);
Assert.AreEqual("Index", ((RedirectToRouteResult)result).RouteValues["action"]);
}
[TestMethod]
public void Cannot_Register_Existing_Username()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password = "TestPassword";
model.ConfirmPassword = "TestPassword";
ac.Register(model);
RegisterModel model2 = new RegisterModel();
model2.UserName = "TestUser";
model2.Password = "OtherTestPassword";
model2.ConfirmPassword = "OtherTestPassword";
//Act
ActionResult result = ac.Register(model2);
//Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
Assert.AreEqual("", ((ViewResult)result).ViewName);
Assert.AreEqual(model2, ((ViewResult)result).ViewData.Model);
}
and finally the error i get is as follows:
Test method
Viducate.UnitTests.UserHandling.RegisterTests.Cannot_Register_Existing_Username
threw exception: System.Data.EntityCommandExecutionException: An
error occurred while executing the command definition. See the inner
exception for details. ---> System.Data.SqlClient.SqlException:
Invalid object name 'dbo.Users'.
Thats my problem, not big but very annoying and as mentioned if I run the tests one and one it works, it also works but leaves data in the db if I comment out my RollbackCapabilities class
Okay so I found out that my error was that I had created the database (but not tables) by hand because create database is not supported in multi-transaction.
however creating an empty database means that EF assumes there is tables already and that is why it failed with dont know what dbo.users are.
So what I did was created the tables as well and now it works. However this means I can never run this on a new development machine without first creating the tables and database. so annoying.
I think I will set up another test class that does not inherit my abstract rollback class and hade that create the tables permanently... should solve the problem as long as that runs first.

MEF: how to import from an exported object?

I have created a MEF plugin control that I import into my app. Now, I want the plugin to be able to import parts from the app. I can't figure how setup the catalog in the plugin, so that it can find the exports from the app. Can somebody tell me how this is done? Below is my code which doesn't work when I try to create an AssemblyCatalog with the current executing assembly.
[Export(typeof(IPluginControl))]
public partial class MyPluginControl : UserControl, IPluginControl
[Import]
public string Message { get; set; }
public MyPluginControl()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
CompositionContainer container = new CompositionContainer(catalog);
try
{
container.ComposeParts(this);
}
catch (CompositionException ex)
{
Console.WriteLine(ex.ToString());
}
}
}
You don't need to do this.
Just make sure that the catalog you're using when you import this plugin includes the main application's assembly.
When MEF constructs your type in order to export it (to fulfill the IPluginControl import elsewhere), it'll already compose this part for you - and at that point, will import the "Message" string (though, you most likely should assign a name to that "message", or a custom type of some sort - otherwise, it'll just import a string, and you can only use a single "string" export anywhere in your application).
When MEF composes parts, it finds all types matching the specified type (in this case IPluginControl), instantiates a single object, fills any [Import] requirements for that object (which is why you don't need to compose this in your constructor), then assigns it to any objects importing the type.

How come you can create an interface instance in Office Interop?

I've seen this quite a few times while using Office Interop classes
this.CustomXMLParts.Add(MyResources.Data, new Office.CustomXMLSchemaCollection());
If I hover over the CustomXMLSchemaCollection class, it shows up as an interface. Then how come I can do a new on it ? What gives?
BTW this code compiles and works.
You are not creating an instance of the CustomXMLSchemaCollection interface but an instance of the CustomXMLSchemaCollectionClass coclass.
The definition for CustomXMLSchemaCollection interface is:
[Guid("000CDB02-0000-0000-C000-000000000046")]
[CoClass(typeof(CustomXMLSchemaCollectionClass))]
public interface CustomXMLSchemaCollection : _CustomXMLSchemaCollection
{
}
This means that the designated coclass that implements the interface is CustomXMLSchemaCollectionClass. My guess is that when the C# compiler sees the new for CustomXMLSchemaCollection interface it translates it to create a COM instance of the CustomXMLSchemaCollectionClass based on the attributes provided with the interface.
After writing this simple example:
namespace ConsoleApplication2
{
using System;
using Office = Microsoft.Office.Core;
class Program
{
static void Main(string[] args)
{
Office.CustomXMLSchemaCollection test = new Office.CustomXMLSchemaCollection();
}
}
}
I just ran ildasm and get the following MSIL:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] class [Interop.Microsoft.Office.Core]Microsoft.Office.Core.CustomXMLSchemaCollection test)
IL_0000: nop
IL_0001: newobj instance void [Interop.Microsoft.Office.Core]Microsoft.Office.Core.CustomXMLSchemaCollectionClass::.ctor()
IL_0006: stloc.0
IL_0007: ret
} // end of method Program::Main
As you can see the class that is constructed is CustomXMLSchemaCollectionClass to prove my initial assumption.