.NET Core 2 中使用 Castle DynamicProxy 的 Autofac 方法级拦截
Autofac method level interception with Castle DynamicProxy in .NET Core 2
我目前写了一个拦截器,代码如下
public class TransactionalInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
}
但是当注册这个拦截器时,它将应用于所有方法。我有一个服务 class,其中的存储库注入了 CRUD 方法。
我不希望为查询方法打开事务。
我读了这个 link 但我不知道如何将它应用到我的代码中
http://docs.autofac.org/en/latest/advanced/adapters-decorators.html#decorators
我不知道谁来重构我的 TransactionalInterceptor(并注册它)以在 class 中使用它,就像这段代码
[Intercept(typeof(LoggerInterceptor))] //logger
public class SomeService : ISomeService
{
private readonly ISomeRepository someRepository;
public SomeService(SomeRepository someRepository)
{
this.someRepository = someRepository;
}
public IEnumerable<SomeDto> GetAll()
{
// code
}
public SomeDto GetById()
{
// code
}
[Transactional]
public int Create(SomeDto someDto)
{
// code to insert
}
}
Intercept
方法的invocation
参数中包含一个Method
属性是当前拦截方法的一个MethodInfo
。
您可以使用此 属性 来做您想做的事。
例如使用方法名:
public void Intercept(IInvocation invocation)
{
if (invocation.MethodInvocationTarget.Name != nameof(ISomeService.Create))
{
invocation.Proceed();
return;
}
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
或基于目标方法的属性:
if (!invocation.MethodInvocationTarget
.CustomAttributes
.Any(a => a.AttributeType == typeof(TransactionalAttribute)))
您也可以使用 IInterceptorSelector
类型,但需要更多工作才能将其注册到 Autofac
我用 ProxyGenerationHook
解决了这个问题。请参阅
- 创建您的自定义属性以选择要拦截的方法。该属性的目标应该是 Method.
[System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
sealed class UseInterceptorAttribute : Attribute
{
public UseInterceptorAttribute()
{
}
}
- 创建您的服务接口和服务class:
public interface ISomeService
{
void GetWithoutInterceptor();
[UseInterceptor]
void GetWithInterceptor();
}
public class SomeService
{
void GetWithoutInterceptor()
{
//This method will not be intercepted...
}
[UseInterceptor]
void GetWithInterceptor()
{
//This method will be intercepted...
}
}
- 创建您的
ProxyGenerationHook
public class SomeServiceProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected()
{
}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
return methodInfo
.CustomAttributes
.Any(a => a.AttributeType == typeof(UseInterceptorAttribute));
}
}
- 不要使用属性来启用拦截器。启用它时
像这样注册您的服务:
public class AutofacDependencyResolver
{
private readonly IContainer _container;
public AutofacDependencyResolver()
{
_container = BuildContainer();
}
private IContainer BuildContainer()
{
var proxyGenerationOptions = new ProxyGenerationOptions(new ProductServiceProxyGenerationHook());
builder.RegisterType<SomeService>()
.As<ISomeService>()
.EnableInterfaceInterceptors(proxyGenerationOptions)
.InterceptedBy(typeof(TransactionalInterceptor))
builder.Register(c => new TransactionalInterceptor());
return builder.Build();
}
public T GetService<T>()
where T:class
{
var result = _container.TryResolve(out T serviceInstance);
return serviceInstance ?? throw new Exception($"The service could not found: {nameof(T)}");
}
}
此解决方案遵循此 article
我还上传了关于此解决方案的最小 example。
也可以试试,很简单https://fs7744.github.io/Norns.Urd/index.html
public class AddTenInterceptorAttribute : AbstractInterceptorAttribute
{
public override void Invoke(AspectContext context, AspectDelegate next)
{
next(context);
AddTen(context);
}
private static void AddTen(AspectContext context)
{
if (context.ReturnValue is int i)
{
context.ReturnValue = i + 10;
}
else if(context.ReturnValue is double d)
{
context.ReturnValue = d + 10.0;
}
}
public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next)
{
await next(context);
AddTen(context);
}
}
[AddTenInterceptor]
public interface IGenericTest<T, R> : IDisposable
{
// or
//[AddTenInterceptor]
T GetT();
}
我目前写了一个拦截器,代码如下
public class TransactionalInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
}
但是当注册这个拦截器时,它将应用于所有方法。我有一个服务 class,其中的存储库注入了 CRUD 方法。 我不希望为查询方法打开事务。
我读了这个 link 但我不知道如何将它应用到我的代码中 http://docs.autofac.org/en/latest/advanced/adapters-decorators.html#decorators
我不知道谁来重构我的 TransactionalInterceptor(并注册它)以在 class 中使用它,就像这段代码
[Intercept(typeof(LoggerInterceptor))] //logger
public class SomeService : ISomeService
{
private readonly ISomeRepository someRepository;
public SomeService(SomeRepository someRepository)
{
this.someRepository = someRepository;
}
public IEnumerable<SomeDto> GetAll()
{
// code
}
public SomeDto GetById()
{
// code
}
[Transactional]
public int Create(SomeDto someDto)
{
// code to insert
}
}
Intercept
方法的invocation
参数中包含一个Method
属性是当前拦截方法的一个MethodInfo
。
您可以使用此 属性 来做您想做的事。
例如使用方法名:
public void Intercept(IInvocation invocation)
{
if (invocation.MethodInvocationTarget.Name != nameof(ISomeService.Create))
{
invocation.Proceed();
return;
}
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
或基于目标方法的属性:
if (!invocation.MethodInvocationTarget
.CustomAttributes
.Any(a => a.AttributeType == typeof(TransactionalAttribute)))
您也可以使用 IInterceptorSelector
类型,但需要更多工作才能将其注册到 Autofac
我用 ProxyGenerationHook
解决了这个问题。请参阅
- 创建您的自定义属性以选择要拦截的方法。该属性的目标应该是 Method.
[System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
sealed class UseInterceptorAttribute : Attribute
{
public UseInterceptorAttribute()
{
}
}
- 创建您的服务接口和服务class:
public interface ISomeService
{
void GetWithoutInterceptor();
[UseInterceptor]
void GetWithInterceptor();
}
public class SomeService
{
void GetWithoutInterceptor()
{
//This method will not be intercepted...
}
[UseInterceptor]
void GetWithInterceptor()
{
//This method will be intercepted...
}
}
- 创建您的
ProxyGenerationHook
public class SomeServiceProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected()
{
}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
return methodInfo
.CustomAttributes
.Any(a => a.AttributeType == typeof(UseInterceptorAttribute));
}
}
- 不要使用属性来启用拦截器。启用它时 像这样注册您的服务:
public class AutofacDependencyResolver
{
private readonly IContainer _container;
public AutofacDependencyResolver()
{
_container = BuildContainer();
}
private IContainer BuildContainer()
{
var proxyGenerationOptions = new ProxyGenerationOptions(new ProductServiceProxyGenerationHook());
builder.RegisterType<SomeService>()
.As<ISomeService>()
.EnableInterfaceInterceptors(proxyGenerationOptions)
.InterceptedBy(typeof(TransactionalInterceptor))
builder.Register(c => new TransactionalInterceptor());
return builder.Build();
}
public T GetService<T>()
where T:class
{
var result = _container.TryResolve(out T serviceInstance);
return serviceInstance ?? throw new Exception($"The service could not found: {nameof(T)}");
}
}
此解决方案遵循此 article
我还上传了关于此解决方案的最小 example。
也可以试试,很简单https://fs7744.github.io/Norns.Urd/index.html
public class AddTenInterceptorAttribute : AbstractInterceptorAttribute
{
public override void Invoke(AspectContext context, AspectDelegate next)
{
next(context);
AddTen(context);
}
private static void AddTen(AspectContext context)
{
if (context.ReturnValue is int i)
{
context.ReturnValue = i + 10;
}
else if(context.ReturnValue is double d)
{
context.ReturnValue = d + 10.0;
}
}
public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next)
{
await next(context);
AddTen(context);
}
}
[AddTenInterceptor]
public interface IGenericTest<T, R> : IDisposable
{
// or
//[AddTenInterceptor]
T GetT();
}