如何使用ASP.NET MVC,WebAPI和MEF正确地确定每个请求的组合范围

时间:2013-12-27 18:57:33

标签: asp.net-mvc asp.net-web-api mef mef2

我最近使用各种资源(包括此SO答案How to integrate MEF with ASP.NET MVC 4 and ASP.NET Web API)将MEF添加到MVC / WebAPI应用程序中。虽然这工作了一段时间,但我开始收到与连接数据库相关的间歇性错误,最常见的错误是:“System.InvalidOperationException:Timeout expired。在从池中获取连接之前已经过了超时时间。这可能是已经发生,因为所有汇集的连接都在使用,并且达到了最大池大小。“

我意识到我正在泄漏连接,但不明白为什么。我的所有存储库都实现了IDisposable并在完成时处理了它们的连接。在我的配置方法中加入断点很快就会发现它们永远不会被击中。当我将代码基于上面链接的示例时,我注意到没有任何清理,但是对MEF和MVC不熟悉我错误地认为在MVC的/ MEF的依赖管道中正在进行清理。

我想知道其他人如何在MVC和WebAPI中使用MEF来解决每个请求的组合范围?

我在这里和那里找到了模糊的指导,它们都面向MVC或WebAPI。 Mef.codeplex在这里有一个几乎完整的MVC中心解决方案:https://mef.codeplex.com/releases/view/79090但它基于MVC的预览版本。我在这里找到了一个WebAPI解决方案:https://github.com/WebApiContrib/WebApiContrib.IoC.Mef。我现在正在推出自己的解决方案,但由于我不想重新发明轮子,我想我会问是否有人知道其中已经有一个滚动。

2 个答案:

答案 0 :(得分:5)

在我没有找到任何令我满意的东西之后,我最终在假日期间自己解决了这个问题。 CodePlex的MEF贡献有一个良好的开端,但尚未完成。我将其与一些修改合并,并将其与一些研究和反复试验相结合。

我在Github上创建了一个项目(链接如下,我知道外部链接不受欢迎,但是包含内联的代码太多了)。这是四个项目。第一个提供核心组合和拆解,两个库分别将核心放入MVC和WebAPI的上下文中,最后一个只是一个带有两个控制器的快速示例MVC应用程序,每个控制器依赖于另一个注入的类。有一点需要注意,我认为WebAPI项目尚未完成,因为它尚未包含WebAPI过滤器提供程序的设施(也许还有其他我尚未想到或尚未完成的事情)。

我希望这会有所帮助。

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

答案 1 :(得分:2)

哇谢谢。我也有一个解决这个问题的方法,虽然采用了更为简单的方法,但我已经证实了内存使用的显着减少。我创建了一个MefDependencyResolver,它在BeginScope方法中而不是像我们在其他示例中看到的那样返回'this',我创建了一个基于过滤目录的子容器,如mef codplex网站http://mef.codeplex.com/wikipage?title=Filtering%20Catalogs&referringTitle=Parts%20Lifetime所示。

我的WebAPI测试项目首先使用实体​​框架代码将实体存储在数据库中。

我创建了一个测试客户端,将15000个实体发送到数据库中,在每次测试中我运行了3个并发客户端,重复测试3次。使用begin scope返回'this'和Dispose方法中的NOOP,我最大化了为ApplicationPool分配的内存。通过返回基于过滤目录的新容器并将容器放置在Dispose方法中并重复测试内存增加到600MB并保持IIS仍然满意并且没有发生池回收。

 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
}