Open Closed

Cannot isolate IPermissionChecker implementation in the shared project #4433


User avatar
0
alexander.nikonov created
  • ABP Framework version: v5.1.2
  • UI type: Angular
  • DB provider: EF Core
  • Identity Server Separated (Angular)

I am trying to create a custom implementation of IPermissionChecker in the shared project and consume this implementation in several projects. Currently I'm having the problem with this implementation. Here is the checker:

[Dependency(ReplaceServices = false)]
public class AbxPermissionChecker : IPermissionChecker
{
    private PermissionChecker _abpPermissionChecker;
    private IServiceProvider _serviceProvider;
    private readonly ILicencePermissionChecker _licencePermissionChecker;

    public AbxPermissionChecker
    (
        PermissionChecker abpPermissionChecker,
        IServiceProvider serviceProvider,
        ILicencePermissionChecker licencePermissionChecker
    )
    {
        _abpPermissionChecker = abpPermissionChecker;
        _serviceProvider = serviceProvider;
        _licencePermissionChecker = licencePermissionChecker;
    }

    public async Task<bool> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name)
    {
        using var scope = _serviceProvider.CreateScope();

        var abxRequestContext = scope.ServiceProvider.GetRequiredService<IAbxRequestContext>();

        return await _licencePermissionChecker.IsGrantedAsync(abxRequestContext.AbxTenantId, abxRequestContext.AbxModuleId) && await _abpPermissionChecker.IsGrantedAsync(claimsPrincipal, name);
    }

    public Task<bool> IsGrantedAsync(string name)
    {
        return _abpPermissionChecker.IsGrantedAsync(name);
    }

    public Task<MultiplePermissionGrantResult> IsGrantedAsync(string[] names)
    {
        return _abpPermissionChecker.IsGrantedAsync(names);
    }

    public Task<MultiplePermissionGrantResult> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string[] names)
    {
        return _abpPermissionChecker.IsGrantedAsync(claimsPrincipal, names);
    }
}

public class PermissionManager : DomainService
{
    private readonly IRepository<Tenant, int> _tenantRepository;
    private readonly IRepository<ModuleLicence> _moduleLicenceRepository;
    private readonly IRepository<CompanyLicence> _companyLicenceRepository;

    public PermissionManager
    (
        IRepository<Tenant, int> tenantRepository,
        IRepository<ModuleLicence> moduleLicenceRepository,
        IRepository<CompanyLicence> companyLicenceRepository
    )
    {
        _tenantRepository = tenantRepository;
        _moduleLicenceRepository = moduleLicenceRepository;
        _companyLicenceRepository = companyLicenceRepository;
    }

    public async Task<List<string>> GetAccessibleModulesAsync(int abxTenantId)
    {
        var tenants = await _tenantRepository.GetQueryableAsync();
        var companyLicences = await _companyLicenceRepository.GetQueryableAsync();
        var moduleLicences = await _moduleLicenceRepository.GetQueryableAsync();

        var query = from tenant in tenants.Where(x => x.Id == abxTenantId).Take(1)
                    join companyLicence in companyLicences on tenant.CompanyId equals companyLicence.CompanyId
                    join moduleLicence in moduleLicences on companyLicence.LicenceId equals moduleLicence.LicenceId
                    select moduleLicence.ModuleId;

        return query.Distinct().ToList();
    }
}

The exception I'm getting in the consuming project when accessing PermissionManager method:

Autofac.Core.DependencyResolutionException: An exception was thrown while activating Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController -> Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationAppService -> AbxEps.CT.Core.Permissions.AbxPermissionChecker -> AbxEps.CT.Core.Permissions.AbxLicencePermissionChecker -> AbxEps.CT.Core.Permissions.PermissionManager. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'AbxEps.CT.Core.Permissions.PermissionManager' can be invoked with the available services and parameters: Cannot resolve parameter 'Volo.Abp.Domain.Repositories.IRepository2[AbxEps.CT.Core.Tenants.Tenant,System.Int32] tenantRepository' of constructor 'Void .ctor(Volo.Abp.Domain.Repositories.IRepository2[AbxEps.CT.Core.Tenants.Tenant,System.Int32], Volo.Abp.Domain.Repositories.IRepository1[AbxEps.CT.Core.ModuleLicences.ModuleLicence], Volo.Abp.Domain.Repositories.IRepository1[AbxEps.CT.Core.CompanyLicences.CompanyLicence])'.

Now let me explain what I'm trying to achieve. CoreDbContext in the shared project contains SIMPLIFIED models of entities which are ALREADY bound in the consuming project. Since I cannot bind the model to the same table name twice in the same DbContext as well as I don't want to MOVE a complex model binding from consuming project to the shared project, I decided to use two independent DbContext:

public static void ConfigureCore(
    this ModelBuilder builder,
    Action<CoreModelBuilderConfigurationOptions> optionsAction = null
) {
    builder.Entity<CompanyLicence>(b =>
    {
        b.ToTable("CT_CA_COMP_LIC", CentralToolsConsts.DbSchema);
        .... simplified binding
    }

public static void ConfigureConsuming(
    this ModelBuilder builder,
    Action<ConsumingModelBuilderConfigurationOptions> optionsAction = null
) {
    builder.Entity<CompanyLicence>(b =>
    {
        b.ToTable("CT_CA_COMP_LIC", CentralToolsConsts.DbSchema);
        .... advanced binding
    }

6 Answer(s)
  • User Avatar
    0
    alexander.nikonov created

    I've tried to resolved the issue with the code below (separating DbContexts):

    public static void ConfigureCoreInternal(this ModelBuilder builder, Action<CoreModelBuilderConfigurationOptions> optionsAction = null)
    ...
    

    EntityFramework Module:

    [DependsOn(typeof(CoreDomainModule), typeof(AbpEntityFrameworkCoreModule))]
    public class CoreEntityFrameworkCoreModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.AddAbpDbContext<CoreDbContext>(options =>
            {
                options.AddDefaultRepository<ModuleLicence>();
                options.AddDefaultRepository<CompanyLicence>();
                options.AddDefaultRepository<Tenant>();
            });
        }
    }
    

    The method which does DB work:

    public async Task<List<string>> GetAccessibleModulesAsync(int abxTenantId)
    {
        using (var uow = _unitOfWorkManager.Begin())
        {
            var tenants = await _tenantRepository.GetQueryableAsync();
            var companyLicences = await _companyLicenceRepository.GetQueryableAsync();
            var moduleLicences = await _moduleLicenceRepository.GetQueryableAsync();
    
            var query = from tenant in tenants.Where(x => x.Id == abxTenantId).Take(1)
                        join companyLicence in companyLicences on tenant.CompanyId equals companyLicence.CompanyId
                        join moduleLicence in moduleLicences on companyLicence.LicenceId equals moduleLicence.LicenceId
                        select moduleLicence.ModuleId;
    
            return query.Distinct().ToList();
        }
    }
    

    Application Module where I add my custom class AbxPermissionChecker:

    [DependsOn(...., typeof(CoreApplicationModule))]
    public class CentralToolsApplicationModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var configuration = context.Services.GetConfiguration();
    
            Configure<AbpAutoMapperOptions>(options =>
            {
                options.AddMaps<CentralToolsApplicationModule>();
            });
    
            ....
            context.Services.Replace(ServiceDescriptor.Transient<IPermissionChecker, AbxPermissionChecker>()); // REPLACING ABP PermissionChecker!
        }
    }
    

    But still getting the above exception

    What is a proper way of isolating entities in the DbContext of the project which is shared? Maybe this is the only root of the problem?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The situation may be complicated, can you share the simplest project to reproduce your problem? I can download and check it.

  • User Avatar
    0
    alexander.nikonov created

    Eventually I've resolved thie issue. I've split the shared project DbContexts into 2 - one contains the entities which are shared in the consuming project, another one contains the entities which use the same table as the entities in the consuming project. Please, replenish my point for this question.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I think there is no problem with this.

  • User Avatar
    0
    alexander.nikonov created

    hi

    I think there is no problem with this.

    Restore my question points then please if not done yet.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Refunded

Made with ❤️ on ABP v9.1.0-preview. Updated on December 10, 2024, 06:38