C# Unity IoC在运行时突然失败
我在WebAPI2中有一个控制器,并使用Unity将依赖项注入其中。在我的日志中突然出现这些异常之前,这似乎工作得很好。前两行来自控制器的成功调用(之前的数百次调用工作正常),其余两行来自失败的调用(有数百次失败的异常)。当控制器在同一次运行中也正常工作时,在运行时什么会触发这些异常?应用程序池被自动回收(从日志中的低ms数可以看出),控制器再次正常工作(我想直到它再次变坏为止) Unity在WebApiConfig.cs中注册如下:C# Unity IoC在运行时突然失败,c#,exception,runtime,inversion-of-control,C#,Exception,Runtime,Inversion Of Control,我在WebAPI2中有一个控制器,并使用Unity将依赖项注入其中。在我的日志中突然出现这些异常之前,这似乎工作得很好。前两行来自控制器的成功调用(之前的数百次调用工作正常),其余两行来自失败的调用(有数百次失败的异常)。当控制器在同一次运行中也正常工作时,在运行时什么会触发这些异常?应用程序池被自动回收(从日志中的低ms数可以看出),控制器再次正常工作(我想直到它再次变坏为止) Unity在WebApiConfig.cs中注册如下: var container = new Un
var container = new UnityContainer();
container.RegisterType<IEventMapping, EventMapping>(new HierarchicalLifetimeManager());
container.RegisterType<IMessageQueue, MessageQueue>(new HierarchicalLifetimeManager());
container.RegisterInstance<IMapper>(new MapperConfiguration(cfg => {
cfg.CreateMap<Event, EventDTO>();
}).CreateMapper());
config.DependencyResolver = new UnityResolver(container);
config.Filters.Add(new LogExceptionFilterAttribute());
config.Services.Add(typeof(IExceptionLogger), new LogExceptionLogger());
var container=newunitycontainer();
RegisterType(新的层次结构CallifetimeManager());
RegisterType(新的层次结构CallifetimeManager());
container.RegisterInstance(新的MapperConfiguration(cfg=>{
CreateMap();
}).CreateMapper());
config.DependencyResolver=新的UnityResolver(容器);
添加(新的LogExceptionFilterAttribute());
Add(typeof(ieexceptionlogger),newlogexceptionlogger());
这是UnityResolver:
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
公共类UnityResolver:IDependencyResolver
{
受保护的IUnity容器;
公共单元Resolver(IUnityContainer容器)
{
if(容器==null)
{
抛出新的ArgumentNullException(“容器”);
}
this.container=容器;
}
公共对象GetService(类型serviceType)
{
尝试
{
返回容器解析(serviceType);
}
捕获(解决失败异常)
{
返回null;
}
}
公共IEnumerable GetServices(类型serviceType)
{
尝试
{
返回容器.ResolveAll(serviceType);
}
捕获(解决失败异常)
{
返回新列表();
}
}
公共IDependencyScope BeginScope()
{
var child=container.CreateChildContainer();
返回新的UnityResolver(子项);
}
公共空间处置()
{
container.Dispose();
}
}
真正的异常被一扫而光,您不可能看到真正的原因。发生这种情况的原因是:
- 在Web API设计中,如果出现错误,强制
返回nullidependencysolver.GetService
- 实现
的方式UnityResolver
idependencysolver.GetService
方法捕获所有resolutionfailedeexception
s并返回null,因此您将丢失重要的异常信息。最好的解决方案是完全避免使用idependencysolver
抽象,或者至少确保使用适当的抽象来解析控制器:IHttpControllerActivator。下面是一个例子:
公共密封类单元控制器激活器:IHTTPC控制器激活器
{
私有只读UnityContainer容器;
公共UnityController激活器(UnityContainer容器){
this.container=容器;
}
公共IHTTP控制器创建(HttpRequestMessage请求,
HttpControllerDescriptor控制器描述器,类型控制器类型){
//在调用resolve之前,请确保存在活动作用域。
request.GetDependencyScope();
返回(IHttpController)this.container.Resolve(controllerType);
}
}
您可以在Unity中注册此UnityController激活器,如下所示:
configuration.Services.Replace(typeof(IHttpControllerActivator),
new UnityControllerActivator());
这确保了Web API将使用此自定义的UnityControllerActivator
,而不是使用其DefaultHttpControllerActivator
。DefaultHttpControllerActivator
调用IDependencyResolver
,但它可以返回null
。相反,我们的自定义UnityControllerActivator
将直接调用Unity,并且永远不会返回null
。相反,Unity引发的原始异常被保留并记录。这允许您分析真正的原因。如果这个新的异常对您没有意义,您可能想回到这里,问一个关于Stackoverflow的新问题。谢谢。我自己的构造函数很简单。但是对控制器的调用很慢(相隔几秒钟),因此请求重叠的风险非常小。但我认为我的代码中没有任何并发性问题。我是否仍然应该使用config.dependencysolver=newunityresolver(容器)
?@galmok:是否替换默认的依赖解析程序
,取决于您是否使用Unity解析Web API请求的其他服务。一般来说,我会说您只想拦截控制器的创建,因此不再需要UnityResolver
。建议的解决方案存在问题。当我向HierarchyCallifeTimeManager注册类型时,注册的对象仍然会在每次调用控制器实例化时重用。如果没有建议的解决方案,生命周期与控制器方法调用相同。我将如何修改您的解决方案t
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
configuration.Services.Replace(typeof(IHttpControllerActivator),
new UnityControllerActivator());