JonPSmith / AuthPermissions.AspNetCore

This library provides extra authorization and multi-tenant features to an ASP.NET Core application.
https://www.thereformedprogrammer.net/finally-a-library-that-improves-role-authorization-in-asp-net-core/
MIT License
788 stars 159 forks source link

.net 7 Error Sharding Example #80

Closed johndcollins closed 1 year ago

johndcollins commented 1 year ago

Hi Jon, I'm trying to add your Sharding Example to my .net 7 Web App. I'm getting the following error: I can't seem to locate the issue.

System.AggregateException HResult=0x80131500 Message=Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: AuthPermissions.AdminCode.ITenantChangeService Lifetime: Transient ImplementationType: MyProject.Web.Sharding.ShardingTenantChangeService': Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions1[MyProject.Web.Sharding.ShardingSingleDbContext]' while attempting to activate 'MyProject.Web.Sharding.ShardingTenantChangeService'.) Source=Microsoft.Extensions.DependencyInjection StackTrace: at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection1 serviceDescriptors, ServiceProviderOptions options) at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options) at Microsoft.Extensions.Hosting.HostApplicationBuilder.Build() at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build() at Program.

$(String[] args) in C:\MyProject\src\MyProject.Web\Program.cs:line 84

This exception was originally thrown at this call stack: [External Code]

Inner Exception 1: InvalidOperationException: Error while validating the service descriptor 'ServiceType: AuthPermissions.AdminCode.ITenantChangeService Lifetime: Transient ImplementationType: MyProject.Web.Sharding.ShardingTenantChangeService': Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MyProject.Web.Sharding.ShardingSingleDbContext]' while attempting to activate 'MyProject.Web.Sharding.ShardingTenantChangeService'.

Inner Exception 2: InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MyProject.Web.Sharding.ShardingSingleDbContext]' while attempting to activate 'MyProject.Web.Sharding.ShardingTenantChangeService'.

This is my startup code. It errors on the builder.Build() line

var builder = WebApplication.CreateBuilder(args);

// Add services to the container. var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext(options => options.UseSqlServer(connectionString));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = false) .AddEntityFrameworkStores();

builder.Services.AddControllersWithViews() .AddRazorRuntimeCompilation();

builder.Services.RegisterAuthPermissions(options => { options.TenantType = TenantTypes.SingleLevel | TenantTypes.AddSharding; options.EncryptionKey = builder.Configuration[nameof(AuthPermissionsOptions.EncryptionKey)]; options.PathToFolderToLock = builder.Environment.WebRootPath; options.SecondPartOfShardingFile = builder.Environment.EnvironmentName; options.Configuration = builder.Configuration; }) //NOTE: This uses the same database as the individual accounts DB .UsingEfCoreSqlServer(connectionString) .IndividualAccountsAuthentication() .RegisterAddClaimToUser() .RegisterAddClaimToUser() .RegisterTenantChangeService() .AddRolesPermissionsIfEmpty(MyProjectAppAuthSetupData.RolesDefinition) .AddTenantsIfEmpty(MyProjectAppAuthSetupData.TenantDefinition) .AddAuthUsersIfEmpty(MyProjectAppAuthSetupData.UsersRolesDefinition) .RegisterFindUserInfoService() .RegisterAuthenticationProviderReader() .AddSuperUserToIndividualAccounts() .SetupAspNetCoreAndDatabase(options => { //Migrate individual account database options.RegisterServiceToRunInJob<StartupServiceMigrateAnyDbContext>(); //Add demo users to the database (if no individual account exist) options.RegisterServiceToRunInJob();

    //Migrate the application part of the database
    options.RegisterServiceToRunInJob<StartupServiceMigrateAnyDbContext<ShardingSingleDbContext>>();
    //This seeds the invoice database (if empty)
    options.RegisterServiceToRunInJob<StartupServiceSeedShardingDbContext>();
});

//This is used to set a tenant as "Down", builder.Services.AddDistributedFileStoreCache(options => { options.WhichVersion = FileStoreCacheVersions.Class; //I override the the default first part of the FileStore cache file because there are many example apps in this repo options.FirstPartOfCacheFileName = "MyProjectCacheFileStore"; }, builder.Environment);

//manually add services from the AuthPermissions.SupportCode project builder.Services.AddSingleton<IGlobalChangeTimeService, GlobalChangeTimeService>(); //used for "update claims on a change" feature builder.Services.AddSingleton<IDatabaseStateChangeEvent, TenantKeyOrShardChangeService>(); //triggers the "update claims on a change" feature builder.Services.AddTransient<IAccessDatabaseInformation, AccessDatabaseInformation>(); builder.Services.AddTransient<ISetRemoveStatus, SetRemoveStatus>();

var app = builder.Build();

johndcollins commented 1 year ago

Looks like I was missing an important step in the RegisterExample6Invoices function. Maybe this should have been named differently :) Really has nothing to do with invoices.

        //Register the retail database to the same database used for individual accounts and AuthP database
        services.AddDbContext<ShardingSingleDbContext>(options =>
            options.UseSqlServer(
                configuration.GetConnectionString("DefaultConnection"), dbOptions =>
            dbOptions.MigrationsHistoryTable(ShardingSingleDbContextHistoryName)));