Hello
public class AccessTokenTenantResolver : HttpTenantResolveContributorBase
{
public override string Name => "AccessToken";
protected override Task<string> GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext)
{
string accessCode = httpContext.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(accessCode))
{
var token = accessCode.Split(" ")[1];
var tokenHandler = new JwtSecurityTokenHandler();
var tokens = tokenHandler.ReadJwtToken(token);
var client_id = tokens.Claims.FirstOrDefault(x => x.Type == "client_id").Value;
var scopes = tokens.Claims.FirstOrDefault(x => x.Type == "scope").Value;
}
return Task.FromResult("39fb7b60-0ba6-8109-70b1-a049e5f25575");
//throw new NotImplementedException();
}
}
I have this custom tenant resolver which resolves the tenant based on the client_id from the AccessToken. The Current Tenant Information is populated properly however the connection string of the tenant is not changed based on the connection string set in the database.
23 Answer(s)
-
0
hi
n. The Current Tenant Information is populated properly
Do you mean the
ICurrentTenant
is changed? Can you confirm?the connection string of the tenant is not changed based on the connection string set in the database.
Can you explain in details?
-
0
Do you mean the ICurrentTenant is changed? Can you confirm? Yes. It shows the proper tenant
The connection string of the tenant is not changed based on the connection string set in the database. I am using seperate database per tenant. The connection string is stored in the database for each tenant database. While running the query the connection string is not taken from the database.
E.g The Identity Server Project Has seperate connection strings for each module
"ConnectionStrings": { "Default": "Host=xxx.xxx.xxx.xxx;Port=5432;Database=Tenant1;Username=postgres;Password=xxxxxx;", "AbpIdentityServer": "Host=xxx.xxx.xxx.xxx;Port=5432;Database=Identity;Username=postgres;Password=xxxxxx;", "AbpIdentity": "Host=xxx.xxx.xxx.xxx;Port=5432;Database=Identity;Username=postgres;Password=xxxxxx;", }
and if I set a Default Connection String for the Tenant in the database (AbpTenantConnectionStrings Table) When I Try to login to this tenant the Identity Server throws errors
Npgsql.PostgresException (0x80004005): 42P01: relation "AbpUsers" does not exist
For some reason the abp tries to find the AbpUsers table in Tenant1 Database Instead of searching for it in Identity Database.
-
0
hi
Can you copy the code of
MultiTenantConnectionStringResolver
to debug to see what happend?https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs
-
0
Hi
The current tenant id is null in MultiTenantConnectionStringResolver even after the custom tenant resolver has executed also it is null when the api is executing.
I am on version 4.2.2
-
0
HI
That's why I need you to confirm the
ICurrentTenant
.So your
AccessTokenTenantResolver
is not working.The framework has some build in
TenantResolver
https://docs.abp.io/en/abp/latest/Multi-Tenancy#determining-the-current-tenantCurrentUserTenantResolveContributor: Gets the tenant id from claims of the current user, if the current user has logged in. This should always be the first contributor for the security.
-
0
I have disabled AccessTokenTenantResolver and trying to access the application it still cannot determine the tenant connection string from the database.
It only happens when a connection string for a tenant is set in the database.
Can you please do a remote session and check. I have been facing this issue since i upgraded to 4.2.2
Thanks
-
0
I have disabled AccessTokenTenantResolver and trying to access the application it still cannot determine the tenant connection string from the database. It only happens when a connection string for a tenant is set in the database.
hi
Can you check the
MultiTenantConnectionStringResolver
? I also check it if we remotely. -
0
I have checked MultiTenantConnectionStringResolver.
I'll share zoom details on email.
-
0
hi Mohammad
I have checked. This is by design.
Your tenant's default connection string should contain the module tables that support multi-tenancy.
The tenant's default connection string means default, So it will no longer look for the connection string on the host side.
If you don't want this behavior, you can customize
MultiTenantConnectionStringResolver
for some special cases of your. -
0
Hi Ma
Can you provide a sample code to acheive this using MultiTenantConnectionStringResolver ?
Thanks
-
0
hi
These few lines of code return the tenant's default connection string, you can call
return await base.ResolveAsync(connectionStringName);
for some situations, which will get the host's connection string.https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs#L76-L79
-
0
Hi Ma.
I was debugging the same. There is a very wierd behaviour with the MultiTenantConnectionStringResolver code.
For 1 request it asks to resolve AbpPermissionManagement, AbpAuditLogging on the 2nd request it Asks to resolve only AbpAuditLogging for the same page request.
I was trying a workaround. where I set a custom name for the tenant connection string. So when the connectionstring is required by the dbcontext it will try to resolve using the MultiTenantConnectionStringResolver.
I have two modules which work on multitenany
- ProductManagement
- Intelligence
So according the the code behaviour It should try to resolve connection string for ProductManagement and Intelligence. But it only tries to resolve ProductManagement.
This thread also has the same issues https://support.abp.io/QA/Questions/335/Steps-to-create-Single-Deployment---Multiple-Database-Multi-Tenant-Solution
If you can connect to me remotely I can show you the debug.
Thanks
-
0
For 1 request it asks to resolve AbpPermissionManagement, AbpAuditLogging on the 2nd request it Asks to resolve only AbpAuditLogging for the same page request.
I think this is because the
Permissions
are cached. So we don't need read it from db for 2nd request.So according the the code behaviour It should try to resolve connection string for ProductManagement and Intelligence. But it only tries to resolve ProductManagement.
It will only be triggered when Intelligence-related repositories are used and the
_currentTenant.Id
not be null.Your entity also need
IsMultiTenant
https://github.com/abpframework/abp/blob/c4e92a3431787b1a6727a615768a7a2906a9ba69/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs#L52 -
0
For 1 request it asks to resolve AbpPermissionManagement, AbpAuditLogging on the 2nd request it Asks to resolve only AbpAuditLogging for the same page request.
I think this is because the
Permissions
are cached. So we don't need read it from db for 2nd request.So according the the code behaviour It should try to resolve connection string for ProductManagement and Intelligence. But it only tries to resolve ProductManagement.
It will only be triggered when Intelligence-related repositories are used and the
_currentTenant.Id
not be null.Your entity also need
IsMultiTenant
I am using Single database per tenant.
- Should My entities implement IMultitenant?
-
0
The entity inherits
IMultiTenant
which means it is multi-tenant, and will try to get the connection string of the tenant. -
0
The entity inherits
IMultiTenant
which means it is multi-tenant, and will try to get the connection string of the tenant.In v4.0 It was working without Inheriting
IMultiTenant
https://github.com/abpframework/abp/blob/rel-4.0/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.csI think its a change that has been made in the new version?
-
0
See https://github.com/abpframework/abp/pull/7509
-
0
So what would you suggest in my case for Seperate database per tenant?
- Should I inherit all entities with IMultiTenant? If I do this then I'll have to store the tenantid in each table? Which doesnt serve the purpose of having separate databases per tenant.
-
0
You should implement the IMultiTenant interface for your entities to make them multi-tenancy ready.
https://docs.abp.io/en/abp/latest/Multi-Tenancy
-
0
Thanks
-
0
Hello
I am getting this error when I try to resolve a repository using ServiceProvider.GetService in CustomTenantResolver
Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
-
0
hi Mohammad
Please create a new question, Thanks
-
0
Hi Maliming
Its belonging to the customtenantresolver