问题
I currently wrote an Interceptor which code is below
public class TransactionalInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
}
but when register this interceptor it will apply to all methods. I have a service class with a repository injected having CRUD methods. I don't want a transaction to be opened for query methods.
I read this link but I cannot figure out how to apply it to my code http://docs.autofac.org/en/latest/advanced/adapters-decorators.html#decorators
I don't know who to refactor my TransactionalInterceptor (and register it) to use it in a class like this code
[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
}
}
回答1:
The invocation
parameter of the Intercept
method contains a Method
property which is a MethodInfo
of the method currently intercepted.
You can use this property to do what you want.
For example by using the method name :
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();
}
}
}
or based on an attribute from the target method :
if (!invocation.MethodInvocationTarget
.CustomAttributes
.Any(a => a.AttributeType == typeof(TransactionalAttribute)))
You can also use the IInterceptorSelector
type but it requires more work to register it with Autofac
回答2:
I solved the problem with ProxyGenerationHook
. See the answer
- Create your custom attribute for selecting which method to intercept. This attribute's target should be Method.
[System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
sealed class UseInterceptorAttribute : Attribute
{
public UseInterceptorAttribute()
{
}
}
- Create your service interface and service 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...
}
}
- Create your
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));
}
}
- Don't use attributes for enabling interceptors. Enable it when registering your service like this:
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)}");
}
}
This solution is following this article
Also I uploaded the minimal example about this solution.
来源:https://stackoverflow.com/questions/48255182/autofac-method-level-interception-with-castle-dynamicproxy-in-net-core-2