在 ASP.NET Core 中实施 OrganizationUnit 过滤器

Implement OrganizationUnit filter in ASP.NET Core

在 ASP.NET 样板中,有内置的数据过滤器,如租户过滤器,我们可以使用 SetTenantId 来启用查询特定 tenantId.

根据官方文档,它不支持 EF Core 中的自定义 Filter,这与 EF 6.x 不同。

我想知道如何为 OrganizationUnitId 参数实现类似的过滤器。

这是我到目前为止所做的:

  1. 覆盖 CreateFilterExpression:

    protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
    {
        Expression<Func<TEntity, bool>> expression = null;
        if (typeof(IMayHaveOrganizationUnit).IsAssignableFrom(typeof(TEntity)))
        {
            Expression<Func<TEntity, bool>> mayHaveOUFilter = e => ((IMayHaveOrganizationUnit)e).OrganizationUnitId == CurrentOrganizationUnitId || (((IMayHaveOrganizationUnit)e).OrganizationUnitId == CurrentOrganizationUnitId) == IsMayHaveOrganizationUnitFilterEnabled;
            expression = expression == null ? mayHaveOUFilter : CombineExpressions(expression, mayHaveOUFilter);
        }
    
        expression = expression == null ? base.CreateFilterExpression<TEntity>() : CombineExpressions(expression, base.CreateFilterExpression<TEntity>());
    
        return expression;
    }
    
  2. 我通过下面的代码注册了新的过滤器:

    Configuration.UnitOfWork.RegisterFilter("MayHaveOrganizationUnit", true);
    

但是,我该如何实现设置 OrganizationUnitId 的代码?

SetTenantId用于配置tenantId,我如何配置OrganizationUnitIdUnitOfWork

  1. 我尝试继承 ClaimsAbpSession 如下所示:

    public class CustomAbpSession : ClaimsAbpSession, ICustomAbpSession
    {
        private readonly IRepository<User, long> _userRepository;
    
        public CustomAbpSession(
            IRepository<User, long> userRepository,
            IPrincipalAccessor principalAccessor,
            IMultiTenancyConfig multiTenancy,
            ITenantResolver tenantResolver,
            IAmbientScopeProvider<SessionOverride> sessionOverrideScopeProvider)
            : base(principalAccessor, multiTenancy, tenantResolver, sessionOverrideScopeProvider)
        {
            _userRepository = userRepository;
        }
    
        public virtual long? OrganizationUnitId
        {
            get
            {
                if (UserId != null)
                {
                    var user = _userRepository.Get(UserId.Value);
                    return 1;
                }
    
                return null;
            }
        }
    
        public long? ImpersonatorOrganizationUnitId => throw new NotImplementedException();
    }
    
    protected virtual long? GetCurrentOrganizationUnitIdOrNull()
    {
        return 3; // ((ICustomAbpSession)AbpSession).OrganizationUnitId;
    }
    
  2. 使用下面的代码注册自定义 IAbpSession:

    Configuration.ReplaceService(typeof(IAbpSession), () =>
    {
        IocManager.Register<IAbpSession, CustomAbpSession>(DependencyLifeStyle.Transient);
    });
    

用法:

public List<Product> GetAll()
{
    using (CurrentUnitOfWork.SetFilterParameter("MayHaveOrganizationUnit", "OrganizationUnitId", 2))
    {
        return _productRepositry.GetAll().ToList();
    }
}

但是,CustomAbpSessionOrganizationUnitId 的值总是 return,此方法 CurrentUnitOfWork.SetFilterParameter 没有将值设置到过滤器中。

这不仅仅是几行代码。

IMayHaveTenantCreateFilterExpression 中的过滤方式开始。

您可以在 DbContext 中覆盖 ShouldFilterEntityCreateFilterExpression

SetTenantId is used to configure the tenantId, how could I configure OrganizationUnitId from UnitOfWork?

您可以使用等效的 SetFilterParameter 方法。

But, it always return value from OrganizationUnitId in CustomAbpSession, this method CurrentUnitOfWork.SetFilterParameter did not set the value into filter.

CurrentUnitOfWorkProvider.Current,您可以访问 Filters

protected virtual long? GetCurrentOrganizationUnitIdOrNull()
{
    if (CurrentUnitOfWorkProvider != null &&
        CurrentUnitOfWorkProvider.Current != null)
    {
        return CurrentUnitOfWorkProvider.Current
            .Filters.FirstOrDefault(f => f.FilterName == "MayHaveOrganizationUnit")?
            .FilterParameters["OrganizationUnitId"] as long?;
    }

    return ((ICustomAbpSession)AbpSession).OrganizationUnitId;
}