iammukeshm / multitenancy-aspnet-core Goto Github PK
View Code? Open in Web Editor NEWMultitenancy in ASP.NET Core
Home Page: https://codewithmukesh.com/blog/multitenancy-in-aspnet-core/
Multitenancy in ASP.NET Core
Home Page: https://codewithmukesh.com/blog/multitenancy-in-aspnet-core/
Hello, I am trying to set up a structure as in the picture below using the codes you shared.
The system administrator of this application is "Root User", a user with the ability to add other users to the system.
Gold, silver, bronze .. etc. will have an unlimited user base. Each will have their own database. Let's not get hung up on the naming. These will be in the form of individual customers, not as a group.
All users will log into the application from the same place. If the user is a system administrator, he will only see the area related to users. This is about frontend. If it is in normal user status, it will read the connection string from the "Shared DB" and connect to the relevant database.
I want to save Tenant definitions in "Shared DB" database. Appsettings.json will only have "Shared DB" information.
For example, when "Gold User" logs in, it will read its own connection string from "Shared DB" and continue its operations in "Gold DB". Also, it will not close the other connection so that it can read other data from "Shared DB".
I am trying to add "DB Context" in a multiple way. However, only the 2nd "DB Context" I added works in the controller. It crushes the first.
Can you help me with this part?
For now I'm pulling the Tenant definitions from the appsettings.json file. I am using .Net Core 6.0.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"TenantSettings": {
"Defaults": {
"DBProvider": "mssql",
"ConnectionString": "Server=192.168.0.78,1435;Database=tenant_SharedDB;User Id=sa;Password=***;"
},
"Tenants": [
{
"Name": "bronze",
"TenantId": "bronze",
"ConnectionString": "Server=192.168.0.78,1435;Database=tenant_BronzeTenantDB;User Id=sa;Password=***;"
},
{
"Name": "silver",
"TenantId": "silver",
"ConnectionString": "Server=192.168.0.78,1435;Database=tenant_SilverTenantDB;User Id=sa;Password=***;"
},
{
"Name": "gold",
"TenantId": "gold",
"ConnectionString": "Server=192.168.0.78,1435;Database=tenant_GoldTenantDB;User Id=sa;Password=***;"
}
]
}
}
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddHttpContextAccessor();
builder.Services.Configure<TenantSettings>(builder.Configuration.GetSection("TenantSettings"));
builder.Services.AddInfrastructureService();
await builder.Services.AddPersistenceService();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/UserControllers/swagger.json", "MultiTenantWebApi - User Tables");
c.SwaggerEndpoint("/swagger/ProductControllers/swagger.json", "MultiTenantWebApi - Product Tables");
});
}
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
public static class ServiceRegistration
{
public static void AddInfrastructureService(this IServiceCollection collection)
{
collection.AddTransient<ITenantService, TenantService>();
}
public static async Task AddPersistenceService(this IServiceCollection collection)
{
collection.AddScoped<IUserService, UserService>();
collection.AddScoped<IProductService, ProductService>();
using var provider = collection.BuildServiceProvider();
var configuration = provider.GetRequiredService<IConfiguration>();
var tenantSettings = configuration.GetSection("TenantSettings").Get<TenantSettings>();
var defaultConnectionString = tenantSettings.Defaults?.ConnectionString;
var defaultDbProvider = tenantSettings.Defaults?.DbProvider;
if (defaultDbProvider.ToLower() == "mssql")
{
collection.AddDbContext<SharedDbContext>(option => option.UseSqlServer(e => e.MigrationsAssembly(typeof(SharedDbContext).Assembly.FullName)));
}
using IServiceScope scope = collection.BuildServiceProvider().CreateScope();
// SharedDb Migration
var dbContext = scope.ServiceProvider.GetRequiredService<SharedDbContext>();
dbContext.Database.SetConnectionString(defaultConnectionString);
if (dbContext.Database.GetMigrations().Count() > 0)
await dbContext.Database.MigrateAsync();
if (defaultDbProvider.ToLower() == "mssql")
{
collection.AddDbContext<TenantDbContext>(option => option.UseSqlServer(e => e.MigrationsAssembly(typeof(TenantDbContext).Assembly.FullName)));
}
using IServiceScope scope2 = collection.BuildServiceProvider().CreateScope();
foreach (var tenant in tenantSettings.Tenants)
{
string connectionString = tenant.ConnectionString switch
{
null => defaultConnectionString,
not null => tenant.ConnectionString
};
var dbContext2 = scope2.ServiceProvider.GetRequiredService<TenantDbContext>();
dbContext2.Database.SetConnectionString(connectionString);
if (dbContext2.Database.GetMigrations().Count() > 0)
await dbContext2.Database.MigrateAsync();
}
}
}
With these codes, migrations are working correctly. I have bound the User table to the SharedDbContext. I also bound the Product table to TenantDbContext. The tables are created in the corresponding databases.
Product listing and adding products work correctly in the controller. But user listing, adding user is not working. I am getting an error like this:
I just need help with controller. Because I couldn't find enough resources for .net core. I don't have enough knowledge. What do I need to do for the controller to work properly?
I wish you good work.
Hi,
Thanks for this project! Unfortunately I'm having difficulties when trying to remove a migration. Running the project and adding migrations works without problems, executing "remove-migration" results in the following error message:
PM> Remove-Migration
Build started...
Build succeeded.
System.InvalidOperationException: A relational store has been configured without specifying either the DbConnection or connection string to use.
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.get_DbConnection()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.<>c__DisplayClass18_0.<Exists>b__0(DateTime giveUp)
at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.<>c__DisplayClass12_0`2.<Execute>b__0(DbContext c, TState s)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.Execute[TState,TResult](IExecutionStrategy strategy, TState state, Func`2 operation, Func`2 verifySucceeded)
at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.Execute[TState,TResult](IExecutionStrategy strategy, TState state, Func`2 operation)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Exists(Boolean retryOnNotExists)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerDatabaseCreator.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()
at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.RemoveMigration(String projectDir, String rootNamespace, Boolean force, String language)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.RemoveMigration(String contextType, Boolean force)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.RemoveMigrationImpl(String contextType, Boolean force)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.RemoveMigration.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
**A relational store has been configured without specifying either the DbConnection or connection string to use.**
Steps to reproduce:
Do you know how to solve this issue?
Please upgrade to .NET 6 (current .NET 5)
It was not possible to find any compatible framework version
The framework 'Microsoft.AspNetCore.App', version '5.0.0' (x64) was not found.
- The following frameworks were found:
6.0.3 at [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
7.0.0-preview.3.22178.4 at [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
You can resolve the problem by installing the specified framework and/or SDK.
The specified framework can be found at:
- https://aka.ms/dotnet-core-applaunch?framework=Microsoft.AspNetCore.App&framework_version=5.0.0&arch=x64&rid=win10-x64
D:\github\multitenancy-aspnet-core\Multitenant.Api\bin\Debug\net5.0\Multitenant.Api.exe (process 12484) exited with code -2147450730.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.