How to properly scope composition per request using ASP.NET MVC, WebAPI, and MEF

被刻印的时光 ゝ 提交于 2019-12-05 09:42:35

I ended up tackling this problem myself over the holidays after not finding anything to my satisfaction. MEF contrib on CodePlex had a good start but it was unfinished. I incorporated it with a few modification and combined that with some research and trial and error.

I've created a project on Github (link below, I know external links are frowned upon but it's just too much code to include inline). In it are four projects. The first provides core composition and teardown, the two libraries put the core into the context of MVC and WebAPI respectively, and the last is just a quick sample MVC app with two controllers that each depend on another class which is injected. One caveat, I consider the WebAPI project unfinished as it doesn't yet include facilities for WebAPI filter providers (and maybe other things I haven't thought of or needed yet).

I hope this helps.

https://github.com/rlvandaveer/Heliar-Web-Composition

John

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
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!