C# Unity IoC在运行时突然失败

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

我在WebAPI2中有一个控制器,并使用Unity将依赖项注入其中。在我的日志中突然出现这些异常之前,这似乎工作得很好。前两行来自控制器的成功调用(之前的数百次调用工作正常),其余两行来自失败的调用(有数百次失败的异常)。当控制器在同一次运行中也正常工作时,在运行时什么会触发这些异常?应用程序池被自动回收(从日志中的低ms数可以看出),控制器再次正常工作(我想直到它再次变坏为止)

Unity在WebApiConfig.cs中注册如下:

        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设计中,如果出现错误,强制
    idependencysolver.GetService
    返回null
  • 实现
    UnityResolver
    的方式
描述Web API的解析管道是如何工作的,以及为什么会收到这个愚蠢的“确保控制器具有无参数公共构造函数”异常消息。在链接问题中,OP没有明确注册他的控制器。但是,在您的情况下,问题是不同的,因为只有在某些情况下,您的控制器没有得到解决。我能想到为什么会发生这种情况的几个原因:

  • 您在注入构造函数中做的工作太多了。这会导致它们失败,因为某些外部系统(数据库、web服务等)不可用
  • 代码或Unity中存在并发错误
  • 由于您是
    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());