简体   繁体   English

.NET Core 2 中使用 Castle DynamicProxy 的 Autofac 方法级拦截

[英]Autofac method level interception with Castle DynamicProxy in .NET Core 2

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.我有一个服务类,其中注入了 CRUD 方法的存储库。 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我读了这个链接,但我不知道如何将它应用到我的代码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我不知道谁来重构我的 TransactionalInterceptor(并注册它)以在这样的代码类中使用它

[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
    }
}

The invocation parameter of the Intercept method contains a Method property which is a MethodInfo of the method currently intercepted. Intercept方法的invocation参数包含一个Method属性,它是当前拦截的方法的MethodInfo

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您也可以使用IInterceptorSelector类型,但需要更多的工作才能将其注册到Autofac

I solved the problem with ProxyGenerationHook .我用ProxyGenerationHook解决了这个问题。 See the answer查看答案

  1. Create your custom attribute for selecting which method to intercept.创建您的自定义属性以选择要拦截的方法。 This attribute's target should be Method .该属性的目标应该是Method
    [System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    sealed class UseInterceptorAttribute : Attribute
    {
        public UseInterceptorAttribute()
        {
        }
    }
  1. 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...
        }
    }
  1. Create your ProxyGenerationHook创建您的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));
        }
    }
  1. 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.我还上传了有关此解决方案的最小示例

also can try, it is simple https://fs7744.github.io/Norns.Urd/index.html也可以试试,简单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();
}

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

相关问题 使用Castle.DynamicProxy和Simple Injector进行基于属性的拦截 - Attribute based interception with Castle.DynamicProxy and Simple Injector 使用Autofac在.NET Core 2.0 Web API控制器上进行拦截 - Interception on .NET Core 2.0 Web API Controller By Using Autofac 带有Ninject拦截的AOP,Castle DynamicProxy和WPF窗口:在窗口的DynamicProxy中找不到XAML资源 - AOP with Ninject Interception, Castle DynamicProxy and WPF window: Can't find XAML resource in DynamicProxy of window 使用ASP.NET Core 2和Castle.Core的手动拦截无法解析一般服务 - Can not resolve a generic service using manual interception with ASP.NET Core 2 and Castle.Core DryIoc 用城堡核心开启通用拦截 - DryIoc open generic interception with castle core 如何从 Castle.DynamicProxy 中的 ProxyGenerationHook 访问自定义方法属性 - How to access custom method attributes from ProxyGenerationHook in Castle.DynamicProxy 如何从Castle.Core而不是Moq引用Castle.DynamicProxy.IProxyTargetAccessor? - How to reference Castle.DynamicProxy.IProxyTargetAccessor from Castle.Core rather than Moq? 具有类型参数的Autofac DynamicProxy - Autofac DynamicProxy with type parameters 程序集“Ninject.Extensions.Interception.DynamicProxy”中的方法没有实现 - Method from assembly 'Ninject.Extensions.Interception.DynamicProxy' does not have an implementation 带有Autofac DI的.NET Core - .NET Core with Autofac DI
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM