简体   繁体   中英

Registering/Using Castle.Core.AsyncInterceptor Interceptors

I'm trying to use the Castle.Core.AsyncInterceptor package to handle exceptions thrown from async methods but I'm struggling to understand how to link it all together.

My previous ExceptionInterceptor implemented the standard IInterceptor interface, so I could apply the interceptor to all the relevant classes using something like

  _container.Register(Classes.FromAssemblyContaining(typeof(BaseDao))
                            .BasedOn<BaseDao>()
                            .Configure(c => c.Interceptors<ExceptionInterceptor>()));

The docs suggest implementing IAsyncInterceptor instead, which I have done, but the last line in the code above now understandably gives me a compile error (no implicit reference conversion from ExceptionInterceptor to IInterceptor) because it's not an IInterceptor any more.

Instead the docs suggest doing it this way

var myClass = new ClasThatImplementsIMyInterface(); var generator = new ProxyGenerator(); var interceptor = new ClasThatImplementsIAsyncInterceptor(); IMyInterface proxy = generator.CreateInterfaceProxyWithTargetInterface<IMyInterface>(myClass,interceptor)

But I'm not sure what to do after that. Do I have to generate a proxy for each of my DAOs and then register them individually with the container before I can use them?

I've been going through the accompanying unit tests to try and figure it out but I'm struggling to understand how it would work.

Thanks

I'll add what I have so far an an answer since it does answer my question to some extent, although needs some work to make it more generic. I've no idea how to apply this pattern to every DAO in an assembly but at least it works for one class. I'd just have to repeat this for each class I want to add the interceptor to.

_container.Register(
          Component.For<IGroceryDao>()
              .UsingFactoryMethod(() => ServiceFactory.BuildGroceryDao(_container.Resolve<IDbTransaction>()))
              .LifestyleScoped());

It uses a factory method in ServiceFactory (just a class I created that contains the below method) to create the proxied DAO that has had the interceptor applied:

public static IGroceryDao BuildGroceryDao(IDbTransaction transaction)
    {
      return (IGroceryDao) new ProxyGenerator()
                                .CreateInterfaceProxyWithTargetInterface<IGroceryDao>(new Neo4jGroceryDao(transaction), new ExceptionInterceptor());
    }

The transaction object is something that is already registered with the container that the DAO needs so I just resolve it and then pass it to the factory method.

Seems to work anyway. If anyone can advise how to make this more generic that would be awesome but at least I think this answers the question as I asked it.

The Castle.Core.AsyncInterceptor nuget contains an extension method

Castle.DynamicProxy.ProxyGeneratorExtensions.ToInterceptor(this IAsyncInterceptor interceptor)

that can convert async interceptor to sync interceptor. It seems that it's not possible to use an instance for registration, you need to do it some other way. It might be possible

  • to register interceptor as a named component and use InterceptorReferences
  • just to create an adapter that converts async interceptor to sync interceptor

I have gone with adapter and it seems to work fine.

internal class MyInterceptorAdapter : IInterceptor {
  private readonly IInterceptor inner;

  public MyInterceptorAdapter(SomeDependency dep) {
    inner = new MyAsyncInterceptor(dep).ToInterceptor()
  }

  public void Intercept(IInvocation invocation) 
       => inner.Intercept(invocation);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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