Wow thanks. I also had a go at resolving this, Though much simpler approach I have confirmed a dramatic reduction in memory use. I created a MefDependencyResolver Which in the BeginScope method instead of returning 'this' as we have seen in other examples, I create a child container based on a filtered catalog as shown in the mef codplex site http://mef.codeplex.com/wikipage?title=Filtering%20Catalogs&referringTitle=Parts%20Lifetime.
My WebAPI test project uses entity framework code first to store entities in a DB.
I created a test client to POST 15000 entities into the database, in each test I ran 3 concurrent clients, repeating the test 3 times. With begin scope returning 'this' and a NOOP in the Dispose method I maxed out the memory allocated for the ApplicationPool. By returning a new container based on a filtered catalogue and disposing the container in the Dispose method and repeating the test Memory increased to 600MB and stayed there IIS remain happy and no pool recycling occurred.
public class MefDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
protected CompositionContainer _container;
public MefDependencyResolver(CompositionContainer container)
{
_container = container;
}
public IDependencyScope BeginScope()
{
var filteredCat = new FilteredCatalog(_container.Catalog,
def => def.Metadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName) &&
((CreationPolicy)def.Metadata[CompositionConstants.PartCreationPolicyMetadataName]) == CreationPolicy.NonShared);
var child = new CompositionContainer(filteredCat, _container);
return new MefDependencyResolver(child);
}
/// <summary>
/// Called to request a service implementation.
///
/// Here we call upon MEF to instantiate implementations of dependencies.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>Service implementation or null.</returns>
public object GetService(Type serviceType)
{
if (serviceType == null)
throw new ArgumentNullException("serviceType");
var name = AttributedModelServices.GetContractName(serviceType);
var export = _container.GetExportedValueOrDefault<object>(name);
if (export != null)
{
Trace.WriteLine("PAUSE");
}
return export;
}
/// <summary>
/// Called to request service implementations.
///
/// Here we call upon MEF to instantiate implementations of dependencies.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>Service implementations.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
if (serviceType == null)
throw new ArgumentNullException("serviceType");
var exports = _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
return exports;
}
#region IDisposable
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing) // Managed:
{
//NOOP since MEF does not have the idea of a Scoped Container (except it does have a concept of a filtered container!)
//
Trace.WriteLine("DISPOSING MEF CONTAINER.");
this._container.Dispose();
this._container = null;
}
// Unmanaged:
_disposed = true;
}
}
~MefDependencyResolver()
{
Dispose(false);
}
#endregion
}