- ABP Framework version: v7.2
- UI Type: Angular
- Database System: EF Core (PostgreSQL)
- Tiered (for MVC) or Auth Server Separated (for Angular): yes
Was not able to find any samples or documentation on how to enable url host tenant mapping feature in abp commercial microservices solution.
Maybe you can help?
I found samples repo, but there is no microservices sample available. Also tried to backward engineer feature enabling according tiered identity server solution, but it is not working.
Would appreciate your help on this.
Best Regards.
26 Answer(s)
-
0
Hello kirotech,
Could you please guide us how to reproduce this issue, share some steps to reproduce if possible.
Thank you
-
0
There is no documentation nor samples how to enable subdomain mapping to saas tenant feature on your abp commercial microservices solution.
I probably could provide you with zip with the current state of work and maybe you can fix it?
At the moment we getting authentication issues, also infinite login loop issue.
If you provide documentation or sample for your abp commercial microservices solution it would be great.
I found example for identity server tiered and openiddict monolitick solutions, but there is none for microservice commercial solution.
I need your support on this.
-
0
Hi
please check this doc for resolving subdomain for tenant https://docs.abp.io/en/abp/latest/Multi-Tenancy#domain-subdomain-tenant-resolver
you can place this code in BookstoreSharedHostingMicroservicesModule
{yourprojectname}.Shared.Hosting.Microservices
you can see the sample of ng tiered demo which will be similar to microservice. https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/NG-TIERED
-
0
Hello kirotech,
Please do let us know if this solution has worked for you?
Awaiting for your response.
Thank You, Anjali
-
0
I'm afraid to tell, but I'm not able to enable host mapping feature in abp commercial microservices solution.
I already used sample your provided (https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/NG-TIERED) to backward engineer configuration for abp commercial microservices solution, but it didn't work as i mentioned i started getting number of issues starting ssl issues ending openiddict configuration authentication issues.
Could you please provide abp commercial microservices solution host mapping feature configuration documentation or sample?
Let me know how you want to move forward.
Best regards.
-
0
Hi,
can you explain your issue with a scenarios as i am not able clearly able to understand enable url host tenant mapping feature. The sample provided can work in microservices too but yes may differ in configuration.
if you can provide a more detailed instructions of what you are trying to achieve we can provide some sample code related to that.
Thanks.
-
1
Yes i can provide more details.
We do want to configure subdomain to tenant mapping feature in abp commercial microservices solution.
Feature is described in the doc your provided: https://docs.abp.io/en/abp/latest/Multi-Tenancy?&_ga=2.146571124.1730784827.1693308814-2050754730.1671709604#domain-subdomain-tenant-resolver
{0}.mydomain.com we want to map {0} to tenant in abp commercial microservices solution.
There is no docs nor sample for that.
So we tried to use your ng tiered sample from here: https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/NG-TIERED
It didn't work.
Can you provide sample how to configure this abp feature in your abp commercial microservices solution?
I can invite you in test repository where i have my current progress and you can apply your configuration sample directly or you going to provide it here?
Best regards.
-
1
Hello,
Looks like your openiddict ng sample has issues.
How to reproduce:
- Run https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver/OpenIddict/NG
- Login with host
- Create new tenant
- Go to https://newtenant.ng.abp.net:4200
- Click login
- You get open iddict redirect uri error:
error:invalid_request error_description:The specified 'redirect_uri' is not valid for this client application. error_uri:https://documentation.openiddict.com/errors/ID2043
How do you guys want to proceed on abp commercial microservices sample issues?
Best regards.
-
0
any update?
-
0
check out https://community.abp.io/posts/how-to-use-domainbased-tenant-resolver-in-abp-with-angular-and-openiddict-v9y8da7v
-
0
Hello alper, article helped to solve redirect_uri issue, but now I face angular problem where if you go to https://testtenant.ng.abp.net:4200 angular doesn't load because if he thinks that user is not authenticated no matter authserver returned valid token and issuer matching angular issuer environment config.
I do have all this abp commercial microservices tenant subdomain mapping config in separate test repository which im ok to share with you if needed.
I still need help with finishing this abp commercial microservices feature work.
-
0
Hello alper, article helped to solve redirect_uri issue, but now I face angular problem where if you go to https://testtenant.ng.abp.net:4200 angular doesn't load because if he thinks that user is not authenticated no matter authserver returned valid token and issuer matching angular issuer environment config.
I do have all this abp commercial microservices tenant subdomain mapping config in separate test repository which im ok to share with you if needed.
I still need help with finishing this abp commercial microservices feature work.
Hi, kirotech, if you have problem at the angular side, you can try the following steps, maybe it will work:
- Create a
multi-tenancy-utils.ts
file, this will be override the default implementation of ABP framework:
import { ABP, CORE_OPTIONS, Environment, EnvironmentService, createTokenParser, getRemoteEnv, } from '@abp/ng.core'; import { Injector } from '@angular/core'; import clone from 'just-clone'; const tenancyPlaceholder = '{0}'; function getCurrentTenancyName(appBaseUrl: string): string { if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/'; const parseTokens = createTokenParser(appBaseUrl); const token = tenancyPlaceholder.replace(/[}{]/g, ''); return parseTokens(window.location.href)[token]?.[0]; } export function cleanPlaceholderFromHostUrl(injector: Injector) { const fn = async () => { const environmentService = injector.get(EnvironmentService); const options = injector.get(CORE_OPTIONS) as ABP.Root; environmentService.setState(options.environment as Environment); await getRemoteEnv(injector, options.environment); const baseUrl = environmentService.getEnvironment()['appBaseUrl'] || environmentService.getEnvironment().application?.baseUrl || ''; const tenancyName = getCurrentTenancyName(baseUrl); if (!tenancyName) { /** * If there is no tenant, we still have to clean up {0}. from baseUrl to avoid incorrect http requests. */ replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder + '.'); replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder); } return Promise.resolve(); }; return fn; } function replaceTenantNameWithinEnvironment( injector: Injector, tenancyName: string, placeholder = tenancyPlaceholder ) { const environmentService = injector.get(EnvironmentService); const environment = clone(environmentService.getEnvironment()) as Environment; if (environment.application.baseUrl) { environment.application.baseUrl = environment.application.baseUrl.replace( placeholder, tenancyName ); } if (environment.oAuthConfig?.redirectUri) { environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace( placeholder, tenancyName ); } if (!environment.oAuthConfig) { environment.oAuthConfig = {}; } environment.oAuthConfig.issuer = (environment.oAuthConfig.issuer || '').replace( placeholder, tenancyName ); environment.oAuthConfig.clientId = (environment.oAuthConfig.clientId || '').replace( placeholder, tenancyName ); Object.keys(environment.apis).forEach(api => { Object.keys(environment.apis[api]).forEach(key => { environment.apis[api][key] = (environment.apis[api][key] || '').replace( placeholder, tenancyName ); }); }); return environmentService.setState(environment); }
- Create
domain-resolver.module.ts
file:
import { CommonModule } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; import { APP_INITIALIZER, Injector, NgModule } from '@angular/core'; import { cleanPlaceholderFromHostUrl } from './multi-tenancy-utils'; @NgModule({ imports: [CommonModule, HttpClientModule], providers: [ { provide: APP_INITIALIZER, multi: true, deps: [Injector], useFactory: cleanPlaceholderFromHostUrl, }, ], }) export class DomainResolverModule {}
- Import the
DomainResolverModule
in yourAppModule
:
import { CoreModule } from '@abp/ng.core'; import { GdprConfigModule } from '@volo/abp.ng.gdpr/config'; import { SettingManagementConfigModule } from '@abp/ng.setting-management/config'; import { HTTP_ERROR_HANDLER, ThemeSharedModule } from '@abp/ng.theme.shared'; import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CommercialUiConfigModule } from '@volo/abp.commercial.ng.ui/config'; import { AccountAdminConfigModule } from '@volo/abp.ng.account/admin/config'; import { AccountPublicConfigModule } from '@volo/abp.ng.account/public/config'; import { AuditLoggingConfigModule } from '@volo/abp.ng.audit-logging/config'; import { IdentityConfigModule } from '@volo/abp.ng.identity/config'; import { LanguageManagementConfigModule } from '@volo/abp.ng.language-management/config'; import { registerLocale } from '@volo/abp.ng.language-management/locale'; import { SaasConfigModule } from '@volo/abp.ng.saas/config'; import { TextTemplateManagementConfigModule } from '@volo/abp.ng.text-template-management/config'; import { HttpErrorComponent, ThemeLeptonModule } from '@volo/abp.ng.theme.lepton'; import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { APP_ROUTE_PROVIDER } from './route.provider'; import { OpeniddictproConfigModule } from '@volo/abp.ng.openiddictpro/config'; import { FeatureManagementModule } from '@abp/ng.feature-management'; import { AbpOAuthModule } from '@abp/ng.oauth'; import { ServiceWorkerModule } from '@angular/service-worker'; import { APP_VALIDATION_PROVIDER } from './validation/app.validation.provider'; import { DomainResolverModule } from './customization'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, BrowserAnimationsModule, AppRoutingModule, DomainResolverModule, CoreModule.forRoot({ environment, registerLocaleFn: registerLocale(), }), AbpOAuthModule.forRoot(), ThemeSharedModule.forRoot({ httpErrorConfig: { errorScreen: { component: HttpErrorComponent, forWhichErrors: [401, 403, 404, 500], hideCloseIcon: true, }, }, }), // Other import statements ], providers: [ APP_ROUTE_PROVIDER, APP_VALIDATION_PROVIDER ], bootstrap: [AppComponent], }) export class AppModule {}
- Create a
-
0
Thank you Linch, what problem you been solving by rewriting angular domain resolver? As i understand it supposed to work out of the box without rewriting it?
-
0
Hello alper, Anjali_Musmade. Any update? I still need help with this abp commercial microservices solution feature.
-
0
any update?
-
0
any update regarding this issue?
-
0
any update?
-
0
Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?
@mahmut.gundogdu Did we have updates on v7.4 based on this issue?
-
0
Thank you Linch, what problem you been solving by rewriting angular domain resolver? As i understand it supposed to work out of the box without rewriting it?
Hi, kirotech, I just updated the code of
multi-tenancy-utils.ts
, because it is work for datdv1 https://support.abp.io/QA/Questions/5650#answer-3a0d82ab-0969-e910-4824-cab59dc00e91Maybe you can try this to solve your problem. Hope it is work for you.
import { ABP, CORE_OPTIONS, Environment, EnvironmentService, createTokenParser, getRemoteEnv, } from '@abp/ng.core'; import { Injector } from '@angular/core'; import clone from 'just-clone'; const tenancyPlaceholder = '{0}'; function getCurrentTenancyName(appBaseUrl: string): string { if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/'; const parseTokens = createTokenParser(appBaseUrl); const token = tenancyPlaceholder.replace(/[}{]/g, ''); return parseTokens(window.location.href)[token]?.[0]; } export function cleanPlaceholderFromHostUrl(injector: Injector) { const fn = async () => { const environmentService = injector.get(EnvironmentService); const options = injector.get(CORE_OPTIONS) as ABP.Root; environmentService.setState(options.environment as Environment); await getRemoteEnv(injector, options.environment); const baseUrl = environmentService.getEnvironment()['appBaseUrl'] || environmentService.getEnvironment().application?.baseUrl || ''; const tenancyName = getCurrentTenancyName(baseUrl); if (!tenancyName) { /** * If there is no tenant, we still have to clean up {0}. from baseUrl to avoid incorrect http requests. */ replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder + '.'); replaceTenantNameWithinEnvironment(injector, '', tenancyPlaceholder); } return Promise.resolve(); }; return fn; } function replaceTenantNameWithinEnvironment( injector: Injector, tenancyName: string, placeholder = tenancyPlaceholder ) { const environmentService = injector.get(EnvironmentService); const environment = clone(environmentService.getEnvironment()) as Environment; if (environment.application.baseUrl) { environment.application.baseUrl = environment.application.baseUrl.replace( placeholder, tenancyName ); } if (environment.oAuthConfig?.redirectUri) { environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace( placeholder, tenancyName ); } if (!environment.oAuthConfig) { environment.oAuthConfig = {}; } environment.oAuthConfig.issuer = (environment.oAuthConfig.issuer || '').replace( placeholder, tenancyName ); environment.oAuthConfig.clientId = (environment.oAuthConfig.clientId || '').replace( placeholder, tenancyName ); Object.keys(environment.apis).forEach(api => { Object.keys(environment.apis[api]).forEach(key => { environment.apis[api][key] = (environment.apis[api][key] || '').replace( placeholder, tenancyName ); }); }); return environmentService.setState(environment); }
-
0
Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?
@mahmut.gundogdu Did we have updates on v7.4 based on this issue?
I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.
I created a separate github repo where i can reproduce the issue for this feature.
-
0
Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?
@mahmut.gundogdu Did we have updates on v7.4 based on this issue?
I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.
I created a separate github repo where i can reproduce the issue for this feature.
Please do share the github repository if its non-commercial or you can add galiperdem@gmail.com if it is commercial and private repository.
-
0
Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?
@mahmut.gundogdu Did we have updates on v7.4 based on this issue?
I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.
I created a separate github repo where i can reproduce the issue for this feature.
Please do share the github repository if its non-commercial or you can add galiperdem@gmail.com if it is commercial and private repository.
OK. I invited your email to the repo. Yes it is commercial product microservices architecture version. It is private repo.
-
0
Did you try the LichArnold's solution at https://support.abp.io/QA/Questions/5638/How-to-enable-ABP-Commercial-host-tenant-mapping-feature-in-ABP-commercial-microservices-solution#answer-3a0d8f61-d8d7-8289-06cd-6c106915fe24 ?
@mahmut.gundogdu Did we have updates on v7.4 based on this issue?
I did not try no. I believe it supposed to work out of the box? My thought was because of lack of samples and documentation maybe i misconfigured feature.
I created a separate github repo where i can reproduce the issue for this feature.
Please do share the github repository if its non-commercial or you can add galiperdem@gmail.com if it is commercial and private repository.
any update?
-
0
We've created internal issue related to this. It will be fixed in the next minor or major patch based on Angular team's workload.
I've refunded your credit.
Thank you.
-
0
We've created internal issue related to this. It will be fixed in the next minor or major patch based on Angular team's workload.
I've refunded your credit.
Thank you.
Thank you very much for your help. Really appreciate it. Can you explain the problem a bit? I see you didn't event look at our repo. Maybe there is some temporary workaround while you release commercial fix?