For LeptonX + Angular (ABP 10) there is currently no built‑in setting or simple CSS switch to change/remove the 2026© Lepton Theme by Volosoft footer.
The supported way is to own the layout (or theme source) and register your own layout component via the Angular component replacement mechanism.
Download LeptonX source (commercial)
In ABP Suite → Tools → Download LeptonX Source, download the Angular LeptonX package.
This gives you the actual layout component HTML/TS so you can start from a copy instead of from scratch.
Copy the application layout component into your Angular app
From the downloaded source, locate the application layout component (it contains the current footer markup).
Copy that component (TS + HTML + SCSS) into your Angular project under e.g. src/app/layout/custom-application-layout.
Edit the footer section
In your copied HTML template, remove or change the footer markup – e.g. delete the copyright text or replace it with your own footer.
Register your layout via ReplaceableComponentsService
In a root module (usually AppModule), register your custom layout component as the implementation for the LeptonX application layout:
import { NgModule } from '@angular/core';
import { ReplaceableComponentsService } from '@abp/ng.core';
import { eThemeLeptonXComponents } from '@volosoft/abp.ng.theme.lepton-x';
import { CustomApplicationLayoutComponent } from './layout/custom-application-layout/custom-application-layout.component';
@NgModule({
declarations: [CustomApplicationLayoutComponent],
// imports: [...]
})
export class AppModule {
constructor(replaceableComponents: ReplaceableComponentsService) {
replaceableComponents.add({
component: CustomApplicationLayoutComponent,
key: eThemeLeptonXComponents.ApplicationLayout,
});
}
}
Once this is in place, your layout (with your footer or no footer at all) is used everywhere, and the original Volosoft copyright footer disappears.
LeptonX does not expose a documented CSS variable or configuration flag specifically for hiding the footer; the theme is designed to be customized via:
Because of that, the supported and future‑proof way on Angular is what’s described above: replace the layout component (or, if a dedicated footer component is used in your version, replace that footer component via the same mechanism).
For ABP 10 and current LeptonX for Angular, the situation is:
If you want this to become a simple configuration option, the official channel is to open a feature request or continue the discussion on the support portal so it can be tracked as a product change.
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
MapAbpStaticAssets (and underlying MapStaticAssets) works on the static web assets manifest generated at build/publish time.
That means:
wwwroot after deployment are not discovered by MapStaticAssets, so they return 404.So what you are seeing is expected behavior with MapStaticAssets/MapAbpStaticAssets and not a misconfiguration.
robots.txt per environmentYou have two practical options:
robots.txt in the project and republishrobots.txt into your Blazor Web App project under wwwroot (or another folder, as long as it’s part of static web assets)..csproj of the WebApp project):<ItemGroup>
<Content Include="wwwroot\robots.txt" CopyToOutputDirectory="Always" />
</ItemGroup>
For different environments (dev/test/prod), you can:
robots.txt into wwwroot before publish, orwwwroot/robots.txt based on an environment variable/profile.This fits best with the MapStaticAssets design.
/robots.txt (no republish for content changes)If you really need to change robots.txt without republishing, don’t rely on static web assets at all. Serve it via middleware or a minimal API that reads from the physical file or configuration:
In your Blazor Web App host project (where you call app.MapAbpStaticAssets()), add something like:
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
// ... existing pipeline configuration ...
app.MapAbpStaticAssets();
// Custom robots.txt endpoint
app.MapGet("/robots.txt", async ctx =>
{
ctx.Response.ContentType = "text/plain; charset=utf-8";
// Example 1: Different content by environment
if (env.IsDevelopment())
{
await ctx.Response.WriteAsync("User-agent: *\nDisallow:");
}
else if (env.IsEnvironment("Test"))
{
await ctx.Response.WriteAsync("User-agent: *\nDisallow: /");
}
else // Production
{
// Example 2: Read from a physical file that you can change on the server
var filePath = Path.Combine(env.ContentRootPath, "robots.txt");
if (File.Exists(filePath))
{
await ctx.Response.WriteAsync(await File.ReadAllTextAsync(filePath));
}
else
{
await ctx.Response.WriteAsync("User-agent: *\nDisallow:");
}
}
});
// ... rest of pipeline (routing, antiforgery, endpoints, etc.) ...
}
Notes:
robots.txt (or the logic) takes effect immediately on restart.robots.txt outside of wwwroot (e.g., at ContentRootPath) so it’s clearly treated as configuration, not a static asset.MapStaticAssets and MapAbpStaticAssets behavior (build-time optimization and use of static web assets manifest):This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
For a long‑lived, upgrade‑friendly Commercial solution, Option 2 is the recommended path:
This aligns with how ABP team advises adding Public Website/CMS Kit to existing apps:
you generate a new solution with Public Website, then move that project into your existing solution rather than trying to “convert” another solution into a module.
From an official support answer:
“Create a new blank application (that includespublic websiteproject) with the same options with your existing application.
Move thepublic websiteproject from the newly created solution to your existing solution.”
(support question: “add public website (and CMS kit) to existing application?”)
Using a separate “B as a module” works, but:
So, for maintainability and upgrade safety: Option 2.
This is technically feasible, but more complex/fragile than Option 2.
High‑level steps if you insist on Option 1:
B.DomainB.Domain.SharedB.ApplicationB.Application.ContractsB.HttpApiB.HttpApi.Host (optional if you want a separate host)B.Web (for the public website UI)AbpModule class, with proper [DependsOn] attributes, e.g.:// B.Domain.Shared
[DependsOn(
typeof(AbpDddDomainSharedModule),
typeof(CmsKitDomainSharedModule) // if you depend on CmsKit
)]
public class BDomainSharedModule : AbpModule
{
}
// B.Domain
[DependsOn(
typeof(AbpDddDomainModule),
typeof(BDomainSharedModule),
typeof(CmsKitDomainModule)
)]
public class BDomainModule : AbpModule
{
}
Database & migrations
B.EntityFrameworkCore with its own migrations & connection string.Wire the module into A
DependsOn the B modules you need, e.g.:[DependsOn(
typeof(BWebModule),
typeof(CmsKitPublicWebModule) // if used
)]
public class AWebModule : AbpModule
{
}
UI integration
app.UseEndpoints, etc., as in a standard ABP Public Website.Multi‑tenancy
ICurrentTenant, tenant resolvers, etc.).Because this essentially recreates what the ABP “Application Module” template already gives you, and you also must keep up with Public Website template changes, this option is usually not worth the maintenance cost unless you are building a generic module to reuse in multiple, unrelated solutions.
# Open-source
abp add-module Volo.CmsKit --skip-db-migrations
# Commercial (Pro)
abp add-module Volo.CmsKit.Pro --skip-db-migrations
YourProjectNameDomainSharedModule (or GlobalFeatureConfigurator):GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit =>
{
cmsKit.EnableAll();
});
GlobalFeatureManager.Instance.Modules.CmsKitPro(cmsKitPro =>
{
cmsKitPro.EnableAll();
});
Run EF Core migrations (A’s DbContext project):
This is the officially documented install path for CMS Kit into an existing solution.
There is no direct “add public website” CLI command to an existing solution. Official guidance:
abp new TempSolution --with-public-website [other-options-matching-A]
In solution C, locate the Public Website project (e.g. TempSolution.Public.Web).
Copy that project into A’s solution:
src directory..sln.Update references:
Domain.Shared, Application.Contracts, HttpApi.Client etc., as in C.Volo.CmsKit.Public.Web / Volo.CmsKit.Pro.Public.Web (they should already be referenced from the template).DbMigrator (if used) knows about the CMS migrations (usually automatic if using the unified DbContext).This step gives you a canonical, up‑to‑date Public Website layer, exactly as ABP expects, now living inside solution A.
From your experimental solution B (created with CMS Kit + Public Website):
Identify what you actually changed in B:
Pages/Public/...), view models, components.Copy over custom UI code:
B.Public.Web:
A.Public.Web:
Pages/Public/...Themes/LeptonX/... overridesCopy/merge application/domain logic (if any) from B into A:
Re‑run and verify migrations if you added new entities for B that need DB tables in A.
Test all flows in A:
This is conceptually the same as “upgrading imported module source code by re‑downloading and merging” that ABP support often suggests for modules: you bring in a fresh template version and then merge your custom changes on top.
With everything in a single solution A, you still want only a subset of tenants to have CMS/public web capability.
Use a combination of:
Feature management / settings per tenant
CmsKit.Enabled) or reuse existing module features.Tenant‑specific DNS + tenant resolvers
Permission control
This is aligned with ABP’s feature system + multi‑tenancy model and avoids duplicating application code per tenant.
Recommended:
Avoid:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
In your Blazor Server UI project (the one that has the theme), add a class like this:
using System;
using System.Linq;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Components.Server.Theming.Bundling; // for BlazorStandardBundles
namespace CardNavigator.Web.Bundling;
public class RemoveVulnerableScriptsContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
// Example: remove ALL bootstrap-daterangepicker scripts
var toRemove = context.Files
.Where(f => f.Contains("bootstrap-daterangepicker", StringComparison.OrdinalIgnoreCase))
.ToList();
foreach (var file in toRemove)
{
context.Files.Remove(file);
}
// You can repeat the same pattern for other libraries:
// - bootstrap-datepicker
// - jquery-form
// - zxcvbn
// etc.
//
// Example:
// var datepicker = context.Files
// .Where(f => f.Contains("bootstrap-datepicker", StringComparison.OrdinalIgnoreCase))
// .ToList();
// foreach (var file in datepicker)
// {
// context.Files.Remove(file);
// }
}
}
Adjust the Contains(...) checks to match the actual paths you see under wwwroot/libs (e.g. /libs/bootstrap-daterangepicker/daterangepicker.js).
In your Blazor Server host module (e.g. CardNavigatorWebModule), inside ConfigureServices:
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Components.Server.Theming.Bundling; // BlazorStandardBundles
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBundlingOptions>(options =>
{
// For Blazor Server global scripts
options.ScriptBundles
.Configure(BlazorStandardBundles.Scripts.Global, bundle =>
{
bundle.AddContributors(typeof(RemoveVulnerableScriptsContributor));
});
// If you also need to remove CSS, do the same with StyleBundles:
// options.StyleBundles.Configure(BlazorStandardBundles.Styles.Global, bundle =>
// {
// bundle.AddContributors(typeof(RemoveVulnerableStylesContributor));
// });
});
}
If your project is using the classic MVC bundles instead (e.g. for an MVC host), use StandardBundles.Scripts.Global instead of BlazorStandardBundles.Scripts.Global.
Rebuild the static assets and test
From the UI project folder:
abp install-libs
This way you are not touching ABP’s NPM packages directly; you are just customizing the final bundles to exclude specific files or entire libraries.
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Yes, this kind of report is common when running SAST/SCA tools (Sonatype, GitHub Advanced Security, etc.) on ABP-based solutions.
The items in your screenshot (e.g. bootstrap-daterangepicker, bootstrap-datepicker, jquery-form, preact, zxcvbn, etc.) are front-end dependencies that come from ABP’s NPM packages (themes, modules, etc.), not from your own package.json directly.
ABP regularly upgrades both NuGet and NPM dependencies, but scanners sometimes:
To make sure you’re using the newest versions that ABP provides:
Update ABP NuGet packages & solution version
From command line in your solution root:
abp update
Or use ABP Studio → Update All ABP Packages.
This brings your solution up to the latest compatible ABP Framework / ABP Commercial version and in turn updates referenced front‑end packages (because each ABP version pins specific NPM versions).
Re-install front-end libraries
In your Blazor Server UI project folder (the one with package.json):
abp install-libs
This:
node_modules (according to the ABP NPM package versions).wwwroot/libs from those packages.If you’ve customized package.json
If you added your own dependencies there, also run:
yarn install
# or
npm install
Then re-run your bundling process (if you use a custom one).
After these steps, you are on the latest JS/CSS stack for your ABP version. Many scanners will stop flagging older vulnerabilities once those versions are updated.
In most cases, those components are encapsulated inside ABP’s own NPM packages (e.g. LeptonX theme, account/auth UI, etc.). That means:
bootstrap-daterangepicker or preact by editing your package.json, because:
You have three realistic options:
Preferred: wait for / request ABP to upgrade them
The ABP team regularly does bulk upgrades of third‑party libraries. If there is a newer safe version of one of those libraries, they generally upgrade it in upcoming releases.
Remove the library if unused
If you are sure you don’t use the functionality that brings a specific library, you can:
/wwwroot/libs and the related bundling contributor in your UI project).This is advanced and you must manually verify nothing breaks.
Full custom front-end
For extreme security requirements, some teams:
This gives full control, but you lose ABP’s ready-made UI integration.
If you:
abp install-libs,then:
Confirm the vulnerability is real and version-specific
Some findings (especially for minified JS) are pattern based and can be false-positives. Check whether the CVE/advisory:
If confirmed, raise it with ABP
Provide the full Sonatype report and CVE references so the ABP team can:
Temporary mitigation / exception
Until ABP publishes a release containing the upgraded dependency, many customers:
Summary of what you should do now
In your solution root:
abp update
abp install-libs
Re-run the Sonatype scan.
For any remaining high-severity items:
This is the supported and safe way to deal with security scan findings in an ABP solution, without breaking the LeptonX theme or ABP modules.
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
This is a known limitation of the Angular proxy generator:
when you have custom classes that subclass PagedResultDto<T> (or other complex generics), the generated models.ts can end up with:
import type { MyEntityDto } from './models';
export interface MyEntityDto {
// ...
}
or similar patterns for generic type parameters (e.g. T, TKey), causing TypeScript errors like:
TS2440: Import declaration conflicts with local declaration of 'MyEntityDto'TS2303 / TS2459 about circular definition or missing exported member T, TKey, etc.The official support answer for the linked ticket confirms:
The
generate-proxycommand may not support all C# types; you need to modify the generated code manually for now.
So this is a limitation/bug of the proxy generator, not your specific project.
You have two practical options. The recommended one is to simplify the C# DTOs so they’re proxy‑friendly.
Avoid exposing custom subclasses of PagedResultDto<T> in your public application contracts.
Instead of:
public class MyEntityDto : EntityDto<Guid>
{
// ...
}
public class MessageCenterCustomPagedResultDto : PagedResultDto<MyEntityDto>
{
}
Change your application service methods to return the base PagedResultDto<T> directly:
public class MyEntityDto : EntityDto<Guid>
{
// ...
}
// AppService method
public virtual async Task<PagedResultDto<MyEntityDto>> GetListAsync(MyInputDto input)
{
// ...
}
If you need extra properties on the “paged result”, make them normal properties on a non‑generic DTO instead of subclassing PagedResultDto<T>:
public class MyEntityPagedResultDto
{
public long TotalCount { get; set; }
public List<MyEntityDto> Items { get; set; }
// Any additional fields you need
public string SomeExtraInfo { get; set; }
}
// AppService method
public virtual async Task<MyEntityPagedResultDto> GetCustomListAsync(MyInputDto input)
{
// Map manually from a PagedResultDto<MyEntityDto> or query result
}
This produces simple DTO shapes that the Angular proxy generator can handle without generating recursive imports or bogus generic imports.
After changing the contracts:
abp generate-proxy -t ng
You should no longer see TS2440 on MyEntityDto (or similar generic / import issues).
If you must keep the C# design as‑is, you can:
abp generate-proxy -t ng.src/app/proxy/models.ts (and any client-models/models.ts in modules, if applicable).// Remove this line:
import type { MyEntityDto } from './models';
The downside: every time you regenerate proxies, these files can be overwritten, so you must either:
PagedResultDto<T>.CompareLookupDto<TKey>, MyEntityCustomPagedResultDto<T>).models.ts, leading to:
import { MyEntityDto } from './models'; while also defining MyEntityDto),import { T } from '../../../models';).Given the current behavior, the most robust, maintenance‑friendly fix is to refactor your application contracts as in Option A so they only use:
PagedResultDto<MyEntityDto> directly, orTotalCount + Items + any extra fields.Support ticket describing this exact behavior and official guidance that generate-proxy does not support all C# types and may require manual fixes:
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
In ABP (including v10) with LeptonX, the favicon is still taken from the root of each application. The theme does not require any extra configuration: placing the files in the right place is enough.
For a Blazor Server + separated AuthServer setup with LeptonX:
Make sure the favicon files are in the correct paths
For each application (AuthServer and Blazor Server UI):
YourApp.AuthServer/wwwroot/favicon.svgYourApp.AuthServer/wwwroot/favicon.icoYourApp.Blazor/wwwroot/favicon.svgYourApp.Blazor/wwwroot/favicon.icoThere should be no sub-folder (like /images/ or /assets/) in the path – LeptonX looks at the root.
Remove any manual <link rel="icon" ...> overrides
If you previously followed older instructions and edited layout/profile pages, restore/remove any custom favicon lines, for example:
<link rel="icon" href="/some/other/path/icon.svg" ... />
or any layout/component that points to a LeptonX favicon.
With LeptonX, you normally do not need to add a <link rel="icon"...> tag at all; the default layout will use /favicon.svg and /favicon.ico from wwwroot.
Ensure the files are published and served as static content
For both AuthServer and Blazor projects:
favicon.svg and favicon.ico in Visual Studio → Properties:
Build Action = ContentCopy to Output Directory = Do not copy or Copy if newer (both are fine as long as they end up under wwwroot at publish time).<publish_root>\wwwroot\favicon.svg<publish_root>\wwwroot\favicon.icoVerify which favicon URL is actually being requested
In the browser (for both AuthServer URL and Blazor UI URL):
favicon./favicon.svg or /favicon.ico and not something like /Themes/LeptonX/.../favicon.svg.If you see the favicon being requested from a different URL, that means some layout/component is still pointing to the LeptonX icon. Remove/override that link, so only /favicon.svg (or /favicon.ico) from wwwroot is used.
Clear cache correctly
Because browsers cache favicons aggressively:
If AuthServer and Blazor show different icons
https://authserver-host/favicon.svg → you should see your SVG.https://blazor-host/favicon.svg → you should see the same SVG.wwwroot/favicon.* is not updated or not deployed correctly. Fix that project and rebuild.If all the above conditions are satisfied (correct paths, no custom <link> overrides, files actually deployed and served) LeptonX in ABP 10 will use your favicon instead of the LeptonX icon.
favicon.svg / favicon.ico under ~/wwwroot in each app):This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Based on the information in the linked tickets and our internal docs:
templates/app/react-native (used as the base for the commercial one).8727) led to another round of updates (Expo version bump, new structure, new docs).So, regarding your concrete questions:
“Is the React Native / Expo template actually supported by the ABP team?”
Yes. It is part of the official ABP offering (and the commercial variant is covered under support). When blocking issues are reported (like the ones you list), they are treated as bugs and get fixed in subsequent releases. The docs are also kept in sync with those template updates:
“Is there a plan to get it working for real-world projects?”
Yes. The intent is that the React Native / Expo template is usable for real projects, not just demos. The fact that:
is evidence that it is not abandoned; it’s just that mobile (especially React Native + Expo) changes much faster than the .NET backend, and the template has repeatedly lagged behind that pace.
About the specific problems you listed (missing files, normalize-css-color, outdated/duplicate packages, TS/JS mix):
These fall into two buckets:
index.ts referencing CreateUpdateTenant, TenantsScreen that don’t exist, normalize-css-color resolution problems).native-base and react-native-paper, TS/JS mixing, unused packages).The right way to get these resolved is:
index.ts line(s), normalize-css-color error stack, etc.).package.json of the generated mobile app.What’s actually going on / why this keeps happening
From the pattern in previous tickets and the current docs:
Those are not intentional and not “by design”; they’re bugs / technical debt that need to be raised (like you are doing) so they can be fixed in the next patch.
Practical recommendations if you must decide for a production project now
Given your clear requirement for production-grade reliability:
If you must use React Native / Expo today for a serious, long-lived project, the safest process with the current template is:
package.json.index.ts references or normalize-css-color) and keep those fixes in your own repo.If you do not want to carry that responsibility (i.e., you want a template that is “green and hands-off” like the Angular or MVC templates), then today the RN/Expo template may not match your expectation yet. In that case, you may:
If you’re open to helping improve the situation, the ABP team already pointed out that contributions to the open-source React Native template are welcome. Those improvements are then ported into the commercial template.
Sources
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
In the app template with SaaS host side, ITenantAppService is in the host contracts package:
Volo.Saas.Host.Application.ContractsSaasHostApplicationContractsModuleVolo.SaasSo you should depend on Volo.Saas.Host.Application.Contracts, not on a non‑existing Volo.Saas.Application.Contracts.
You normally need ITenantAppService only in your Application layer, where you build DTOs and orchestrate calls.
*.Application project.*.Application.Contracts project unless you really need to expose SaaS DTOs in your own public contracts.MyModule.Application.csprojIf you’re using NuGet packages:
<ItemGroup>
<PackageReference Include="Volo.Saas.Host.Application.Contracts" Version="x.y.z" />
</ItemGroup>
(Use the same x.y.z ABP/Commercial version as the rest of your solution.)
Or, if you have a Saas.Host.Application.Contracts project in the solution, just add a project reference instead of NuGet.
In your module’s Application project:
using Volo.Abp.Modularity;
using Volo.Saas.Host; // for SaasHostApplicationContractsModule
[DependsOn(
typeof(SaasHostApplicationContractsModule)
// other dependencies...
)]
public class MyModuleApplicationModule : AbpModule
{
}
Now you can inject ITenantAppService in your app services:
using Volo.Saas;
public class MyEntityAppService : ApplicationService
{
private readonly ITenantAppService _tenantAppService;
public MyEntityAppService(ITenantAppService tenantAppService)
{
_tenantAppService = tenantAppService;
}
public async Task<MyEntityDto> GetAsync(Guid id)
{
var entity = await Repository.GetAsync(id);
var dto = ObjectMapper.Map<MyEntity, MyEntityDto>(entity);
if (entity.TenantId.HasValue)
{
var tenantDto = await _tenantAppService.GetAsync(entity.TenantId.Value);
dto.TenantName = tenantDto.Name;
}
return dto;
}
}
Application.Contracts project?Application.Contracts of your module should define your own DTOs and service interfaces and stay relatively clean.Volo.Saas.Host.Application.Contracts there only if:
If you just need tenant info internally to build DTOs, referencing it only from *.Application is the cleaner approach.
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
ITenantAppService is defined in the SaaS module’s application contracts:
Volo.SaasVolo.Saas.Application.ContractsFrom your own module’s Application layer, you should depend on this contracts package (or project), not on the SaaS implementation.
In your <YourModule>.Application project:
.csproj
<ItemGroup>
<PackageReference Include="Volo.Saas.Application.Contracts" Version="*" />
</ItemGroup>
(Use the same version as the rest of your ABP packages.)
Module class
using Volo.Saas;
[DependsOn(
typeof(SaasApplicationContractsModule) // <- important
)]
public class MyModuleApplicationModule : AbpModule
{
}
Now you can inject ITenantAppService anywhere in this application module:
using Volo.Saas;
public class MyEntityAppService : ApplicationService
{
private readonly ITenantAppService _tenantAppService;
public MyEntityAppService(ITenantAppService tenantAppService)
{
_tenantAppService = tenantAppService;
}
// use _tenantAppService.GetAsync(id) etc.
}
Saas.Application.Contracts projectIn that case, instead of NuGet, add a project reference from your module’s *.Application project to the Saas.Application.Contracts project, and still annotate your module with:
[DependsOn(typeof(SaasApplicationContractsModule))]
public class MyModuleApplicationModule : AbpModule
{
}
Everything else is the same; you can inject ITenantAppService normally.
TenantId value).ITenantAppService here is a standard and recommended pattern.This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.