Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I've just updated my MVC4 app to MVC5 and for some reason this appears to have completely broken my MEF implementation at the same time.

The code snippets below from my solutions have been running without a hitch for over a year and I'm not entire clear on what the solution is.

I have two solutions, an MVC5 web site and a MVC WebAPI 2 solution.

The error I'm seeing one the web site is:

"Currently composing another batch in this ComposablePartExportProvider. Only one batch can be composed at a time."

And on the WebAPI solution none of the [Import] marked fields in the controller classes are populated and generate "Object not set to an instance of an object". All very confusing considering the same code has been running for over a year with no problems.

From checking the container parts all the expected and required parts are present.

MVC5 Web Site Mef Config

public static class MefConfig
{
    public static void RegisterMef()
    {
        var container = ConfigureContainer();
        ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
        GlobalConfiguration.Configuration.DependencyResolver = new MefControllerFactory(container);
    }

    private static CompositionContainer ConfigureContainer()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
        catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(MoodConfig.AppBaseDirectory, @"bin\plugins")));

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

WebApi 2 Mef Config

public static class MefConfig
{
    public static void RegisterMef()
    {
        var container = ConfigureContainer();
        ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
        GlobalConfiguration.Configuration.DependencyResolver = new MefControllerFactory(container);
    }

    private static CompositionContainer ConfigureContainer()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
        catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(ConfigHelper.AppBaseDirectory, @"bin\plugins")));
        var container = new CompositionContainer(catalog, true);
        return container;
    }
}

MefControllerFactory

public class MefControllerFactory : DefaultControllerFactory, System.Web.Http.Dependencies.IDependencyResolver
{
    private readonly CompositionContainer _compositionContainer;

    private bool _disposed;

    public MefControllerFactory(CompositionContainer compositionContainer)
    {
        _compositionContainer = compositionContainer;
    }

    public IDependencyScope BeginScope()
    {
        return this;
    }

    public object GetService(Type serviceType)
    {
        var export = _compositionContainer.GetExports(serviceType, null, string.Empty).SingleOrDefault();

        return null != export ? export.Value : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var exports = _compositionContainer.GetExports(serviceType, null, string.Empty);
        return exports.Select(export => export.Value).ToList();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            var baseMessage = "Not Found, controllerType is null";
            if (requestContext != null)
            {
                throw new HttpException(404, string.Format("{0} RequestedUrl: {1}", baseMessage, requestContext.HttpContext.Request.Url));
            }

            throw new HttpException(404, baseMessage);
        }

        var export = _compositionContainer.GetExports(controllerType, null, string.Empty).SingleOrDefault();

        IController result;

        if (null != export)
        {
            result = export.Value as IController;
        }
        else
        {
            result = base.GetControllerInstance(requestContext, controllerType);
            _compositionContainer.ComposeParts(result);
        }

        return result;
    }

    private void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
            }
        }

        _disposed = true;
    }
}

All the controllers in both solutions are marked like this:

[Export(typeof(MyController)), PartCreationPolicy(CreationPolicy.NonShared)]

What I'm finding really confusing is that this same code has been running witout problems for a long time and since I haven't changed the .NET version (4.5) this should be running the same MEF code.

There is obviously a problem with what I'm doing and I've read that changing from using the ComposeParts method to using the SatisfyImportsOnce method fixes the issue. When I changed the code to use this method I no longer get the batch composing error but my [Import] properties are still null on the API controllers despite the parts being in the container.

I'm really not clear on why this has started happening in the first place after upgrading the the newer version of MVC and WebAPI and I'm unclear on what the final solution is.

My implementation is largely based on this:

http://kennytordeur.blogspot.co.uk/2012/08/mef-in-aspnet-mvc-4-and-webapi.html

Has anyone seen similar and fixed this? What was the fix in your situation?

share|improve this question
    
I've tried all manner of solutions since asking this question and its still thoroughly broken. It appears that WebAPI2 works drastically different in this regard, any info from anyone having gotten this to work would be helpful. –  Jammer Jun 20 at 13:37
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.