ABP框架使用拦截器动态配置租户过滤器

文章目录

前言

最近项目要求在ABP框架中根据TenantId是否为空来配置是否禁用租户过滤器。ABP自身给我我们禁用租户过滤器的两种方法官方文档

  • 方法一:使用工作单元
using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
{
    var people2 = _personRepository.GetAllList();                
}
  • 方法二:全局禁用过滤器
Configuration.UnitOfWork.OverrideFilter(AbpDataFilters.MayHaveTenant, false);

但是方法一要修改的地方很多,嫌麻烦;方法二只能全局在Configuration中配置,不能动态改变,也不合适。于是我查阅了APB AOP和拦截技术,另外查阅了ABP自身注册了拦截器——UnitOfWorkRegistrar,会默认为继承自IRepository或者是IApplicationService的两种类型添加UnitOfWork特性,于是便可以通过拦截方法去实现动态禁用过滤器。

具体实现

首先在Application 层新建一个TenantInterceptor 继承IInterceptor接口

public class TenantInterceptor : IInterceptor
{
    public ILogger Logger { get; set; }

    public TenantInterceptor()
    {
        Logger = NullLogger.Instance;
    }

    public void Intercept(IInvocation invocation)
    {
        // 从invocation中拿到当前注册进来的工作单元,主要用于获取TenantId
        Type t = invocation.InvocationTarget.GetType();
        var unitOfWorkManager = (t.GetProperty("UnitOfWorkManager").GetValue(invocation.InvocationTarget)) as IUnitOfWorkManager;
        //根据TenantId是否禁用租户过滤器
        if (unitOfWorkManager.Current.GetTenantId().HasValue)
        {
            invocation.Proceed(); // 执行方法体
        }
        else {
        	// 禁用租户
        	// PS:这里不可以使用 using      	
            unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant, AbpDataFilters.MustHaveTenant);
            invocation.Proceed(); // 执行方法体
        }
    }
}

拦截器里的内容很简单,主要就是根据工作单元获取TenantId来动态禁用过滤器。因为这里没有需要返回的东西,也就不用分同步异步去拦截。
接下来就是为所需要禁用租户过滤器的类注册拦截器

public static class TenantInterceptorRegistrar
{
    public static void Initialize(IKernel kernel)
    {

        kernel.ComponentRegistered += Kernel_ComponentRegistered;
    }

    private static void Kernel_ComponentRegistered(string key, IHandler handler)
    {
        var implementationType = handler.ComponentModel.Implementation.GetTypeInfo();
        // 为实现了接口IRepository接口的所有类注册拦截器
        //if (typeof(IRepository).IsAssignableFrom(implementationType))
        //{
        //    handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(TenantInterceptor)));
        //}
		
		// 为指定类注册拦截器
        if (InternalAsyncHelper.DisableFilterTenantTypes.Any(a => a.IsAssignableFrom(implementationType)))
        {
            handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(TenantInterceptor)));
        }
    }
}

internal static class InternalAsyncHelper
{
    public static Type[] DisableFilterTenantTypes =
    {
        typeof(IRepository<Student,Guid>),
        typeof(IRepository<School,Guid>)
    };
}

TenantInterceptorRegistrarInitialize方法中,首先会注入整个ABP系统中唯一的IIocManager,然后就是订阅唯一的IocContainer这个容器的ComponentRegistered事件,在订阅事件中首先是获取当前触发此事件的类型信息,然后根据需求注册TenantInterceptor这个拦截器。

这里有一点需要注意,本来想为实现了IApplicationService接口的类注册拦截器,但是ASP.NET Boilerplate使用动态方法拦截的功能有一些限制

  • 如果通过接口调用该方法,则可以将其用于任何公共方法(例如,通过接口使用的Application Services)。
  • 如果直接从类引用(例如ASP.NET MVC或Web API控制器)中调用方法,则该方法应为虚拟方法。
  • 一种方法应该是虚拟的,如果它的保护。

也就是如果将服务作为客户端的Web API控制器公开,那么方法必须是虚方法(virtual) 附上官方Git issues

最后一步就是把拦截器在模块文件中初始化

public class ApplicationCoreModule : AbpModule
{
    public override void PreInitialize()
    {
        TenantInterceptorRegistrar.Initialize(IocManager.IocContainer.Kernel);
    }

    public override void Initialize()
    {
    }
}

这样就可以按着自己的需要在DisableFilterTenantTypes 中配置自己想配置的仓储了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

V-BOX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值