我最近把一个.Net Framework 4.7.2 MVC项目从Unity移到了Microsoft.Extensions.DependencyInjection,因为Unity已经被弃用了。这个切换看起来很简单,主要的变化是需要创建一个自定义的DependencyResolver
,因为这以前是由Unity处理的。
现在,这些更改已投入生产,我开始注意到一些严重的内存问题。获取内存使用情况转储显示,内存中最大的项目是Microsoft.Extensions.DependencyInjection的ServiceProvider
,其中包含数千个尚未处理的控制器。
依赖关系解析程序如下所示:
public class MicrosoftDefaultDependencyResolver
: System.Web.Mvc.IDependencyResolver
, System.Web.Http.Dependencies.IDependencyResolver
{
protected IServiceProvider serviceProvider;
public MicrosoftDefaultDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IDependencyScope BeginScope()
{
return new MicrosoftDefaultDependencyResolver(
this.serviceProvider.CreateScope().ServiceProvider);
}
public void Dispose()
{
}
public object GetService(Type serviceType)
{
return this.serviceProvider.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.serviceProvider.GetServices(serviceType);
}
}
我已经根据我读到的一篇stackoverflow文章实现了这个:How do I inject dependency in webapi in .net framework using Microsoft.Extensions.DependencyInjection?
Startup类类似于:
public void Configuration(IAppBuilder app)
{
// Set MVC Resolver
MicrosoftDefaultDependencyResolver resolver = GetDependencyResolver();
DependencyResolver.SetResolver(resolver);
// Any connection or hub wire up and configuration should go here
app.MapAzureSignalR(GetType().FullName);
// Turn tracing on programmatically
GlobalHost.TraceManager.Switch.Level = SourceLevels.Error;
}
由于我们仍然在使用.Net framework,看起来控制器没有自动注册,所以我不得不将它们显式注册为Transient。
我的问题是,我是不是完全忽略了什么?我希望迁移到Microsoft DI包时,它的工作方式与新版本的.Net相同,但我现在觉得迁移到一个完全不同的IoC框架(如Autofaq)来解决这些内存问题更容易。
2条答案
按热度按时间pexxcrt21#
你的
MicrosoftDefaultDependencyResolver
有缺陷。如果你看一下
System.Web.Mvc.IDependencyResolver
的定义,你会注意到没有BeginScope
方法。MVC不会自动启动一个作用域。这意味着你所有的MVC控制器都是从根作用域/容器解析的。任何从根容器解析的作用域或暂时的可释放依赖项都将被永远引用。正如您可能注意到的,只有MVC控制器保持引用; Web API控制器没有此问题。这是因为
System.Web.Http.Dependencies.IDependencyResolver
定义实际上包含BeginScope
方法,并且ASP.NET Web API在每个请求开始时主动调用此方法。这意味着Web API控制器是从特定于请求的IServiceScope
解析的,并且此范围将自动进行垃圾回收。但是,在您的Web API实现中仍然存在一个bug,因为您没有处理
IServiceScope
方法。虽然Web API控制器会自动被处理,但来自容器的其他服务不会。注意:我想说MVC中的DI实现有点缺陷,但这可能是API团队首先创建新的
IDependencyResolver
接口的原因。因此,MVC的解决方案是(以某种方式)确保在每个请求上创建
IServiceScope
,MVC控制器从该作用域得到解析,并且在请求结束时处理该作用域。有几种方法可以做到这一点,但最简单的方法可能是挂钩到
Application
事件。在此之后,最好创建一个单独的类来作为
System.Web.Mvc.IDependencyResolver
的适配器。这个实现可以利用存储的IServiceScope
:为了完整起见,Web API依赖项解析器可能应该如下所示:
最后要注意的是,两个依赖关系解析器实现仍然会导致控制器类型被释放两次,这是因为MVC和Web API也会释放控制器。然而,在正常情况下,这应该不会导致任何问题。
jjjwad0x2#
我本可以尝试Steven的答案,但对于使用Unity时需要很少输入的东西来说,这是非常复杂的。为了简单起见,我切换到使用AutoFac,在最小的工作量内,内存问题已经消失。