Inside Docker, NuGet SSL problems usually come from the container not trusting the same certificates as your host (corporate proxy, dev HTTPS certs, man‑in‑the‑middle scanners, etc.). Below are concrete ways to fix this when building/running ABP apps in Docker.
dotnet restore (NuGet feed SSL)Check the exact error message
Most common messages are like:
The SSL connection could not be establishedUnable to load the service index for source 'https://....'Authentication failed because the remote party has closed the transport streamIf you are behind a corporate proxy with its own CA
You must import the proxy’s root certificate into the Docker image so dotnet/NuGet trusts it.
Typical Dockerfile pattern (Linux Debian/Ubuntu base images):
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy your corporate/proxy root certificate to the image
COPY mycorp-root-ca.crt /usr/local/share/ca-certificates/mycorp-root-ca.crt
# Register certificate in container trust store
RUN update-ca-certificates
# Now restore & build
COPY *.sln ./
COPY src/ ./src/
RUN dotnet restore
RUN dotnet build -c Release -o /app/build
Notes:
mycorp-root-ca.crt (Base‑64).update-ca-certificates, the dotnet CLI and NuGet will use the updated trust store.If using a private NuGet feed with self‑signed certificate
Temporarily test by disabling HTTPS verification (not recommended for production)
Only to confirm it’s an SSL trust issue, you can temporarily point to an HTTP feed (if available) or use another public feed (like nuget.org) in NuGet.config and see if restore succeeds. If yes, then the problem is definitely certificate/trust.
When developing ABP apps with Docker (especially microservice template), you often use local HTTPS endpoints. For development, ABP docs recommend using mkcert to create locally trusted certificates:
Install mkcert on your host
Follow mkcert’s guide:
mkcert -installmkcert localhost
localhost.pem and localhost-key.pem (or .crt/.key).Use mkcert for your development certificates in Docker
Typical pattern:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
# Copy mkcert-generated certificate into container
COPY certs/localhost.pem /https/aspnetapp.crt
COPY certs/localhost-key.pem /https/aspnetapp.key
# Configure Kestrel via environment in docker-compose.yml:
# ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.crt
# ASPNETCORE_Kestrel__Certificates__Default__KeyPath=/https/aspnetapp.key
This way both your browser and the container trust the same dev certificate.
nuget.abp.io (ABP Commercial feeds) via HTTPSabp login <your-email>
dotnet nuget list source
Ensure the ABP feed is HTTPS and works locally.
Propagate any custom CA/proxy trust to Docker
If your environment injects certificates (proxy, SSL inspection), you must import that CA as shown in section A.
Avoid turning off SSL validation
Don’t use DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=false or similar workarounds in production – fix trust instead.
curl https://api.nuget.org/v3/index.json inside the container?
mkcert for dev ABP microservices?
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.
The runtime error:
MissingMethodException: Method not found:
'Void Volo.Abp.Localization.LanguageInfo..ctor(System.String, System.String, System.String, System.String)'
is caused by a version mismatch between your ABP Framework packages and the LeptonX theme package.
In ABP 8.3 the LanguageInfo type (from Volo.Abp.Localization) exposes only the 3‑parameter constructor.
LeptonX 3.1 was compiled against an earlier ABP version where the 4‑parameter constructor still existed. At runtime, the CLR tries to call that old 4‑parameter constructor and fails with MissingMethodException.
Fix
.csproj and update the LeptonX package:<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX" Version="3.3.*" />
(or explicitly, e.g. 3.3.0/3.3.1, matching your ABP 8.3 minor version).
dotnet list package
If you see mixed versions, update them so every Volo.Abp.* package is 8.3.x and LeptonX is 3.3.x.
abp clean
dotnet restore
dotnet build
dotnet run
After upgrading LeptonX to 3.3.x, it will be compiled against the correct LanguageInfo constructor (3 parameters), and the MissingMethodException will be gone.
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 EasyCRM Angular app the text shown in the browser tab is the HTML <title> tag of the Angular app, not an ABP setting.
Change it in angular/src/index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- CHANGE THIS LINE -->
<title>My New CRM Title</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
yarn start or npm start).If you later want localized, per‑page titles, you can additionally use a custom TitleStrategy (as shown in the second source below), but for simply replacing “MyProjectName” the index.html <title> tag is the place to 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.
That almost always means:
v10 moved everything fully to OpenIddict and tightened validation. You must realign:
Below is a concrete, minimal set of checks/fixes that resolves this in practice.
In API‑1:
public class LoggingHttpClientAuthenticator : IRemoteServiceHttpClientAuthenticator, ISingletonDependency
{
private readonly IRemotingTokenStore _tokenStore;
private readonly ILogger<LoggingHttpClientAuthenticator> _logger;
public LoggingHttpClientAuthenticator(
IRemotingTokenStore tokenStore,
ILogger<LoggingHttpClientAuthenticator> logger)
{
_tokenStore = tokenStore;
_logger = logger;
}
public async Task Authenticate(RemoteServiceHttpClientAuthenticateContext context)
{
context.Request.Headers.Authorization = null;
var token = await _tokenStore.GetTokenAsync(CancellationToken.None);
_logger.LogInformation("Outgoing inter-service access token: {Token}", token);
if (!string.IsNullOrEmpty(token))
{
context.Request.Headers.Add("Authorization", $"Bearer {token}");
}
}
}
Authorization: Bearer <copied-token>If you still get 403, then the problem is not ABP remote services, but access token configuration / scopes / audiences between AuthServer, API‑1 client, and APIs 2 & 3.
In your AuthServer (Identity service), open your OpenIddictDataSeedContributor (or equivalent) and check the application (client) that represents API‑1.
It must have:
client_type = confidentialclient_credentialsRoughly like the official template:
// scopes
await CreateScopesAsync(context, new[]
{
"Api2",
"Api3",
OpenIddictConstants.Scopes.Email,
OpenIddictConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles
});
// client for API-1
await CreateApplicationAsync(
name: "Api1_Internal_Client",
type: OpenIddictConstants.ClientTypes.Confidential,
consentType: OpenIddictConstants.ConsentTypes.Systematic,
displayName: "Api1 internal client",
secret: "VERY-SECRET",
grantTypes: new[]
{
OpenIddictConstants.GrantTypes.ClientCredentials
},
scopes: new[]
{
"Api2",
"Api3"
});
Make sure the scope names you put here match what APIs 2 & 3 are configured to accept (next section).
If the client was migrated from IdentityServer4 config, the allowed scopes/resources often need to be re‑created in this OpenIddict seeding.
In each resource API (2 and 3) you normally have something like this in the module’s ConfigureServices:
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = configuration["AuthServer:Authority"]; // e.g. https://auth.mycompany.com
options.RequireHttpsMetadata = true;
options.Audience = "Api2"; // or "Api3" for the 3rd API
});
// ...
}
Or, if you use OpenIddict validation:
PreConfigure<OpenIddictValidationBuilder>(builder =>
{
builder.AddAudiences("Api2"); // or "Api3"
builder.UseLocalServer();
builder.UseAspNetCore();
});
Now match that:
Audience / AddAudiences("Api2") must equal the scope name you granted to API‑1’s client (previous step).Api2 Api3 but API‑2 is configured with Audience = "MyApi2" or something else, the token will be considered not for this API, and authorization will fail.So:
"Api2" and "Api3".OpenIddictDataSeedContributor (scope + client’s allowed scopes).Audience or AddAudiences).Your IRemotingTokenStore (or equivalent) in API‑1 must request the same scopes:
public class RemotingClientOptions
{
public string ClientName { get; set; }
public string ClientSecret { get; set; }
public string Scope { get; set; } // e.g. "Api2 Api3"
}
appsettings.json in API‑1:
"AuthServer": {
"Authority": "https://<your-auth-server>"
},
"Remoting": {
"Client": {
"ClientName": "Api1_Internal_Client",
"ClientSecret": "VERY-SECRET",
"Scope": "Api2 Api3"
}
}
Token store (simplified):
var tokenResponse = await client.RequestClientCredentialsTokenAsync(
new ClientCredentialsTokenRequest
{
Address = discovery.TokenEndpoint,
ClientId = clientId,
ClientSecret = clientSecret,
Scope = scope // "Api2 Api3"
},
cancellationToken);
If in v9 you used older IdentityServer4 client‑credentials with different scope names, after migrating to OpenIddict those old names will not work. You must request scopes that actually exist in OpenIddict.
Once the token and scopes are fixed, your existing ABP remote service setup is usually fine:
// appsettings.json of API-1
"RemoteServices": {
"Api2": {
"BaseUrl": "https://api2.yourdomain"
},
"Api3": {
"BaseUrl": "https://api3.yourdomain"
}
}
// in API-1 module
context.Services.AddHttpClientProxies(
typeof(Api2ApplicationContractsModule).Assembly,
remoteServiceConfigurationName: "Api2"
);
context.Services.AddHttpClientProxies(
typeof(Api3ApplicationContractsModule).Assembly,
remoteServiceConfigurationName: "Api3"
);
Together with an IRemoteServiceHttpClientAuthenticator that attaches the bearer token, those parts typically don’t change between v9 and v10.
Summary of what to actually change
In AuthServer
Api2, Api3).client_credentials and allowed scopes Api2, Api3.In APIs 2 & 3
Api2 / Api3 (same as scopes above).In API‑1
Scope = "Api2 Api3".IRemoteServiceHttpClientAuthenticator to attach that token.Debug once
IRemotingTokenStore, IRemoteServiceHttpClientAuthenticator, scopes, and audiences):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.
A 403 from API‑2 / API‑3 means:
So the problem is not “remote service call configuration”, but application‑to‑application authorization after the v9→v10 upgrade (where identity/auth stack has changed).
On each modular layered API (2 & 3):
Check the authorize attributes
[Authorize("SomePolicy")]
// or
[Authorize(MyPermissions.Foo.Bar)]
ensure that the **principal represented by the token coming from API‑1** is actually allowed for that policy / permission.
If you use permissions, ensure the calling client has them
When you use ABP’s permission system on APIs:
ClientPermissionValueProvider).In a microservice/zero‑trust setup this is typically done via a central identity/permission service; see the “Zero Trust Microservice Architecture with ABP Framework” article for a complete pattern:
// Example central permission check service
public interface IPermissionCheckerAppService : IApplicationService
{
Task<bool> CheckPermissionAsync(CheckPermissionInput input);
Task<MultiplePermissionGrantResultDto> CheckPermissionsAsync(CheckPermissionsInput input);
}
Check that the token subject is what you expect
ICurrentUser.IsAuthenticated or user‑based permissions), they will deny requests coming from a pure client token.On the single‑layer API‑1, which calls 2 & 3 via remote service / HTTP client:
Confirm how the token is added to outgoing calls
You should have something equivalent to an IRemoteServiceHttpClientAuthenticator that sets the Authorization: Bearer <token> header for all dynamic client proxy calls, e.g.:
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IRemoteServiceHttpClientAuthenticator))]
public class SampleServiceHttpClientAuthenticator :
IRemoteServiceHttpClientAuthenticator, ISingletonDependency
{
private readonly IRemotingTokenStore _tokenStore;
public async Task Authenticate(RemoteServiceHttpClientAuthenticateContext context)
{
context.Request.Headers.Authorization = null;
var token = await _tokenStore.GetTokenAsync(CancellationToken.None);
if (!string.IsNullOrEmpty(token))
{
context.Request.Headers.Add("Authorization", $"Bearer {token}");
}
}
}
If after the upgrade this authenticator is not registered or not executed, API‑2/3 will receive a request without a valid token and return 401/403.
Check client credentials used by API‑1
If API‑1 uses client credentials to obtain a token (as in the “Zero Trust Microservice Architecture” sample):
appsettings.json) that:
AuthServer:Authority points to the correct identity server.Remoting:Client:ClientName, ClientSecret, and Scope (or equivalent) match a client that exists and is allowed to call API‑2/3.Ensure RemoteServices base URLs are correct
In API‑1, for each remote service:
"RemoteServices": {
"Service2": {
"BaseUrl": "https://<api2-host>"
},
"Service3": {
"BaseUrl": "https://<api3-host>"
}
}
and in your module:
context.Services.AddHttpClientProxies(
typeof(Service2ApplicationContractsModule).Assembly,
remoteServiceConfigurationName: "Service2"
);
context.Services.AddHttpClientProxies(
typeof(Service3ApplicationContractsModule).Assembly,
remoteServiceConfigurationName: "Service3"
);
Misconfigured remote service name or base URL won’t usually produce 403, but verify them while you’re here.
Based on similar ABP microservice setups (including the referenced zero‑trust sample):
Create/verify a client in your identity server representing API‑1, with:
Grant required permissions to that client (if you use centralized permission management and client permission provider).
Configure API‑1 to use those client credentials when requesting tokens and to attach the token on all remote calls (via an IRemoteServiceHttpClientAuthenticator).
Align [Authorize] usage on API‑2 / API‑3 so that:
Test directly with the same token
The Zero Trust Microservice Architecture with ABP Framework article shows a complete, working pattern of:
IRemotingTokenStore + custom IRemoteServiceHttpClientAuthenticator for inter‑service calls.You can align your solution with that pattern to make your inter‑service calls and permissions robust.
After upgrading to ABP 10, you must:
[Authorize] attributes and permission assignments accordingly.Once client credentials, scopes/permissions, and the HTTP client authenticator are correctly configured, the 403s from your modular APIs will stop.
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.
jQuery.fn.jquery showing 4.0.0 on the deployed dev environment means somewhere in your built bundles another jQuery (4.x) is being loaded after ABP’s @abp/jquery (3.7.1).
LeptonX + ABP 9.0.2 is built and tested with jQuery 3.7.1, and jQuery 4 is not supported – that’s why you get n.parseJSON is not a function only on dev.
To fix it, you must ensure that only jQuery 3.7.1 is used in the public web/auth server application that serves the login page.
Do the following steps:
Add a resolutions block to your package.json to force all packages to use jQuery 3.7.1:
{
"name": "my-app",
"version": "1.0.0",
"private": true,
"dependencies": {
"@abp/tui-editor": "^9.0.2",
"@volo/abp.aspnetcore.mvc.ui.theme.leptonx": "~4.0.3",
"@volo/account": "~9.0.2",
"@volo/audit-logging": "~9.0.2",
"@volo/identity": "~9.0.2",
"@volo/language-management": "~9.0.2",
"@volo/saas": "~9.0.2",
"apexcharts": "^4.0.0",
"flatpickr": "^4.6.13",
"vue": "^3.4.31",
"jquery-ui": "^1.14.1",
"pivottable": "^2.23.0"
},
"resolutions": {
"jquery": "3.7.1",
"**/jquery": "3.7.1"
}
}
Then, re‑install using Yarn (so that CI and local both use the same versions):
# On local
rm -rf node_modules
yarn install
yarn build # or the command that builds your bundles
Commit both package.json and yarn.lock, push, and make sure your CI pipeline runs yarn install (not npm install) so that it respects yarn.lock and resolutions.
If your CI has a package-lock.json from earlier runs, delete it from the repo and ensure the CI configuration is not using npm ci against it.
Since you’re using tiered with a separate MVC/Auth Server (LeptonX theme), verify these files in the web/auth project:
_Layout.cshtml (or AccountLayout.cshtml depending on customization)Make sure there is no additional <script> tag that includes jQuery from a CDN or from wwwroot/lib/jquery etc.
All you should see is the ABP/LeptonX bundle, for example:
@section scripts {
@await RenderSectionAsync("Scripts", required: false)
@await BundleManager.RenderScriptsAsync()
}
If you have something like:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
or any local jquery-4.*.js, remove it.
The only jQuery instance must come from @abp/jquery (3.7.1) via the ABP bundles.
After updating CI to use Yarn + the new resolutions and removing any extra jQuery <script> tags:
jQuery.fn.jquery
It should now print:
"3.7.1"
Uncaught TypeError: n.parseJSON is not a function should be gone.If it still shows 4.0.0, check the Network tab → filter by “jquery” to see from which file/url jQuery 4 is being loaded; remove that reference or force it to use 3.7.1.
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.
The error is a pure SQL Server execution timeout:
Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
The command that times out is the standard ABP Identity user‑creation batch:
UPDATE [AbpRoles] ...
INSERT INTO [AbpUserRoles] ...
UPDATE [AbpUsers] ...
So EF/ABP are working as expected; SQL Server is taking >30 seconds to complete this batch in production (but not in dev). That means:
AbpRoles, AbpUsers, or AbpUserRoles rows are blocked/locked by some other transaction, orYou can resolve and mitigate this with the following steps.
Run these queries directly on the production database:
-- See who is blocking whom
SELECT
r.session_id,
r.status,
r.command,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.wait_resource,
t.text AS sql_text
FROM sys.dm_exec_requests r
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.session_id > 50; -- Ignore system sessions
Look for:
blocking_session_id <> 0wait_timewait_type like LCK_M_* (lock waits) on AbpRoles, AbpUsers, or AbpUserRoles.SELECT
s.session_id,
s.login_name,
s.host_name,
r.status,
r.command,
r.blocking_session_id,
t.transaction_id,
t.transaction_type,
t.transaction_state,
at.name as transaction_name
FROM sys.dm_tran_active_transactions t
JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id
LEFT JOIN sys.dm_tran_active_snapshot_database_transactions at
ON t.transaction_id = at.transaction_id;
If you see:
Abp* tables, kill them (carefully) or stop the service that opened them.From the ABP DbMigrator (or equivalent migration service for Identity):
AbpUsers, AbpRoles, AbpUserRoles schemas match dev.A partially run migration can leave locks or long operations.
For an immediate workaround (to stop production user‑creation failures while you investigate), increase the EF Core command timeout for the IdentityService DbContext.
In your IdentityService EF Core configuration module (e.g. IdentityServiceEntityFrameworkCoreModule or the module where you configure AbpDbContextOptions), add:
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(options =>
{
options.Configure<IdentityServiceDbContext>(c =>
{
c.UseSqlServer(
c.ExistingConnection ??
c.ConnectionString,
sqlOptions =>
{
// Increase command timeout (seconds)
sqlOptions.CommandTimeout(120);
});
});
});
}
Notes:
IdentityServiceDbContext is the DbContext from your Identity microservice (CloverleafCMS.IdentityService.Data.IdentityServiceDbContext in your stack trace).If you have any custom logic that:
make sure those operations:
ABP Unit of Work best practices:
AbpUsers/AbpRoles in a single UoW.AbpUsers, AbpRoles, AbpUserRoles that could be slow or deadlocking.If you do the SQL blocking checks while reproducing the problem (trigger a user creation and immediately inspect sys.dm_exec_requests / sys.dm_tran_locks), you will see exactly which session / query is blocking the AbpRoles / AbpUsers updates. Removing or fixing that blocker is the real solution; the increased timeout just buys time to keep production functional.
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.
Need specific about Angular *abpPermission roles undefined and 403 on permissionGuard only in Azure. Might be related to AbpPermissionDirective attribute vs structural, or requiredPolicy mismatch, or missing permission definition. Also question 2816 already about directive error but different. Need maybe search_code @abp/ng.core AbpPermissionDirective.
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.
AutoMapperMappingExceptionObjectMapper is still using AutoMapper as the IAutoObjectMappingProvider.ObjectMapper.Map<TSource, TDestination>() fail with:AutoMapper.AutoMapperMappingException
Message=Missing type map configuration or unsupported mapping.
ObjectMapper abstraction entirely.To fix this, you must explicitly configure ABP to use Mapperly as the default object mapper.
Follow these concrete steps (for ABP 10.0.2):
In all projects where you had AutoMapper integration:
csproj references
<PackageReference Include="Volo.Abp.AutoMapper" Version="..." />
with:
<PackageReference Include="Volo.Abp.Mapperly" Version="..." />
Module dependencies and usings
In each module (e.g. YourProjectDomainModule, YourProjectApplicationModule, YourProjectBlazorModule, YourProjectHttpApiHostModule, etc.):
using Volo.Abp.AutoMapper;
[DependsOn(
typeof(AbpAutoMapperModule),
// ...
)]
public class YourProjectXXXModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<YourProjectXXXModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<YourProjectXXXModule>(validate: true);
});
}
}
with:
using Volo.Abp.Mapperly;
[DependsOn(
typeof(AbpMapperlyModule),
// ...
)]
public class YourProjectXXXModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Register Mapperly object mapper for this module
context.Services.AddMapperlyObjectMapper<YourProjectXXXModule>();
}
}
Notes:
Configure<AbpAutoMapperOptions>(...) blocks.AbpAutoMapperModule from all [DependsOn] attributes.AbpMapperlyModule (plus your other existing module dependencies).ObjectMapper.MapIn at least one root module that is loaded in every app (e.g. your main host / UI / application module), explicitly register the non-generic AddMapperlyObjectMapper so ABP’s default IObjectMapper uses Mapperly:
using Volo.Abp.Mapperly;
[DependsOn(typeof(AbpMapperlyModule))]
public class YourProjectHttpApiHostModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Make Mapperly the default IAutoObjectMappingProvider used by ObjectMapper.Map<,>()
context.Services.AddMapperlyObjectMapper();
}
}
This is the key step that makes:
ObjectMapper.Map<TSource, TDestination>(source);
go through Mapperly, not AutoMapper.
(From the migration guide: “If your application uses Mapperly: context.Services.AddMapperlyObjectMapper();”)
Mapperly mappers should look like:
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
[Mapper] // RequiredMappingStrategy = Target is default in ABP integration
public partial class MyEntityToMyDtoMapper : MapperBase<MyEntity, MyDto>
{
public override partial MyDto Map(MyEntity source);
public override partial void Map(MyEntity source, MyDto destination);
}
ABP’s Mapperly integration automatically:
[Mapper] classes in DI.ObjectMapper based on <TSource, TDestination>.You don’t need to manually wire each mapper to ObjectMapper.
IObjectMapper<TContext>)If somewhere you use a contextual mapper (or ObjectMapperContext), keep the generic registration:
context.Services.AddMapperlyObjectMapper<MyProjectApplicationModule>();
and in the consumer (e.g., ApplicationService, Blazor page):
public class MyAppService : ApplicationService
{
public MyAppService()
{
ObjectMapperContext = typeof(MyProjectApplicationModule);
}
public Task<MyDto> GetAsync()
{
// This now uses Mapperly, via the module-specific object mapper
return Task.FromResult(ObjectMapper.Map<MyEntity, MyDto>(entity));
}
}
This pattern is the same as with AutoMapper, just using Mapperly registration.
Migration guide – “Migrating from AutoMapper to Mapperly”
(sections Migration Steps and Set Default Mapping Provider – AddMapperlyObjectMapper)
https://abp.io/docs/10.0/release-info/migration-guides/AutoMapper-To-Mapperly
Object-to-object mapping – Mapperly integration & registration (AbpMapperlyModule, AddMapperlyObjectMapper, MapperBase, TwoWayMapperBase)
https://abp.io/docs/latest/framework/infrastructure/object-to-object-mapping
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.
So in an Angular + .NET solution, installing CMS Kit:
The supported, upgrade‑friendly setup is:
Concretely:
You already did this, but for completeness:
abp add-module Volo.CmsKit / .Pro).Domain.Shared (or GlobalFeatureConfigurator).This gives:
There is no CLI command that injects a Web.Public project into an existing Angular-only solution.
The recommended and supported way is:
Generate a temporary solution C with:
For example:
abp new TempSolution -u mvc --with-public-website [other-options-matching-A]
In solution C:
TempSolution.Web) – this contains the CMS management UI you see in your screenshot.TempSolution.Public.Web).Copy these projects into solution A:
src folder..sln.TempSolution.Web to YourProduct.Web, etc.).Wire references:
Domain.Shared, Application.Contracts, HttpApi, HttpApi.Client, etc., instead of TempSolution’s.Run & test:
From your Angular app, you can:
/cms-admin in a new tab or same tab).app.yourtenant.com → Angular SPA (your main product)portal.yourtenant.com → CMS Public Websiteadmin.yourtenant.com or /cms → Razor admin (with CMS menu)All share the same multi‑tenant backend and database.
- After installing CMS Kit in Project A, backend ok, but no CMS UI/menu in Angular?
Correct and expected:
To give tenants a CMS management UI today, you must use a Razor-based admin UI (or build your own Angular UI against CMS APIs).
- Is there an official command or recommended approach to add Public Website to an existing Angular + .NET solution?
This is exactly the same pattern ABP recommends when adding Public Website to an existing solution of any UI type.
To satisfy: one main solution, Angular product UI, CMS for some tenants, maintainable over upgrades:
Upgrade path:
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.