简体   繁体   English

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

[英]Attempt to resolve item from Ninject in IInterceptor fails

I am attempting to use Ninject on my current project, and up to now, have been loving it. 我正在尝试在当前项目中使用Ninject,到目前为止,我一直都很喜欢它。 I am in the middle of attempting to configure an IInterceptor object to intercept and handle a failed method call to my service layer. 我正在尝试配置IInterceptor对象以拦截和处理对服务层的失败方法调用。 This is hosted in an ASP.NET MVC 5 application. 它托管在ASP.NET MVC 5应用程序中。

In the IInterceptor , I've tried several things, such as: IInterceptor ,我尝试了几种方法,例如:

  1. Setting private variables using constructor injection, but came to discover that it appears Ninject will reuse an IInterceptor instance for a method indefinitely, and I haven't found a way to stop that. 使用构造函数注入设置私有变量,但是发现Ninject似乎会无限期地为方法重用IInterceptor实例,而我还没有找到一种方法来停止它。 Since one of the things I bring into scope is a DbContext which gets disposed elsewhere, it ends up failing on any future requests than the one it was created on. 由于我要处理的问题之一是DbContext ,该DbContext将被放置在其他地方,因此它最终对任何将来的请求都失败,而不是对它创建的请求。

  2. I found that the IInvocation has a Request.Kernel property. 我发现IInvocation具有Request.Kernel属性。 However, when I attempt to resolve my UOW from the container, which is .InRequestScope() , it fails, since it attempts to resolve the IUowService dependencies, (one of the dependencies depends on the HttpContext which is null at this point), but appears to be doing so outside the Request scope. 但是,当我尝试从容器( .InRequestScope()解析我的UOW时,它失败了,因为它尝试解析IUowService依赖项,(其中一个依赖项依赖于HttpContext,此时,该依赖项为null),但是似乎是在Request范围之外执行的。 It is ignoring the fact that the dependencies it needs have already been created within the ASP.NET request, and is attempting to create new ones. 它忽略了这样一个事实,即它所需要的依赖项已在ASP.NET请求中创建,并试图创建新的依赖项。

  3. Setting a binding for the interceptor this.Bind<NinjectExceptionHandler>().ToSelf().InTransientScope() , yet this didn't seem to stop the caching of the interceptor. 设置拦截器的绑定this.Bind<NinjectExceptionHandler>().ToSelf().InTransientScope() ,但这似乎并未停止拦截器的缓存。

I imagine there is something I am missing. 我想象有一些我想念的东西。 I understand wanting to cache IInterceptor objects for performance, but I find it irksome that I can't easily use the IOC container or Injection to get the objects I need for my request. 我知道要缓存IInterceptor对象以提高性能,但是我感到IInterceptor是,我无法轻松地使用IOC容器或Injection来获取我的请求所需的对象。

This is the last issue I am having with getting interception up and running as I need, so any help is greatly appreciated! 这是我需要截取并运行拦截程序时遇到的最后一个问题,因此非常感谢您的帮助!

Per your request i'm going into more detail on how we've achieved "1 proxy : 1 interceptor" instance relation ship. 根据您的请求,我将详细介绍如何实现“ 1代理:1拦截器”实例关系。

We've taken the easy way which does not offer as much flexibility as what the official ninject interception extensions offers. 我们采用了一种简单的方法,该方法没有提供官方ninject拦截扩展所提供的灵活性那样大的灵活性。 We are relying directly on castle.core dynamic proxy and thus castle's IInvocation interface. 我们直接依赖Castle.core动态代理,因此也依赖Castle的IInvocation接口。

(Please not the code below is for a proxy without target, but a proxy with target is quite similar -- the only thing which changes is that you'll need to know the target class type and use IResolutionRoot.Get<TargetClassType>() to instanciate it). (请注意,下面的代码不是针对没有目标的代理的,但是具有目标的代理却非常相似-唯一改变的是您需要知道目标类的类型并使用IResolutionRoot.Get<TargetClassType>()实例化)。

Basically we created a binding like: 基本上,我们创建了如下绑定:

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

Now of course we need to know which interceptors the proxy shall use. 现在,我们当然需要知道代理将使用哪个拦截器。 Again we are using an easy - and not so nice - design: 再次,我们使用的是简单的-不太好-设计:

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>();      

This means IFoo shall get two interceptors: LoggingInterceptor and SomeOtherInterceptor . 这意味着IFoo将获得两个拦截器: LoggingInterceptorSomeOtherInterceptor

and the implementation of the provider: 以及提供者的实现:

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);
    }
}

Now of course we polished the thing a little bit so we have a fluent syntax configuring the binding of the proxy and the interceptor - which is easy enough. 现在,我们当然可以对它进行一些改进,因此我们可以使用流利的语法来配置代理和拦截器的绑定-这很容易。

However ninject.extensions.interception's approach with its IAdviceRegistry and IAdvice is certainly better (but also requires more insight into how ninject works). 但是,ninject.extensions.interception的IAdviceRegistryIAdvice方法确实更好(但还需要对ninject的工作方式有更多的了解)。

So it appears that there is no way to do what I was trying gracefully with Ninject. 因此,似乎无法用Ninject优雅地完成我尝试的操作。 Once in the IInterceptor and in the later parts of async operations, the HttpContext was lost and Ninject couldn't resolve things that really it should have thought were in scope. 一旦进入IInterceptor和异步操作的后续部分,HttpContext就会丢失,Ninject无法解决它本应认为在范围内的事情。 Coupled with the fact that it reused IInterceptor 's for a method (like I said, understandable, but irritating), I just couldn't get it to work right as I wanted to. 再加上它重用了IInterceptor的方法(就像我说的那样,可以理解,但很IInterceptor ),我只是无法使它正常工作。

What I was able to do to get around the fact was something simple, yet a little kludgy (I think). 我能够解决这个问题的方法很简单,但是有点混乱(我认为)。 Since all the methods that I was intercepting were in my service layer, and all my services implemented a IBaseService through a BaseService abstract base class, which happened to have the objects I needed as properties, I was able to do this in the interceptor: 因为我要拦截的所有方法都在我的服务层中,并且我所有的服务IBaseService通过BaseService抽象基类实现了IBaseService ,而该基类恰好具有我需要的对象作为属性,所以我可以在拦截器中执行此操作:

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

This allowed me to access my unit of work and Fail it, as well as access the logging instance I was working on. 这使我可以访问我的工作单元并使其失败,以及访问我正在处理的日志记录实例。

While this works, I would like to see someway to get interceptor constructor injection working correctly through multiple calls, or calls to the Kernel further down the line to realize that it has already resolved an object still in scope (although I am guessing that it may think its out of scope since ASP.Net abandoned the scope upon await). 在此过程中,我希望通过某种方式使拦截器构造函数注入正常工作,或者通过进一步调用内核来认识到它已经解析了仍在作用域中的对象(尽管我猜测可能认为它超出范围,因为ASP.Net在等待时放弃了范围)。

For any interested, I am going to try and post about this on my blog soon (see my user page if actually interested, not spamming SO myself). 对于任何有兴趣的人,我将尽快尝试在我的博客上发布有关此内容的信息(如果真的有兴趣,请参阅我的用户页面,而不是自己发垃圾邮件)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM