6

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

我意识到我正在泄漏连接,但不明白为什么。我所有的存储库都实现了 IDisposable 并在完成后处理了它们的连接。在我的 dispose 方法中设置断点很快就会发现它们从未被命中。当我基于上面链接的示例的代码时,我注意到缺少任何清理,但是作为 MEF 和 MVC 的新手,我错误地认为清理是在 MVC/MEF 的依赖管道中的某个地方完成的。

我想知道其他人如何使用 MEF 在 MVC 和 WebAPI 中根据每个请求正确范围组合?

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

4

2 回答 2

5

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

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

我希望这有帮助。

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

于 2014-02-13T17:26:43.970 回答
2

哇谢谢。我也尝试过解决这个问题,尽管方法更简单,但我已经确认内存使用量显着减少。我在 BeginScope 方法中创建了一个 MefDependencyResolver,而不是像我们在其他示例中看到的那样返回“this”,而是根据 mef codplex 站点http://mef.codeplex.com/中所示的过滤目录创建了一个子容器wikipage?title=Filtering%20Catalogs&referringTitle=Parts%20Lifetime

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

我创建了一个测试客户端将 15000 个实体 POST 到数据库中,在每个测试中我运行 3 个并发客户端,重复测试 3 次。随着开始范围返回“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
}
于 2014-02-14T17:35:11.623 回答