3
votes

I use MEF, WebAPI in VS 2012.

I get error

"exceptionMessage":"An error occurred when trying to create a controller of type 'ClienteController'. Make sure that the controller has a parameterless public constructor.","exceptionType":"System.InvalidOperationException"

I have in Global.asax.cs:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        AggregateCatalog catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
        CompositionContainer container = MEFLoader.Init(catalog.Catalogs);
        DependencyResolver.SetResolver(new MefDependencyResolver(container)); // view controllers
        GlobalConfiguration.Configuration.DependencyResolver = new MefAPIDependencyResolver(container); // web api controllers

    }

In my MEFLoader class

    public static CompositionContainer Init(ICollection<ComposablePartCatalog> catalogParts)
    {
        var catalog = new AggregateCatalog();

        catalog.Catalogs.Add(new AssemblyCatalog(typeof(BuscadorClient).Assembly));
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Core.DataRepositoryFactory).Assembly));
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Comun.DataContract.BusinessFault).Assembly));

        if (catalogParts != null)
            foreach (var part in catalogParts)
                catalog.Catalogs.Add(part);

        var container = new CompositionContainer(catalog);
        return container;
    }

Assemblies has in the bin folder of the website for the Webapi Application, in the Integration environment .

Notes:

In Development environment, dev local, sometimes failed and solution was "recompile" the WebApi App Project (csproj)

Anyways, in Integration environment failed.

Microsoft.Internal.Collections.WeakReferenceCollection1.<CleanupDeadReferences>b__0(WeakReference w)\r\n at System.Collections.Generic.List1.RemoveAll(Predicate1 match)\r\n at Microsoft.Internal.Collections.WeakReferenceCollection1.Add(T item)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.StartSatisfyingImports(PartManager partManager, AtomicComposition atomicComposition)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(PartManager partManager, ComposablePart part, Boolean shouldTrackImports)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImports(ComposablePart part)\r\n at System.ComponentModel.Composition.Hosting.CompositionServices.GetExportedValueFromComposedPart(ImportEngine engine, ComposablePart part, ExportDefinition definition)\r\n at System.ComponentModel.Composition.Hosting.CatalogExportProvider.GetExportedValue(CatalogPart part, ExportDefinition export, Boolean isSharedPart)\r\n at System.ComponentModel.Composition.Primitives.Export.get_Value()\r\n at System.ComponentModel.Composition.ReflectionModel.ImportingItem.CastSingleExportToImportType(Type type, Export export)\r\n at System.ComponentModel.Composition.ReflectionModel.ReflectionComposablePart.SetImport(ImportingItem item, Export[] exports)\r\n at System.ComponentModel.Composition.ReflectionModel.ReflectionComposablePart.SetImport(ImportDefinition definition, IEnumerable1 exports)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.PartManager.TrySetImport(ImportDefinition import, Export[] exports)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImportSubset(PartManager partManager, IEnumerable1 imports, AtomicComposition atomicComposition)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImportsStateMachine(PartManager partManager, ComposablePart part)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(PartManager partManager, ComposablePart part, Boolean shouldTrackImports)\r\n at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImports(ComposablePart part)\r\n at System.ComponentModel.Composition.Hosting.CompositionServices.GetExportedValueFromComposedPart(ImportEngine engine, ComposablePart part, ExportDefinition definition)\r\n at System.ComponentModel.Composition.Hosting.CatalogExportProvider.GetExportedValue(CatalogPart part, ExportDefinition export, Boolean isSharedPart)\r\n at System.ComponentModel.Composition.Primitives.Export.get_Value()\r\n at COMPANY..Core.MefExtensions.GetExportedValueByType(CompositionContainer container, Type type) in

1
Maybe problem with multi-threadingKiquenet
I suggest marking the answer by YifanLu as correct. MEF will inexplicably barf when used with ASP.NET controllers, and the only clue is in the WeakReferenceCollection cleanup. The container must be instantiated as thread-safe.tomo

1 Answers

6
votes

Not sure if anyone is still interested in the answer, but I hit the same problem in my WebApi service which using MEF as IoC. The composition container is created at start up time with list of customized export providers.

The cause of my problem is that the export providers are not created using the thread safe constructor.

In that case besides set the thread safety option when creating CompositionContainer, you should also create all your customized export providers using the constructor that set thread safe to be true.

var aggregate = new AggregateCatalog(assemblyCatalogs);
//create default export provider to be thread safe
var defaultExportProvider = new CatalogExportProvider(aggregate, true);
_compContainer = new CompositionContainer(CompositionOptions.DisableSilentRejection|CompositionOptions.IsThreadSafe, defaultExportProvider);
defaultExportProvider.SourceProvider = _compContainer;