我最近使用各种资源(包括此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。我现在正在推出自己的解决方案,但由于我不想重新发明轮子,我想我会问是否有人知道其中已经有一个滚动。
答案 0 :(得分:5)
在我没有找到任何令我满意的东西之后,我最终在假日期间自己解决了这个问题。 CodePlex的MEF贡献有一个良好的开端,但尚未完成。我将其与一些修改合并,并将其与一些研究和反复试验相结合。
我在Github上创建了一个项目(链接如下,我知道外部链接不受欢迎,但是包含内联的代码太多了)。这是四个项目。第一个提供核心组合和拆解,两个库分别将核心放入MVC和WebAPI的上下文中,最后一个只是一个带有两个控制器的快速示例MVC应用程序,每个控制器依赖于另一个注入的类。有一点需要注意,我认为WebAPI项目尚未完成,因为它尚未包含WebAPI过滤器提供程序的设施(也许还有其他我尚未想到或尚未完成的事情)。
我希望这会有所帮助。
答案 1 :(得分:2)
我的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
}