[英]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
public class AsyncInterceptorAdaper<TAsyncInterceptor> : AsyncDeterminationInterceptor
where TAsyncInterceptor : IAsyncInterceptor
{
public AsyncInterceptorAdaper(TAsyncInterceptor asyncInterceptor)
: base(asyncInterceptor)
{ }
}
public class CallLoggerAsyncInterceptor : AsyncInterceptorBase
{
....
}
[Intercept(typeof(AsyncInterceptorAdaper<CallLoggerAsyncInterceptor>))]
public interface ISomeType
//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
.我将城堡核心用于工作单元和日志记录,因此名称为
UnitOfWorkInterceptor
和LogginInterceptor
。 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.