我正在尝试在我当前的项目中使用Ninject,到目前为止,一直都喜欢它。我正在尝试配置一个IInterceptor对象来拦截和处理对我的服务层的失败方法调用。它托管在ASP.NET MVC 5应用程序中。
在IInterceptor
中,我尝试了几件事,例如:
使用构造函数注入设置私有变量,但后来发现看起来Ninject将无限期地重用IInterceptor
实例,并且我还没有找到办法阻止它。由于我带入范围的其中一件事是DbContext
,它被置于其他地方,因此最终未能在未来的任何请求上失败。
我发现IInvocation
有Request.Kernel
属性。但是,当我尝试从容器.InRequestScope()
解析我的UOW时,它失败了,因为它试图解析IUowService
依赖项,(其中一个依赖项依赖于HttpContext,它是null这一点),但似乎在请求范围之外这样做。它忽略了这样一个事实,即它需要的依赖项已经在ASP.NET请求中创建,并且正在尝试创建新的依赖项。
为拦截器this.Bind<NinjectExceptionHandler>().ToSelf().InTransientScope()
设置绑定,但这似乎并没有停止拦截器的缓存。
我想有一些我想念的东西。我理解为了缓存IInterceptor
对象以提高性能,但我觉得我很难用IOC容器或者注入来获取我的请求所需的对象。
这是我根据需要进行拦截和运行的最后一个问题,所以非常感谢任何帮助!
答案 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>();
会有两个拦截器:IFoo
和LoggingInterceptor
。
以及提供者的实施:
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在等待时放弃了范围,所以它可能认为它超出了范围。
对于任何感兴趣的人,我会尽快在我的博客上发布这个帖子(如果我真的感兴趣,请参阅我的用户页面,而不是自己发送垃圾邮件)。