尝试从IInterceptor中的Ninject解析项目失败

时间:2014-05-04 04:01:29

标签: c# ninject ninject.web.mvc interception ninject-interception

我正在尝试在我当前的项目中使用Ninject,到目前为止,一直都喜欢它。我正在尝试配置一个IInterceptor对象来拦截和处理对我的服务层的失败方法调用。它托管在ASP.NET MVC 5应用程序中。

IInterceptor中,我尝试了几件事,例如:

  1. 使用构造函数注入设置私有变量,但后来发现看起来Ninject将无限期地重用IInterceptor实例,并且我还没有找到办法阻止它。由于我带入范围的其中一件事是DbContext,它被置于其他地方,因此最终未能在未来的任何请求上失败。

  2. 我发现IInvocationRequest.Kernel属性。但是,当我尝试从容器.InRequestScope()解析我的UOW时,它失败了,因为它试图解析IUowService依赖项,(其中一个依赖项依赖于HttpContext,它是null这一点),但似乎在请求范围之外这样做。它忽略了这样一个事实,即它需要的依赖项已经在ASP.NET请求中创建,并且正在尝试创建新的依赖项。

  3. 为拦截器this.Bind<NinjectExceptionHandler>().ToSelf().InTransientScope()设置绑定,但这似乎并没有停止拦截器的缓存。

  4. 我想有一些我想念的东西。我理解为了缓存IInterceptor对象以提高性能,但我觉得我很难用IOC容器或者注入来获取我的请求所需的对象。

    这是我根据需要进行拦截和运行的最后一个问题,所以非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

根据您的要求,我将详细介绍我们如何实现&#34; 1代理:1拦截器&#34;实例关系船。

我们采取了简单的方式,它没有提供官方ninject拦截扩展所提供的灵活性。我们直接依赖于castle.core动态代理,因此城堡的IInvocation界面。

(请注意,下面的代码不是针对没有目标的代理,但是具有目标的代理非常相似 - 唯一改变的是您需要知道目标类类型并使用{{1实现它)。

基本上我们创建了一个绑定:

IResolutionRoot.Get<TargetClassType>()

现在我们当然需要知道代理人应该使用哪些拦截器。我们再次使用一种简单 - 而不是那么好 - 的设计:

IBindingRoot.Bind<IFoo>()
     .ToProvider<InterfaceProxyWithoutTargetProvider<IFoo>>();

这意味着public interface IInterceptorBindingDefinition<TTarget> { Type InterceptorType { get; } } public class InterceptorBindingDefinition<TTarget, TInterceptor> : IInterceptorBindingDefinition<TTarget> where TInterceptor : IInterceptor { Type InterceptorType { get { return typeof(TInterceptor); } } } IBindingRoot .Bind<IInterceptorBindingDefinition<IFoo>>() .To<InterceptorBindingDefinition<TTarget, LoggingInterceptor>(); IBindingRoot .Bind<IInterceptorBindingDefinition<IFoo>>() .To<InterceptorBindingDefinition<TTarget, SomeOtherInterceptor>(); 会有两个拦截器:IFooLoggingInterceptor

以及提供者的实施:

SomeOtherInterceptor

当然,我们现在对这个问题进行了一些改进,所以我们有一个流畅的语法来配置代理和拦截器的绑定 - 这很容易。

然而,使用public class InterfaceProxyWithoutTargetProvider<TInterface> : IProvider<TInterface> where TInterface : class { private readonly IProxyGenerator proxyGenerator; private readonly IInterceptorFactory interceptorFactory; public InterfaceProxyWithoutTargetProvider(IProxyGenerator proxyGenerator, IInterceptorFactory interceptorFactory) { this.proxyGenerator = proxyGenerator; this.interceptorFactory = interceptorFactory; } public Type Type { get { return typeof(TInterface); } } public object Create(IContext context) { var interceptorTypes = context.Kernel.Get<IEnumerable<IInterceptorBindingDefinition<TInterface>>(); IList<IInterceptor> interceptors = interceptorTypes .Select(x => x.InterceptorType) .Select(x => context.ContextPreservingGet(x)) .ToList(); return this.proxyGenerator.CreateInterfaceProxyWithoutTarget<TInterface>(interceptors); } } IAdviceRegistry的ninject.extensions.interception方法肯定更好(但也需要更深入地了解ninject如何工作)。

答案 1 :(得分:0)

所以看来我无法用Ninject做我优雅的尝试。一旦进入IInterceptor和异步操作的后期部分,HttpContext就会丢失,Ninject无法解决它应该考虑的范围。再加上它重用IInterceptor的方法(就像我说的那样,可以理解,但很烦人),我根本无法让它按照我的意愿运行。

我能够做到的事情是简单的,但有点笨拙(我想)。由于我拦截的所有方法都在我的服务层中,并且我的所有服务都通过IBaseService抽象基类实现了BaseService,而这个基类恰好具有我需要的对象作为属性,我能够在拦截器中执行此操作:

var uow = (invocation.Request.Target as IBaseService).UnitOfWork;

这使我能够访问我的工作单元并使其失败,并访问我正在处理的日志记录实例。

虽然这有效,但我希望看到通过多次调用让拦截器构造函数注入正常工作,或者进一步调用内核来实现它已经解决了仍在范围内的对象(尽管我在猜测因为ASP.Net在等待时放弃了范围,所以它可能认为它超出了范围。

对于任何感兴趣的人,我会尽快在我的博客上发布这个帖子(如果我真的感兴趣,请参阅我的用户页面,而不是自己发送垃圾邮件)。