首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于城堡DynamicProxy的.NET核2自寻址方法级拦截

基于城堡DynamicProxy的.NET核2自寻址方法级拦截
EN

Stack Overflow用户
提问于 2018-01-14 23:24:00
回答 3查看 2.5K关注 0票数 2

我目前编写了一个代码如下的拦截器

代码语言:javascript
复制
public class TransactionalInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        using (var transaction = ...)
        {
            try
            {
                invocation.Proceed();
                transaction.Commit();

            }
            catch
            {
                transaction.Rollback();
            }
            finally
            {
                transaction.Dispose();
            }
        }

    }
}

但是,当注册此拦截器时,它将应用于所有方法。我有一个服务类,其中注入了一个存储库,其中包含CRUD方法。我不希望为查询方法打开事务。

我读过这个链接,但是我想不出如何将它应用到我的代码http://docs.autofac.org/en/latest/advanced/adapters-decorators.html#decorators中。

我不知道该由谁重构我的TransactionalInterceptor (并注册它),以便在这样的类中使用它

代码语言:javascript
复制
[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
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-01-15 15:45:15

invocation方法的Intercept参数包含一个Method属性,该属性是当前截获的方法的MethodInfo

你可以使用这个属性来做你想做的事。

例如,通过使用方法名:

代码语言:javascript
复制
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();
        }
    }
}

或基于来自目标方法的属性:

代码语言:javascript
复制
if (!invocation.MethodInvocationTarget
               .CustomAttributes
               .Any(a => a.AttributeType == typeof(TransactionalAttribute)))

您也可以使用IInterceptorSelector类型,但它需要更多的工作才能将其注册到Autofac。

票数 1
EN

Stack Overflow用户

发布于 2020-12-02 20:45:27

我用ProxyGenerationHook解决了问题。见回答

  1. 创建自定义属性,以选择要拦截的方法。该属性的目标应该是方法
代码语言:javascript
复制
    [System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    sealed class UseInterceptorAttribute : Attribute
    {
        public UseInterceptorAttribute()
        {
        }
    }
  1. 创建服务接口和服务类:
代码语言:javascript
复制
    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. 创建您的ProxyGenerationHook
代码语言:javascript
复制
    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. 不要使用属性来启用拦截器。在像这样注册您的服务时启用它:
代码语言:javascript
复制
    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)}");
        }
    }

此解决方案遵循此文章

此外,我还上传了关于该解决方案的最小示例

票数 0
EN

Stack Overflow用户

发布于 2020-12-12 07:52:39

也可以尝试,它是简单的https://fs7744.github.io/Norns.Urd/index.html

代码语言:javascript
复制
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();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48255182

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档