katit
katit

Reputation: 17905

MEF composition import issue when using specific interface

I work with MEF for a long time and once in a while it just drives me crazy. Have NO idea what it needs.

I have 2 files that we interested in:

  1. My EXE with 2 classes:

JobFactory : IJobFactory and SaferWatchProcessor : IJob

  1. Quartz.net DLL which have those interfaces definitions

Creating container:

var aggregateCatalog = new AggregateCatalog(
                new DirectoryCatalog(".", "*.dll"),
                new DirectoryCatalog(".", "*.exe"));

            Bootstrapper.CompositionContainer = new CompositionContainer(aggregateCatalog, true);

catalog now have JobFactory but NO SaferWatchProcessor. Why?

enter image description here

Here is classes:

[Export(typeof(IJob))]
public class SaferWatchProcessor : IJob
{
    public void Execute(IJobExecutionContext context)
    {
        Debug.WriteLine("SaferWatchProcessor.Execute");
    }
}

SaferWatchProcessor has nothing there, just one method. Has Export attribute.

[Export(typeof(IJobFactory))]
    public class JobFactory : IJobFactory
    {
        [ImportMany(typeof(IJob))]
        public List<IJob> Jobs { get; private set; }

        public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            IJobDetail jobDetail = bundle.JobDetail;
            Type jobType = jobDetail.JobType;
            try
            {
                Debug.WriteLine("IDATT.WindowsService.JobFactory - creating job instance");
                return this.Jobs.First();
            }
            catch (Exception e)
            {
                var se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Problem instantiating class '{0}'", jobDetail.JobType.FullName), e);
                throw se;
            }
        }

        public virtual void ReturnJob(IJob job)
        {
        }
    }

JobFactory has ImportMany (which doesn't fail, but has 0 items)

I tried to set it as single Import and was getting following error:

System.ComponentModel.Composition Warning: 1 : The ComposablePartDefinition 'IDATT.WindowsService.JobFactory' has been rejected. 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.

    1) No exports were found that match the constraint: 
        ContractName    Quartz.IJob
        RequiredTypeIdentity    Quartz.IJob

    Resulting in: Cannot set import 'IDATT.WindowsService.JobFactory.Jobs (ContractName="Quartz.IJob")' on part 'IDATT.WindowsService.JobFactory'.
    Element: IDATT.WindowsService.JobFactory.Jobs (ContractName="Quartz.IJob") -->  IDATT.WindowsService.JobFactory -->  DirectoryCatalog (Path=".")

    A first chance exception of type 'System.InvalidOperationException' occurred in IDATT.WindowsService.exe

Nothing seems to be wrong, but why it doesn't want to import IJob?

EDIT:

I removed all IJob definitions and use plain Export/Import and added debugging for MEF. Still problem and here is error:

[Part] IDATT.WindowsService.JobFactory from: DirectoryCatalog (Path="C:\CodeWorkspace\IdattLC\ClientServerCode\IDATT.WindowsService\bin\Debug\")
  [Primary Rejection]
  [Export] IDATT.WindowsService.JobFactory (ContractName="Quartz.Spi.IJobFactory")
  [Import] IDATT.WindowsService.JobFactory.SaferWatchProcessor (ContractName="IDATT.WindowsService.Jobs.SaferWatchProcessor")
    [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint: 
    ContractName    IDATT.WindowsService.Jobs.SaferWatchProcessor
    RequiredTypeIdentity    IDATT.WindowsService.Jobs.SaferWatchProcessor
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition)
   at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)

Upvotes: 4

Views: 9840

Answers (2)

katit
katit

Reputation: 17905

Ok, I figured it out hard way. I thought it will be useful to post my findings.

What happened is that I installed MEF 2 from NuGet, new lightweight MEF for 4.5 and Windows store.

All my existing libraries was built with regular old MEF using System.ComponentModel.Composition and for this problematic import ReSharper suggested couple namespaces and I used import using System.Composition for Export attribute

not sure what good in MEF 2, but it's not going to work with existing libraries/exports against regular MEF so be careful!

Upvotes: 2

ogggre
ogggre

Reputation: 2266

Here is a quick check list:

  • Ensure that assembly with SaferWatchProcessor type is physically copied to catalog folder
  • Ensure that corresponding assemblies are fresh and have correct time stamps in catalog folder
  • Ensure that SaferWatchProcessor type really exports Quartz.IJob. It is a common mistake when people are trying to export an empty interface created by Visual Studio instead of referencing the real one

Upvotes: 1

Related Questions