简体   繁体   English

通过 IAsyncInterceptor 使用 Autofac 接口拦截

[英]Using Autofac Interface Interception with IAsyncInterceptor

I did use this documentation: https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html我确实使用了这个文档: https ://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html

to implement Interface Interceptors.实现接口拦截器。 To handle my async calls I used the IAsyncInterceptor interface described here:为了处理我的异步调用,我使用了此处描述的 IAsyncInterceptor 接口:

https://github.com/JSkimming/Castle.Core.AsyncInterceptor https://github.com/JSkimming/Castle.Core.AsyncInterceptor

The registration code I came up with does look like this:我想出的注册码确实是这样的:

 builder.Register(c => new CallResultLoggerInterceptor())
    .Named<IAsyncInterceptor>("log-calls");

  builder.RegisterType<AppointmentService>()
    .As<IAppointmentService>()
    .EnableInterfaceInterceptors()
    .InstancePerDependency();

where the AppointmentService has an InterceptAttribute.其中 AppointmentService 有一个 InterceptAttribute。

 [Intercept("log-calls")]
 public class AppointmentService : IAppointmentService
 ...

When i call the containers Build() method, it throws an ComponentNotRegisteredException with the message:当我调用容器 Build() 方法时,它会抛出一个 ComponentNotRegisteredException 消息:

The requested service 'log-calls (Castle.DynamicProxy.IInterceptor)' has not been registered.请求的服务“日志调用(Castle.DynamicProxy.IInterceptor)”尚未注册。 To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.要避免此异常,请注册组件以提供服务,使用 IsRegistered() 检查服务注册,或使用 ResolveOptional() 方法解析可选依赖项。

which is correct because I do not implement IInterceptor but IAsyncInterceptor.这是正确的,因为我没有实现 IInterceptor,而是实现了 IAsyncInterceptor。 I guess the problem is the concrete implementation of EnableInterfaceInterceptors in autofac using the "wrong" extension method of the ProxyGenerator - but how can I solve this?我想问题是使用 ProxyGenerator 的“错误”扩展方法在 autofac 中 EnableInterfaceInterceptors 的具体实现 - 但我该如何解决这个问题?

Cheers, Manuel干杯,曼努埃尔

You need to register a named IInterceptor for Autofac interceptors to work.您需要为 Autofac 拦截器注册一个命名的IInterceptor才能工作。 You're registering an IAsyncInterceptor .您正在注册IAsyncInterceptor That won't work.那行不通的。

Note Autofac has no support for this extended async interceptor extension you're using.注意 Autofac 不支持您正在使用的这个扩展的异步拦截器扩展。 If you want to get that to work, it'll require writing a custom adapter of some nature to get it to respond to IInterceptor .如果你想让它工作,它需要编写某种性质的自定义适配器来让它响应IInterceptor

You can see my answer in the issue of Castle.Core.AsyncInterceptor: https://github.com/JSkimming/Castle.Core.AsyncInterceptor/issues/42#issuecomment-592074447你可以在Castle.Core.AsyncInterceptor的issue中看到我的回答: https ://github.com/JSkimming/Castle.Core.AsyncInterceptor/issues/42#issuecomment-592074447

  1. create an adapter创建适配器
public class AsyncInterceptorAdaper<TAsyncInterceptor> : AsyncDeterminationInterceptor
  where TAsyncInterceptor : IAsyncInterceptor
{
    public AsyncInterceptorAdaper(TAsyncInterceptor asyncInterceptor)
        : base(asyncInterceptor)
    { }
}
  1. create your async interceptor创建你的异步拦截器
public class CallLoggerAsyncInterceptor : AsyncInterceptorBase  
{
  ....
}
  1. relate the interceptor to interface将拦截器与接口相关联
[Intercept(typeof(AsyncInterceptorAdaper<CallLoggerAsyncInterceptor>))]
public interface ISomeType
  1. register to IoC container注册到 IoC 容器
//register adapter
builder.RegisterGeneric(typeof(AsyncInterceptorAdaper<>));
//register async interceptor
builder.Register(c => new CallLoggerAsyncInterceptor(Console.Out));   

I've made a code sample in https://github.com/wswind/aop-learn/blob/master/AutofacAsyncInterceptor我在https://github.com/wswind/aop-learn/blob/master/AutofacAsyncInterceptor做了一个代码示例

I've created my own extension method for registering application services.我已经创建了自己的扩展方法来注册应用程序服务。 This extension method simply prepares input parameter for castle core ProxyGenerator .此扩展方法只是为 castle core ProxyGenerator准备输入参数。

using System;
using System.Collections.Generic;
using System.Linq;
using Castle.DynamicProxy;
using Autofac;

namespace pixi.Extensions
{
    public static class AutofacExtensions
    {
        private static readonly ProxyGenerator _proxyGenerator = new ProxyGenerator();

        /// <summary>
        /// Use this extension method to register default interceptors <code>UnitOfWorkInterceptor</code>
        /// and <code>LoggingInterceptor</code> on your application service implementations. If you need custom
        /// interceptors that are not part of infrastructure but are part of specific business module then pass
        /// in those interceptors in params explicitly.
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="interceptors"></param>
        /// <typeparam name="TImplementation"></typeparam>
        /// <typeparam name="TService"></typeparam>
        /// <exception cref="ArgumentException"></exception>
        public static void RegisterApplicationService<TImplementation, TService>(this ContainerBuilder builder, params Type[] interceptors)
            where TImplementation : class
        {
            ValidateInput<TService>(interceptors);

            builder.RegisterType<TImplementation>().AsSelf();

            builder.Register(c =>
            {
                var service = c.Resolve<TImplementation>();
                var resolvedInterceptors = ResolveInterceptors<TImplementation, TService>(interceptors, c);

                return (TService) _proxyGenerator.CreateInterfaceProxyWithTarget(
                        typeof(TService),
                        service,
                        ProxyGenerationOptions.Default,
                        resolvedInterceptors
                    );
            }).As<TService>();
        }

        private static void ValidateInput<TService>(Type[] interceptors)
        {
            if (!typeof(TService).IsInterface)
                throw new ArgumentException("Type must be interface");
            if (interceptors.Any(i => i != typeof(IAsyncInterceptor)))
                throw new ArgumentException("Only IAsyncInterceptor types are expected");
        }

        private static IAsyncInterceptor[] ResolveInterceptors<TImplementation, TService>(Type[] interceptors,
            IComponentContext c) where TImplementation : class
        {
            var resolvedInterceptors = new List<IAsyncInterceptor>
            {
                c.Resolve<LoggingInterceptor>(),
                c.Resolve<UnitOfWorkInterceptor>()
            }.Concat(interceptors
                .Where(i => i != typeof(UnitOfWorkInterceptor)
                            && i != typeof(LoggingInterceptor))
                .Select(i => (IAsyncInterceptor) c.Resolve(i))).ToArray();
            return resolvedInterceptors;
        }
    }
}

I am using castle core for unit of work and logging hence the name UnitOfWorkInterceptor and LogginInterceptor .我将城堡核心用于工作单元和日志记录,因此名称为UnitOfWorkInterceptorLogginInterceptor Change these two to your desired defaults.将这两个更改为您想要的默认值。 Default interceptors must be registered in this way:默认拦截器必须以这种方式注册:

public class SomeModule: Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<UnitOfWorkInterceptor>().AsSelf();
            builder.RegisterType<LoggingInterceptor>().AsSelf();
            builder.RegisterApplicationService<SampleService, ISampleService>();
            builder.RegisterType<SampleRepository>().As<ISampleRepository>();
        }
    }

In the above code snippet I've also demonstrated the usage provided extension method.在上面的代码片段中,我还演示了使用提供的扩展方法。 Doing it this way I get red of tag interfaces and placing extra attributes on interfaces.这样做我得到标签接口的红色并在接口上放置额外的属性。 That way I can keep my ApplicationService interfaces free of framework/3rd party library dependencies.这样我就可以让我的 ApplicationService 接口不受框架/第三方库的依赖。

I hope this helps.我希望这有帮助。

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

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