From ee67e1bd7a3a65b6f65a81bba978db51aa3a1e00 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 21 Jul 2026 10:35:33 +0800 Subject: [PATCH] Improve accuracy of framework and module documentation --- .../domain-driven-design/repositories.md | 2 +- .../framework/architecture/modularity/basics.md | 9 ++++++++- .../fundamentals/application-startup.md | 2 +- docs/en/framework/fundamentals/validation.md | 2 +- .../background-workers/hangfire.md | 2 +- docs/en/framework/infrastructure/json.md | 2 +- docs/en/framework/ui/angular/commercial-ui.md | 4 ++-- .../ui/angular/lookup-search-component.md | 1 + docs/en/framework/ui/angular/oauth-module.md | 2 +- docs/en/framework/ui/angular/tree-component.md | 17 ++++------------- .../ui/mvc-razor-pages/javascript-api/clock.md | 2 +- docs/en/modules/ai-management/index.md | 2 +- docs/en/modules/cms-kit/blogging.md | 2 +- docs/en/modules/cms-kit/comments.md | 2 +- docs/en/modules/identity-server.md | 2 +- docs/en/modules/openiddict-pro.md | 4 +++- docs/en/modules/payment-custom-gateway.md | 4 ++-- docs/en/modules/saas.md | 2 +- docs/en/multi-lingual-entities.md | 2 +- 19 files changed, 33 insertions(+), 32 deletions(-) diff --git a/docs/en/framework/architecture/domain-driven-design/repositories.md b/docs/en/framework/architecture/domain-driven-design/repositories.md index f9b1c7d4dd..ea74f0976a 100644 --- a/docs/en/framework/architecture/domain-driven-design/repositories.md +++ b/docs/en/framework/architecture/domain-driven-design/repositories.md @@ -311,7 +311,7 @@ Methods: - `GetQueryableAsync()` - `WithDetailsAsync()` 1 overload -The synchronous `WithDetails()` overload is obsolete. Use `WithDetailsAsync()` for new code. +The synchronous `WithDetails()` overloads are obsolete. Use `WithDetailsAsync()` for new code. Whereas the `IReadOnlyBasicRepository` provides the following methods: diff --git a/docs/en/framework/architecture/modularity/basics.md b/docs/en/framework/architecture/modularity/basics.md index 560d794f96..c6ee6f567c 100644 --- a/docs/en/framework/architecture/modularity/basics.md +++ b/docs/en/framework/architecture/modularity/basics.md @@ -149,7 +149,7 @@ You can also perform startup logic if your module requires it `IModuleLifecycleContributor` is an advanced extension point for adding an application-wide initialization or shutdown phase. A contributor is invoked for every loaded module. Initialization follows module dependency order, while shutdown processes modules in reverse order. -Derive from `ModuleLifecycleContributorBase` and override only the phases you need: +Derive from `ModuleLifecycleContributorBase` and override only the phases you need. Each phase has a synchronous and an asynchronous method; the application calls one of them depending on whether it is initialized synchronously or asynchronously, so override both to cover the two startup paths: ````csharp public class MyModuleLifecycleContributor : ModuleLifecycleContributorBase @@ -161,6 +161,13 @@ public class MyModuleLifecycleContributor : ModuleLifecycleContributorBase // Run initialization logic for the current module. return Task.CompletedTask; } + + public override void Initialize( + ApplicationInitializationContext context, + IAbpModule module) + { + AsyncHelper.RunSync(() => InitializeAsync(context, module)); + } } ```` diff --git a/docs/en/framework/fundamentals/application-startup.md b/docs/en/framework/fundamentals/application-startup.md index acfe4bf2aa..39a849b7bc 100644 --- a/docs/en/framework/fundamentals/application-startup.md +++ b/docs/en/framework/fundamentals/application-startup.md @@ -215,7 +215,7 @@ We've passed a lambda method to configure the `ApplicationName` option. Here's a * `Configuration`: Can be used to setup the [application configuration](./configuration.md) when it is not provided by the hosting system. It is not needed for ASP.NET Core and other .NET hosted applications. However, if you've used `AbpApplicationFactory` with an internal service provider, you can use this option to configure how the application configuration is built. * `FileName` (default: `appsettings`), `Optional` (default: `true`) and `ReloadOnChange` (default: `true`) configure the JSON files. * The builder loads `.json` first and then the optional `.secrets.json` file. When `EnvironmentName` is set, it loads `..json` after both files. - * `EnvironmentName` adds the corresponding environment-specific JSON file. In the `Development` environment, `UserSecretsId` is used before `UserSecretsAssembly` when both are set. + * `EnvironmentName` adds the corresponding environment-specific JSON file. In the `Development` environment, user secrets are added from `UserSecretsId` when it is set; otherwise from `UserSecretsAssembly`. * `BasePath` changes the configuration file base path. The current directory is used by default. * `EnvironmentVariablesPrefix` filters environment variables, and `CommandLineArgs` adds command-line configuration after environment variables. * `Environment`: Environment name for the application. diff --git a/docs/en/framework/fundamentals/validation.md b/docs/en/framework/fundamentals/validation.md index 4d9d8a4d45..2a05e60ad0 100644 --- a/docs/en/framework/fundamentals/validation.md +++ b/docs/en/framework/fundamentals/validation.md @@ -196,7 +196,7 @@ public class MyObjectValidationContributor ### Ignoring Types During Recursive Validation -`AbpValidationOptions.IgnoredTypes` prevents matching values from being recursively validated by the default data annotation contributor. Derived and implementing types are also matched. +`AbpValidationOptions.IgnoredTypes` prevents the default data annotation contributor from descending into the properties of matching values during recursive validation. The data annotations on the matching value itself are still validated. Derived and implementing types are also matched. ````csharp Configure(options => diff --git a/docs/en/framework/infrastructure/background-workers/hangfire.md b/docs/en/framework/infrastructure/background-workers/hangfire.md index 887266e95c..43ddaceb19 100644 --- a/docs/en/framework/infrastructure/background-workers/hangfire.md +++ b/docs/en/framework/infrastructure/background-workers/hangfire.md @@ -47,7 +47,7 @@ public class YourModule : AbpModule > Hangfire background worker integration provides an adapter `HangfirePeriodicBackgroundWorkerAdapter` to automatically load any `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived classes as `IHangfireBackgroundWorker` instances. This allows you to still to easily switch over to use Hangfire as the background manager even you have existing background workers that are based on the [default background workers implementation](../background-workers). -The adapter uses UTC for recurring schedules by default and uses the default Hangfire queue when no queue is specified. You can configure both values globally for adapted periodic workers: +The adapter uses UTC for recurring schedules by default and uses the default Hangfire queue when no queue is specified (a specified queue name is prefixed with `AbpHangfireOptions.DefaultQueuePrefix`, which is empty by default). You can configure both values globally for adapted periodic workers: ````csharp Configure(options => diff --git a/docs/en/framework/infrastructure/json.md b/docs/en/framework/infrastructure/json.md index 28aa279439..54281e40b8 100644 --- a/docs/en/framework/infrastructure/json.md +++ b/docs/en/framework/infrastructure/json.md @@ -47,7 +47,7 @@ public class ProductManager ## IObjectSerializer -`IObjectSerializer` serializes objects to and from `byte[]`. The default implementation uses UTF-8 JSON bytes from `System.Text.Json`: +`IObjectSerializer` (defined in the `Volo.Abp.Serialization` package, independently of the JSON system) serializes objects to and from `byte[]`. The default implementation uses UTF-8 JSON bytes from `System.Text.Json`: ```csharp public interface IObjectSerializer diff --git a/docs/en/framework/ui/angular/commercial-ui.md b/docs/en/framework/ui/angular/commercial-ui.md index e696dec165..c2f24aed34 100644 --- a/docs/en/framework/ui/angular/commercial-ui.md +++ b/docs/en/framework/ui/angular/commercial-ui.md @@ -46,11 +46,11 @@ export class ReportRangeComponent { [(ngModel)]="dateRange" startDateProp="startDate" endDateProp="endDate" - labelText="Reports::DateRange" + labelText="Date Range" /> ``` -Use `abp-datetime-range-picker` with the same inputs when the model also needs start and end times. +Use `abp-datetime-range-picker` with the same inputs when the model also needs start and end times. `labelText` is rendered as-is, so pass an already localized string (for example, a value resolved with the `LocalizationService`) instead of a localization key. ## Standalone Configuration diff --git a/docs/en/framework/ui/angular/lookup-search-component.md b/docs/en/framework/ui/angular/lookup-search-component.md index a60b713510..144f24c1e1 100644 --- a/docs/en/framework/ui/angular/lookup-search-component.md +++ b/docs/en/framework/ui/angular/lookup-search-component.md @@ -25,6 +25,7 @@ import { LookupSearchFn, } from '@abp/ng.components/lookup'; import { map } from 'rxjs'; +import { BookService } from '../services/book.service'; interface BookLookupItem extends LookupItem { authorName: string; diff --git a/docs/en/framework/ui/angular/oauth-module.md b/docs/en/framework/ui/angular/oauth-module.md index 6209f77bb8..b8730806e4 100644 --- a/docs/en/framework/ui/angular/oauth-module.md +++ b/docs/en/framework/ui/angular/oauth-module.md @@ -57,6 +57,6 @@ It also registers the OAuth configuration initializer and the providers from `an ## API Interceptor -For non-external requests, the OAuth API interceptor adds an `Authorization` bearer token, `Accept-Language`, the configured tenant header and `X-Requested-With` when the corresponding values are available. Existing authorization, language and tenant headers are preserved. Requests marked with the `IS_EXTERNAL_REQUEST` HTTP context token are sent without those ABP headers. The interceptor also integrates every request with the HTTP wait service. +For non-external requests, the OAuth API interceptor adds the `X-Requested-With` header and, when the corresponding values are available, an `Authorization` bearer token, `Accept-Language` and the configured tenant header. Existing authorization, language and tenant headers are preserved. Requests marked with the `IS_EXTERNAL_REQUEST` HTTP context token are sent without those ABP headers. The interceptor also integrates every request with the HTTP wait service. To implement another authentication system, provide replacements for the core services and tokens used by the application instead of depending on the OAuth implementations. diff --git a/docs/en/framework/ui/angular/tree-component.md b/docs/en/framework/ui/angular/tree-component.md index bf66cfee12..2a7b446baa 100644 --- a/docs/en/framework/ui/angular/tree-component.md +++ b/docs/en/framework/ui/angular/tree-component.md @@ -19,12 +19,7 @@ Import it into a standalone component and provide nodes in the format expected b ```ts import { Component, signal } from '@angular/core'; -import { - DropEvent, - ExpandedIconTemplateDirective, - TreeComponent, - TreeNodeTemplateDirective, -} from '@abp/ng.components/tree'; +import { DropEvent, TreeComponent } from '@abp/ng.components/tree'; import { of } from 'rxjs'; interface Category { @@ -35,11 +30,7 @@ interface Category { @Component({ selector: 'app-category-tree', templateUrl: './category-tree.component.html', - imports: [ - TreeComponent, - TreeNodeTemplateDirective, - ExpandedIconTemplateDirective, - ], + imports: [TreeComponent], }) export class CategoryTreeComponent { readonly nodes = signal([ @@ -96,7 +87,7 @@ The main inputs are: State changes are exposed through `checkedKeysChange`, `expandedKeysChange`, `selectedNodeChange`, `dropOver` and `nzExpandChange`. -The default `beforeDrop` handler rejects drops. Supply a handler that returns an observable accepted by the underlying tree control when drag-and-drop is enabled. +The default `beforeDrop` handler rejects drops. Supply a handler that returns an observable accepted by the underlying tree control when drag-and-drop is enabled. Note that the default handler is also what records the drop position, so when you replace it, the `pos` property of the `DropEvent` emitted by `dropOver` is not set. ## Templates @@ -116,7 +107,7 @@ Use the `#menu` template, as in the previous example, to add a context menu for ``` }%} -The component example imports `TreeNodeTemplateDirective` and `ExpandedIconTemplateDirective` because Angular must see each directive used by a standalone component template. If you use only one of these templates, import only its corresponding directive. +Import `TreeNodeTemplateDirective` and `ExpandedIconTemplateDirective` from `@abp/ng.components/tree` into the standalone component that uses these templates, because Angular must see each directive used by a component template. If you use only one of these templates, import only its corresponding directive. ## Flat-List Adapter diff --git a/docs/en/framework/ui/mvc-razor-pages/javascript-api/clock.md b/docs/en/framework/ui/mvc-razor-pages/javascript-api/clock.md index 436e6b54af..520f650087 100644 --- a/docs/en/framework/ui/mvc-razor-pages/javascript-api/clock.md +++ b/docs/en/framework/ui/mvc-razor-pages/javascript-api/clock.md @@ -32,7 +32,7 @@ const displayValue = abp.clock.normalizeToLocaleString(requestValue); The standard shared MVC theme bundle loads Luxon and replaces the core implementations of `normalizeToString` and `normalizeToLocaleString`. When multiple time zones are supported, this Luxon implementation interprets the input in the configured IANA time zone, converts it to UTC and returns an ISO value ending in `Z`. The output can include milliseconds (for example, `2026-07-17T08:30:00.000Z`), so do not require an exact string length when consuming it. -If an application uses the core scripts without the shared theme's Luxon contributor, the fallback implementation produces a `Z`-suffixed transport value by detecting a numeric browser offset. It is not a full IANA time-zone conversion and does not account for fractional-hour offsets or an offset change between the current date and the input date. Include the Luxon contributor when those cases must be handled. +If an application uses the core scripts without the shared theme's Luxon contributor, the fallback implementation produces a `Z`-suffixed transport value by detecting the numeric offset of the configured time zone (the `abp.clock.timeZone()` value, which falls back to the browser time zone). It is not a full IANA time-zone conversion and does not account for fractional-hour offsets or an offset change between the current date and the input date. Include the Luxon contributor when those cases must be handled. `normalizeToLocaleString` accepts standard `Intl.DateTimeFormat` options. When no options are supplied, it uses `abp.clock.toLocaleStringOptions`. The default options include the numeric year, long month, numeric day, hour, minute and second. You can replace them to define application-wide display defaults: diff --git a/docs/en/modules/ai-management/index.md b/docs/en/modules/ai-management/index.md index 5b01227437..f9e15a7c9a 100644 --- a/docs/en/modules/ai-management/index.md +++ b/docs/en/modules/ai-management/index.md @@ -485,7 +485,7 @@ Configure(options => | `MaxConcurrentIndexingJobs` | `1` | Maximum indexing batches running concurrently across the application | | `DistributedLockTimeoutSeconds` | `0` | Time to wait for an indexing lock; `0` performs an immediate attempt | -Increase concurrency only after checking the embedding provider's rate limits and vector-store capacity. The concurrency limiter is application-wide; the per-data-source lock still prevents two batches from mutating the same data source concurrently. +Increase concurrency only after checking the embedding provider's rate limits and vector-store capacity. The concurrency limiter and the per-data-source lock both use the [distributed lock](../../framework/infrastructure/distributed-locking.md), so they apply across all application instances when a distributed lock provider is configured (with the default in-process implementation, they only cover a single process). The per-data-source lock prevents two batches from mutating the same data source concurrently. ### Configuring Data Source Upload Options diff --git a/docs/en/modules/cms-kit/blogging.md b/docs/en/modules/cms-kit/blogging.md index 1c0ee4713e..d5f6b9b460 100644 --- a/docs/en/modules/cms-kit/blogging.md +++ b/docs/en/modules/cms-kit/blogging.md @@ -51,7 +51,7 @@ A screenshot from the new blog creation modal: #### Blog Features -The blogging feature uses other CMS Kit features. A newly created blog enables comments, reactions, ratings, tags, marked items, the quick navigation bar and XSS prevention by default when the related global features are available. You can enable or disable these features for each blog by clicking the features action. +The blogging feature uses other CMS Kit features. A newly created blog enables comments, reactions, ratings, tags, marked items, the quick navigation bar and XSS prevention by default; where a corresponding global feature exists, it still controls whether the blog feature takes effect. You can enable or disable these features for each blog by clicking the features action. ![blogs-feature-action](../../images/cmskit-module-blogs-feature-action.png) diff --git a/docs/en/modules/cms-kit/comments.md b/docs/en/modules/cms-kit/comments.md index c3a595a7d8..3dade384a6 100644 --- a/docs/en/modules/cms-kit/comments.md +++ b/docs/en/modules/cms-kit/comments.md @@ -45,7 +45,7 @@ Configure(options => - `EntityTypes`: List of defined entity types (`CommentEntityTypeDefinition`) in the comment system. - `IsRecaptchaEnabled`: This flag enables or disables the reCaptcha for the comment system. You can set it as **true** if you want to use reCaptcha in your comment system. -- `AllowedExternalUrls`: Registers the URL values used by the external-link validation for each entity type. +- `AllowedExternalUrls`: The allowed external URLs for each entity type. When it is specified for an entity type, every external URL detected in a comment text is checked against the configured values, and the comment is rejected when a URL doesn't match any of them. `CommentEntityTypeDefinition` properties: diff --git a/docs/en/modules/identity-server.md b/docs/en/modules/identity-server.md index f79f135056..295af79b83 100644 --- a/docs/en/modules/identity-server.md +++ b/docs/en/modules/identity-server.md @@ -265,4 +265,4 @@ The optional `Volo.Abp.PermissionManagement.Domain.IdentityServer` integration l ## Entity Extensions -The module's [module entity extension](../framework/architecture/modularity/extending/module-entity-extensions.md) API supports the `Client`, `ApiResource` and `IdentityResource` aggregate roots. Configure these extensions before application startup, and create an EF Core migration when an extra property is mapped to a database column. +The module's [module entity extension](../framework/architecture/modularity/extending/module-entity-extensions.md) API supports the `Client`, `ApiResource` and `IdentityResource` aggregate roots. The configuration API also exposes a method for `ApiScope`, but the module does not apply that configuration to the entity. Configure these extensions before application startup, and create an EF Core migration when an extra property is mapped to a database column. diff --git a/docs/en/modules/openiddict-pro.md b/docs/en/modules/openiddict-pro.md index fb4eb0b73d..9854807f36 100644 --- a/docs/en/modules/openiddict-pro.md +++ b/docs/en/modules/openiddict-pro.md @@ -99,7 +99,7 @@ The **Token Lifetime** action configures per-application overrides for: - Request token - Issued token -Enter positive values in seconds. Leave a field empty to remove the application override and use the server default. These values change only the selected application; configure server-wide defaults in the [OpenIddict module](./openiddict.md). +Enter token lifetimes in seconds. Leave a field empty to remove the application override and use the server default. These values change only the selected application; configure server-wide defaults in the [OpenIddict module](./openiddict.md). #### Generate an Access Token @@ -137,6 +137,8 @@ Use a client credentials application when a machine-to-machine client, automatio 7. Select the API scopes the client is allowed to request. 8. Save the application. +The screenshot below shows the authorization settings of an existing application (the layout varies by UI): + ![Client Credentials application](../images/openiddict-client-credentials-application.png) If the protected API also uses ABP permissions, open the application's **Actions** menu, select **Permissions**, and grant permissions for the **Client (OpenIddict Applications)** provider. Scope assignment controls OAuth access; ABP permission assignment controls the operations that the client principal can perform. diff --git a/docs/en/modules/payment-custom-gateway.md b/docs/en/modules/payment-custom-gateway.md index 42af40467d..5c83c911e0 100644 --- a/docs/en/modules/payment-custom-gateway.md +++ b/docs/en/modules/payment-custom-gateway.md @@ -9,7 +9,7 @@ > You must have an [ABP Team or a higher license](https://abp.io/pricing) to use this module. -This document explains how to create a custom payment gateway that is different from the built-in gateways in the [Payment Module](payment#packages). +This document explains how to create a custom payment gateway that is different from the built-in gateways in the [Payment Module](payment.md#packages). ## Creating Core Operations @@ -147,7 +147,7 @@ This document explains how to create a custom payment gateway that is different } ``` - `IsValid` controls whether the gateway is offered for a specific payment request. `StartAsync` passes the request currency to the provider adapter together with the amount. `CompleteAsync` verifies the provider response and reconciles the request identifier, amount, currency, and provider transaction identifier before changing the request state. `HandleWebhookAsync` must validate the webhook signature or equivalent authenticity proof before processing its payload. + The Payment module does not call `IsValid` when offering or selecting gateways; the gateways offered to the user are determined by the `PaymentOptions.Gateways` and `PaymentWebOptions.Gateways` registrations (see [PaymentOptions](payment.md#paymentoptions)). Some built-in gateways call their own `IsValid` inside `CompleteAsync` to verify the provider response, and a custom gateway can do the same. `StartAsync` passes the request currency to the provider adapter together with the amount. `CompleteAsync` verifies the provider response and reconciles the request identifier, amount, currency, and provider transaction identifier before changing the request state. `HandleWebhookAsync` must validate the webhook signature or equivalent authenticity proof before processing its payload. `IMyGatewayTransactionRepository` is application-owned; it isn't part of the Payment module. Implement `TryBindAsync` as an atomic insert-or-match operation. For this one-time gateway, add unique database constraints for both the provider transaction identifier and the payment request identifier, accept an existing row only when the same pair is retried, and execute the binding and payment-request update in the same unit of work. This persists the provider transaction identifier while rejecting cross-request replay and a different transaction for an already-bound request. diff --git a/docs/en/modules/saas.md b/docs/en/modules/saas.md index c0afe5055a..eb527dc37b 100644 --- a/docs/en/modules/saas.md +++ b/docs/en/modules/saas.md @@ -177,7 +177,7 @@ You can create a new edition or edit an existing edition in this page: ![saas-module-edition-edit-modal](../images/saas-module-edition-edit-modal.png) -The application service validates edition display names for uniqueness. Before deleting an edition, you can move all of its tenants to another edition. Deleting an edition without choosing a replacement clears the edition assignment for its tenants. +`EditionManager` validates edition display names for uniqueness. Before deleting an edition, you can move all of its tenants to another edition. Deleting an edition without choosing a replacement clears the edition assignment for its tenants. ##### Edition Features diff --git a/docs/en/multi-lingual-entities.md b/docs/en/multi-lingual-entities.md index 3802c39018..f3c8602269 100644 --- a/docs/en/multi-lingual-entities.md +++ b/docs/en/multi-lingual-entities.md @@ -80,7 +80,7 @@ With the default arguments, the manager uses `CultureInfo.CurrentUICulture.Name` 3. A translation for the language configured by `LocalizationSettingNames.DefaultLanguage`. 4. The first available translation. -The method returns `null` when the collection is null or empty. To disable only the parent-culture fallback, pass `culture` and set `fallbackToParentCultures` to `false`. The default-language and first-available fallbacks still apply. +The method returns `null` when the collection is null or empty. To disable only the parent-culture fallback, set `fallbackToParentCultures` to `false`. The default-language and first-available fallbacks still apply. ## Select Translations in Bulk