In my ASP.NET Zero application, I want to setup data filters by CompanyId
value.
So I read the documents here and the information provided on this support forum thread.
In my EF Core project, I made the following change.
public override void PreInitialize()
{
if (!SkipDbContextRegistration)
{
// ...
Configuration.UnitOfWork.RegisterFilter("CompanyFilter", false);
}
}
I then followed the pattern used for IMustHaveTenant
data filter and applied the changes below into my DB context class:
protected int? CurrentCompanyId = null;
protected bool IsCompanyFilterEnabled => CurrentCompanyId != null && CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled("CompanyFilter") == true;
protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
if (typeof(IHasCompany).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return false;
}
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
{
Expression<Func<TEntity, bool>> expression = null;
if (typeof(IHasCompany).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> companyFilter = e => ((IHasCompany)e).CompanyId == CurrentCompanyId || (((IHasCompany)e).CompanyId == CurrentCompanyId) == IsCompanyFilterEnabled;
expression = expression == null ? companyFilter : CombineExpressions(expression, companyFilter);
}
return base.CreateFilterExpression<TEntity>();
}
Then, in my app service method where I wish to apply the filter, I added the code below.
public async Task<PagedResultDto<EmployeeListDto>> GetEmployees(GetEmployeeInput input)
{
using (CurrentUnitOfWork.EnableFilter("CompanyFilter"))
{
using (CurrentUnitOfWork.SetFilterParameter("CompanyFilter", "CompanyId", GetCurrentUserCompany()))
{
// ...
}
}
}
In the DB context class, if I hard code a CompanyId
value on the line below, the filter works just fine.
protected int? CurrentCompanyId = 123;
I will be honest, I do not fully understand the code that is being used in the CreateFilterExpression
method in the DB context class. I borrowed this straight from the ABP GitHub repo code for IMustHaveTenant
filter.
I have modified the ABP user "My Settings" modal to include CompanyId
. This permits each user to be assigned to a company and thus the application should restrict all data by company for this user.
In my app service base class, I have a method named GetCurrentUserCompany
. This method gets the current user's default company. This is the value that should be used on the data filter for company.
Questions:
CompanyId
in this DB context class?Update: I added the code suggested by Aaron and its still not working. I'm testing with a user Id who has company 1 assigned. Yet when the data loads, it still showing them company 1 and 2.
When line 77 executes and does the GetAll call on the repository, its still showing all companies to the user.
Oct 6 Update: The new code works, but only when the user has a company Id assigned. When the user does not have a company assigned, the error shown in the image below is thrown.
- Do I need to set this company value in the Db context class?
- If yes, then how do I call an app service or repository method to get the company Id in this DB context class?
No. Implement a getter in your DbContext
class:
// using Abp.Collections.Extensions;
// protected int? CurrentCompanyId = null;
protected int? CurrentCompanyId => GetCurrentCompanyIdOrNull();
protected virtual int? GetCurrentCompanyIdOrNull()
{
if (CurrentUnitOfWorkProvider != null &&
CurrentUnitOfWorkProvider.Current != null)
{
return CurrentUnitOfWorkProvider.Current
.Filters.FirstOrDefault(f => f.FilterName == "CompanyFilter")?
.FilterParameters.GetOrDefault("CompanyId") as int?;
}
return null;
}
Return expression
in your CreateFilterExpression
method:
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
{
// Expression<Func<TEntity, bool>> expression = null;
var expression = base.CreateFilterExpression<TEntity>();
if (typeof(IHasCompany).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> companyFilter = e => ((IHasCompany)e).CompanyId == CurrentCompanyId || (((IHasCompany)e).CompanyId == CurrentCompanyId) == IsCompanyFilterEnabled;
expression = expression == null ? companyFilter : CombineExpressions(expression, companyFilter);
}
// return base.CreateFilterExpression<TEntity>();
return expression;
}
A similar question: Implement OrganizationUnit filter in ASP.NET Core