我确实使用过这个文档: https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html
实现接口拦截器。为了处理我的异步调用,我使用了这里描述的IAsyncInterceptor接口:
https://github.com/JSkimming/Castle.Core.AsyncInterceptor
我提出的注册码看起来像这样:
builder.Register(c => new CallResultLoggerInterceptor())
.Named<IAsyncInterceptor>("log-calls");
builder.RegisterType<AppointmentService>()
.As<IAppointmentService>()
.EnableInterfaceInterceptors()
.InstancePerDependency();
其中AppointmentService有一个InterceptAttribute。
[Intercept("log-calls")]
public class AppointmentService : IAppointmentService
...
当我调用容器Build()方法时,它会抛出一个ComponentNotRegisteredException并显示消息:
请求的服务'log-calls(Castle.DynamicProxy.IInterceptor)'尚未注册。要避免此异常,请注册组件以提供服务,使用IsRegistered()检查服务注册,或使用ResolveOptional()方法解析可选依赖项。
这是正确的,因为我没有实现IInterceptor而是IAsyncInterceptor。我想问题是使用ProxyGenerator的“错误”扩展方法在autofac中具体实现EnableInterfaceInterceptors - 但我该如何解决这个问题?
干杯, 曼努埃尔
答案 0 :(得分:1)
您需要为Autofac拦截器注册一个名为IInterceptor
的工作。您正在注册IAsyncInterceptor
。那不会起作用。
注意Autofac不支持您正在使用的此扩展异步拦截器扩展。如果您希望将其付诸实践,则需要编写某种性质的自定义适配器,以使其响应IInterceptor
。
答案 1 :(得分:1)
您可以在Castle.Core.AsyncInterceptor问题中看到我的答案: 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));
我已经在https://github.com/wswind/aop-learn/blob/master/AutofacAsyncInterceptor中制作了代码示例
答案 2 :(得分:0)
我已经创建了自己的扩展方法来注册应用程序服务。
这种扩展方法只是为城堡核心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;
}
}
}
我将城堡核心用于工作单元并记录日志,因此命名为UnitOfWorkInterceptor
和LogginInterceptor
。将这两个更改为所需的默认值。默认拦截器必须以这种方式注册:
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>();
}
}
在上面的代码片段中,我还演示了用法提供的扩展方法。通过这种方式,我获得了标记接口的红色,并在接口上放置了额外的属性。这样,我可以使ApplicationService接口不受框架/第三方库依赖项的影响。
我希望这会有所帮助。