1
votes

I've been wrestling with this issue for about two weeks now and have cut it back to one very specific test.

Bascially I've got a session factory which configures the NHibernate session factory and has a function which [Export(typeof(ISession))].

The code for this class is as follows:

    [Export(typeof(SessionFactoryMock))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class SessionFactoryMock
{
    private readonly ISessionFactory sessionFactory;        

    public SessionFactoryMock()
    {
        sessionFactory =
                Fluently.Configure()
                .Database(
                    MsSqlConfiguration.MsSql2008.ConnectionString(c => c
                        .Server(@".\SQLExpress")
                        .Database("Test")
                        .TrustedConnection()))
                .Mappings(configuration => configuration.FluentMappings.Add<TestEntityMap>())
                .ExposeConfiguration(c => new SchemaExport(c).Execute(true, true, false))                    
                .BuildSessionFactory();            
    }

    [Export(typeof(ISession))]
    public ISession GetSession()
    {
        return sessionFactory.OpenSession();
    }
}

And I'm using the following test:

    [TestMethod]
public void CanGetISession()
{
    Assembly executing = Assembly.GetExecutingAssembly();
    var cat = new AggregateCatalog(new[]
        {
            new AssemblyCatalog(executing)
        });

    var container = new CompositionContainer(cat);

    var batch = new CompositionBatch();
    batch.AddExportedValue(container);

    container.Compose(batch);

    var compositionInfo = new CompositionInfo(cat, container);
    using (var stringWriter = new StringWriter())
    {
        CompositionInfoTextFormatter.Write(compositionInfo, stringWriter);
        string compositionDetail = stringWriter.ToString();
        bool errorDetected = compositionDetail.Contains("[Primary Rejection]");

        if (errorDetected)
        {
            Assert.Fail(compositionDetail);
        }
    }

    var export = container.GetExport<ISession>();
    var exportedValue = export.Value;
    Assert.IsNotNull(exportedValue);
}

This test will continually fail with the message:

System.ComponentModel.Composition.CompositionContractMismatchException: Cannot cast the underlying exported value of type 'MefnHibernateFail.SessionFactoryMock.GetSession (ContractName="NHibernate.ISession")' to type 'NHibernate.ISession'.

Which is extremely unhelpful.

I'm building all the Fluent nHibernate and NHibernate libraries from code and I have an example solution.

I'm really hoping someone can shed some light on this because I'm pretty much at a dead end now.

Full source code can be found here: Source

1
Sigh... wish people would stop using MEF. It's terrible when used as an IoC container. - Phill
Most probably some assembly is being loaded twice from different locations. Have a look at this answer stackoverflow.com/a/14320296/850119. By the way why are you exporting the container? You can avoid MEF completely during your unit tests. - Panos Rontogiannis
Hi Panos - Yes you'd think that, but I've checked and double checked the references and I just can't see it. It is definately due to composition, as I had another example test where one test would pass and another would fail for essentially the same thing. The container isn't being exported for any reason relavent to the test. And I could avoid MEF completely in my tests it they weren't specifically trying to test the composition. - Adam Hardy
Playing around with it today, trying to step through the .Net libraries. I decided to change the GetSession() function to a property getter, and the test passes. Very weird. - Adam Hardy

1 Answers

0
votes

For anyone else having the same issue. The problem was that the export on the function should be [Export(typeof(Func<ISession>)] not [Export(typeof(ISession))]. MEF passes the function pointer not the pointer to the returned object (which is why my function was never called).