Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
eca1e7e
Improve framework documentation coverage
maliming Jul 17, 2026
59c84dd
Improve Audit Logging documentation coverage
maliming Jul 17, 2026
724f086
Correct Background Jobs module documentation
maliming Jul 19, 2026
0c4985a
Document database BLOB storage provider
maliming Jul 19, 2026
db94b14
Expand Feature Management documentation
maliming Jul 19, 2026
2fd8424
Expand Permission Management documentation
maliming Jul 19, 2026
925512e
Expand Setting Management documentation
maliming Jul 19, 2026
950d868
Expand Tenant Management documentation
maliming Jul 19, 2026
3831ab1
Document user lookup and synchronization
maliming Jul 19, 2026
744612b
Expand Identity and Account module documentation
maliming Jul 19, 2026
981cc7d
Expand OpenIddict module documentation
maliming Jul 19, 2026
6b111b7
Update IdentityServer module documentation
maliming Jul 19, 2026
e5836f6
Add standalone Blogging module documentation
maliming Jul 19, 2026
dc9cf07
Modernize Docs module documentation
maliming Jul 19, 2026
ed30879
Expand CMS Kit module documentation
maliming Jul 19, 2026
ceccd77
Expand Elsa module documentation
maliming Jul 19, 2026
8e55955
Document Operation Rate Limiting module
maliming Jul 19, 2026
a2593a7
Expand Chat module documentation
maliming Jul 19, 2026
4c3d6a4
Expand File Management module documentation
maliming Jul 19, 2026
b33d065
Expand Forms module documentation
maliming Jul 19, 2026
30686e7
Expand GDPR module documentation
maliming Jul 19, 2026
64e4286
Expand Language Management module documentation
maliming Jul 19, 2026
9ea4bda
Rewrite OpenIddict Pro module documentation
maliming Jul 19, 2026
fe1cea4
Expand Text Template Management documentation
maliming Jul 19, 2026
4221423
Expand Identity Pro and Account Pro documentation
maliming Jul 19, 2026
f60da00
Expand AI Management module documentation
maliming Jul 19, 2026
9ed7c0e
Expand SaaS module documentation
maliming Jul 19, 2026
b911c13
Expand Payment module documentation
maliming Jul 19, 2026
021d672
Update Blogging and Identity module navigation
maliming Jul 19, 2026
850b75e
Expand CMS Kit Pro documentation
maliming Jul 19, 2026
69bc8a2
Document SaaS payment request edition timing
maliming Jul 20, 2026
37a56c7
Polish Payment and module installation documentation
maliming Jul 20, 2026
ee67e1b
Improve accuracy of framework and module documentation
maliming Jul 21, 2026
d87e927
Optimised images with calibre/image-actions
github-actions[bot] Jul 21, 2026
4d2e597
Fix code samples and behavior descriptions in documentation
maliming Jul 21, 2026
44216a7
Refine documentation wording for normalizer, validation and comment c…
maliming Jul 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions docs/en/docs-nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@
"text": "Localization",
"path": "framework/fundamentals/localization.md"
},
{
"text": "Multi-Lingual Objects",
"path": "multi-lingual-entities.md"
},
{
"text": "Logging",
"path": "framework/fundamentals/logging.md"
Expand Down Expand Up @@ -1111,6 +1115,10 @@
"text": "Dynamic C# API Clients",
"path": "framework/api-development/dynamic-csharp-clients.md"
},
{
"text": "IdentityModel Clients",
"path": "framework/api-development/identitymodel-clients.md"
},
{
"text": "Integration Services",
"path": "framework/api-development/integration-services.md"
Expand Down Expand Up @@ -1354,6 +1362,10 @@
"text": "Auth",
"path": "framework/ui/mvc-razor-pages/javascript-api/auth.md"
},
{
"text": "Clock",
"path": "framework/ui/mvc-razor-pages/javascript-api/clock.md"
},
{
"text": "Current User",
"path": "framework/ui/mvc-razor-pages/javascript-api/current-user.md"
Expand Down Expand Up @@ -1657,6 +1669,10 @@
"text": "Localization",
"path": "framework/ui/angular/localization.md"
},
{
"text": "Document Title Strategy",
"path": "framework/ui/angular/title-strategy.md"
},
{
"text": "Hybrid Localization",
"path": "framework/ui/angular/hybrid-localization.md"
Expand Down Expand Up @@ -1876,6 +1892,14 @@
"text": "Card",
"path": "framework/ui/angular/card-component.md"
},
{
"text": "Tree",
"path": "framework/ui/angular/tree-component.md"
},
{
"text": "Lookup Search",
"path": "framework/ui/angular/lookup-search-component.md"
},
{
"text": "Dynamic Forms",
"path": "framework/ui/angular/dynamic-form-module.md"
Expand All @@ -1884,6 +1908,10 @@
"text": "Password Complexity Indicator",
"path": "framework/ui/angular/password-complexity-indicator-component.md"
},
{
"text": "Commercial UI Components (Pro)",
"path": "framework/ui/angular/commercial-ui.md"
},
{
"text": "Lookup Components(Pro)",
"path": "framework/ui/angular/lookup-components.md"
Expand Down Expand Up @@ -2080,6 +2108,10 @@
"text": "MongoDB",
"path": "framework/data/mongodb"
},
{
"text": "In-Memory Database",
"path": "framework/data/memorydb"
},
{
"text": "Dapper",
"path": "framework/data/dapper"
Expand Down Expand Up @@ -2615,6 +2647,10 @@
"text": "Background Jobs",
"path": "modules/background-jobs.md"
},
{
"text": "Blogging",
"path": "modules/blogging.md"
},
{
"text": "Chat (Pro)",
"path": "modules/chat.md"
Expand Down Expand Up @@ -2691,7 +2727,7 @@
},
{
"text": "URL Forwarding System",
"path": "modules/cms-kit-pro/URL-forwarding.md"
"path": "modules/cms-kit-pro/url-forwarding.md"
},
{
"text": "Poll System",
Expand Down Expand Up @@ -2733,7 +2769,19 @@
},
{
"text": "Identity",
"path": "modules/identity.md"
"isLazyExpandable": true,
"path": "modules/identity.md",
"items": [
{
"text": "Overview",
"path": "modules/identity.md",
"isIndex": true
},
{
"text": "User Lookup and Synchronization",
"path": "modules/identity/user-synchronization.md"
}
]
},
{
"text": "Identity (Pro)",
Expand Down
12 changes: 11 additions & 1 deletion docs/en/framework/api-development/auto-controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ Then the route for getting a book will be '**/api/volosoft/book-store/book/{id}*
* Normalization can be customized by setting the `UrlActionNameNormalizer` option. It's an action delegate that is called for every method.
* If there is another parameter with 'Id' postfix, then it's also added to the route as the final route segment (like '/phoneId').

When the `UrlControllerNameNormalizer` option is not set, the final controller name also removes suffixes configured in `AbpConventionalControllerOptions.IgnoredUrlSuffixesInControllerNames` (a custom normalizer replaces this ignored-suffix step, so the ignored suffixes are not applied). The default list contains `Integration`, so `PaymentIntegrationService` uses `payment` as its controller route name. You can replace the list when another suffix convention is required:

```csharp
Configure<AbpConventionalControllerOptions>(options =>
{
options.IgnoredUrlSuffixesInControllerNames =
["Integration", "Endpoint"];
});
```

#### Customizing the Route Calculation

`IConventionalRouteBuilder` is used to build the route. It is implemented by the `ConventionalRouteBuilder` by default and works as explained above. You can replace/override this service to customize the route calculation strategy.
Expand Down Expand Up @@ -223,4 +233,4 @@ services.Configure<AbpAspNetCoreMvcOptions>(options =>
````
## See Also

* [Video tutorial](https://abp.io/video-courses/essentials/auto-api-controllers)
* [Video tutorial](https://abp.io/video-courses/essentials/auto-api-controllers)
40 changes: 40 additions & 0 deletions docs/en/framework/api-development/dynamic-csharp-clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,46 @@ Using `asDefaultServices: false` may only be needed if your application has alre

> If you disable `asDefaultServices`, you can only use `IHttpClientProxy<T>` interface to use the client proxies. See the *IHttpClientProxy Interface* section above.

### Before Sending a Proxy Request

`AbpHttpClientOptions.AddPreSendAction` registers an action for a named remote service. It receives the proxy configuration, the current request context and the `HttpClient`, and runs immediately before each proxy request is sent.

````csharp
Configure<AbpHttpClientOptions>(options =>
{
options.AddPreSendAction(
"BookStore",
(_, requestContext, httpClient) =>
{
if (requestContext.Action.Name == "GetReportAsync")
{
httpClient.Timeout = TimeSpan.FromMinutes(2);
}
}
);
});
````

### Custom Parameter Converters

Dynamic proxies normally use the built-in conversion rules for query-string, form-data and path values. Implement `IObjectToQueryString<T>`, `IObjectToFormData<T>` or `IObjectToPath<T>` when a type requires custom serialization, register the implementation in dependency injection, and map the value type to the converter:

````csharp
context.Services.AddTransient<MyFilterToQueryString>();
context.Services.AddTransient<MyUploadMetadataToFormData>();
context.Services.AddTransient<MyStrongIdToPath>();

Configure<AbpHttpClientProxyingOptions>(options =>
{
options.QueryStringConverts[typeof(MyFilter)] =
typeof(MyFilterToQueryString);
options.FormDataConverts[typeof(MyUploadMetadata)] =
typeof(MyUploadMetadataToFormData);
options.PathConverts[typeof(MyStrongId)] =
typeof(MyStrongIdToPath);
});
````

### Retry/Failure Logic & Polly Integration

If you want to add retry logic for the failing remote HTTP calls for the client proxies, you can configure the `AbpHttpClientBuilderOptions` in the `PreConfigureServices` method of your module class.
Expand Down
101 changes: 101 additions & 0 deletions docs/en/framework/api-development/identitymodel-clients.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
```json
//[doc-seo]
{
"Description": "Configure ABP IdentityModel clients for server-to-server access tokens, tenant-aware client selection, and request customization."
}
```

# IdentityModel Clients

The `Volo.Abp.IdentityModel` package obtains access tokens for server-to-server HTTP calls. `AbpIdentityModelModule` binds the `IdentityClients` configuration section to `AbpIdentityClientOptions`.

## Installation

Install the `Volo.Abp.IdentityModel` NuGet package in the project that obtains the tokens:

````shell
abp add-package Volo.Abp.IdentityModel
````

The command adds the package and the `AbpIdentityModelModule` dependency to the module class.

## Configure Identity Clients

Define a `Default` client and any named clients in the application configuration:

````json
{
"IdentityClients": {
"Default": {
"GrantType": "client_credentials",
"ClientId": "MyProject_Backend",
"ClientSecret": "your-client-secret",
"Authority": "https://localhost:44301/",
"Scope": "MyProject"
},
"Reporting": {
"GrantType": "client_credentials",
"ClientId": "MyProject_Reporting",
"ClientSecret": "your-reporting-client-secret",
"Authority": "https://localhost:44301/",
"Scope": "Reporting"
}
}
}
````

When a client name is requested for the current tenant, ABP selects the first available configuration in this order:

1. `<client-name>.<tenant-id>`
2. `<client-name>.<tenant-name>`
3. `<client-name>`
4. `Default`

If no client name is supplied, ABP uses `Default` as the client name. Tenant-specific entries let a tenant use different credentials without changing the consuming service. For example, `Reporting.8e6fcd0a-75ab-4d94-90f4-9a2503d0e70c` overrides the `Reporting` client for that tenant ID.

Pass the client name to `TryAuthenticateAsync` when you authenticate an `HttpClient` directly:

````csharp
var client = _httpClientFactory.CreateClient();

if (!await _authenticationService.TryAuthenticateAsync(client, "Reporting"))
{
throw new InvalidOperationException(
"The Reporting identity client is not configured."
);
}

var response = await client.GetAsync("https://reporting.example.com/api/reports");
````

Install `Volo.Abp.Http.Client.IdentityModel` when dynamic HTTP client proxies should obtain tokens automatically. Its `AbpHttpClientIdentityModelModule` integration uses the remote service's `IdentityClient` value when configured, then the remote service name, and finally the `Default` identity client fallback described above:

````json
{
"RemoteServices": {
"Reporting": {
"BaseUrl": "https://reporting.example.com/",
"IdentityClient": "Reporting"
}
}
}
````

## Customize Discovery and Token Requests

Use `IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage` to add headers or otherwise customize the request messages:

````csharp
Configure<IdentityModelHttpRequestMessageOptions>(options =>
{
options.ConfigureHttpRequestMessage = request =>
{
request.Headers.TryAddWithoutValidation(
"X-Internal-Client",
"MyProject"
);
};
});
````

The callback runs for discovery, client-credentials, password and device-authorization request messages created by the default authentication service.
15 changes: 15 additions & 0 deletions docs/en/framework/api-development/swagger.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ services.AddAbpSwaggerGen(
)
```

### Enum and Schema ID Helpers

ABP provides two additional `SwaggerGenOptions` helpers:

* `UserFriendlyEnums()` changes enum schemas from numeric values to string enum names, making generated contracts easier for clients to consume.
* `CustomAbpSchemaIds()` uses full type names and includes generic argument names to avoid schema ID collisions.

```csharp
services.AddAbpSwaggerGen(options =>
{
options.UserFriendlyEnums();
options.CustomAbpSchemaIds();
});
```

## Using Swagger with OAUTH

For non MVC/Tiered applications, we need to configure Swagger with OAUTH to handle authorization.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public virtual async Task<List<PersonDto>> GetListAsync()

ABP uses dynamic proxying to make these attributes work. There are some rules here:

* If you are **not injecting** the service over an interface (like `IPersonAppService`), then the methods of the service must be `virtual`. Otherwise, [dynamic proxy / interception](../../../dynamic-proxying-interceptors.md) system can not work.
* If you are **not injecting** the service over an interface (like `IPersonAppService`), then the methods of the service must be `virtual`. Otherwise, [dynamic proxy / interception](../../infrastructure/interceptors.md) system can not work.
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted.

> Change tracking behavior doesn't affect tracking entity objects returned from `InsertAsync` and `UpdateAsync` methods. The objects returned from these methods are always tracked (if the underlying provider has the change tracking feature) and any change you make to these objects are saved into the database.
Expand Down Expand Up @@ -309,9 +309,10 @@ Methods:

- `GetListAsync()`
- `GetQueryableAsync()`
- `WithDetails()` 1 overload
- `WithDetailsAsync()` 1 overload

The synchronous `WithDetails()` overloads are obsolete. Use `WithDetailsAsync()` for new code.

Whereas the `IReadOnlyBasicRepository<Tentity, TKey>` provides the following methods:

- `GetCountAsync()`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Configure<AbpUnitOfWorkDefaultOptions>(options =>
### Option Properties

* `TransactionBehavior` (`enum`: `UnitOfWorkTransactionBehavior`). A global point to configure the transaction behavior. Default value is `Auto` and work as explained in the "*Database Transaction Behavior*" section above. You can enable (even for HTTP GET requests) or disable transactions with this option.
* `TimeOut` (`int?`): Used to set the timeout value for UOWs. **Default value is `null`** and uses to the default of the underlying database provider.
* `Timeout` (`int?`): Used to set the timeout value for UOWs. **Default value is `null`** and uses to the default of the underlying database provider.
* `IsolationLevel` (`IsolationLevel?`): Used to set the [isolation level](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel) of the database transaction, if the UOW is transactional.

## Controlling the Unit Of Work
Expand Down Expand Up @@ -93,7 +93,7 @@ Then `MyService` (and any class derived from it) methods will be UOW.

However, there are **some rules should be followed** in order to make it working;

* If you are **not injecting** the service over an interface (like `IMyService`), then the methods of the service must be `virtual` (otherwise, [dynamic proxy / interception](../../../dynamic-proxying-interceptors.md) system can not work).
* If you are **not injecting** the service over an interface (like `IMyService`), then the methods of the service must be `virtual` (otherwise, [dynamic proxy / interception](../../infrastructure/interceptors.md) system can not work).
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted. So, sync methods can not start a UOW.

> Notice that if `FooAsync` is called inside a UOW scope, then it already participates to the UOW without needing to the `IUnitOfWorkEnabled` or any other configuration.
Expand Down Expand Up @@ -156,13 +156,13 @@ namespace AbpDemo

Again, the **same rules** are valid here:

* If you are **not injecting** the service over an interface (like `IMyService`), then the methods of the service must be `virtual` (otherwise, [dynamic proxy / interception](../../../dynamic-proxying-interceptors.md) system can not work).
* If you are **not injecting** the service over an interface (like `IMyService`), then the methods of the service must be `virtual` (otherwise, [dynamic proxy / interception](../../infrastructure/interceptors.md) system can not work).
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted. So, sync methods can not start a UOW.

#### UnitOfWorkAttribute Properties

* `IsTransactional` (`bool?`): Used to set whether the UOW should be transactional or not. **Default value is `null`**. if you leave it `null`, it is determined automatically based on the conventions and the configuration.
* `TimeOut` (`int?`): Used to set the timeout value for this UOW. **Default value is `null`** and fallbacks to the default configured value.
* `Timeout` (`int?`): Used to set the timeout value for this UOW. **Default value is `null`** and fallbacks to the default configured value.
* `IsolationLevel` (`IsolationLevel?`): Used to set the [isolation level](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel) of the database transaction, if the UOW is transactional. If not set, uses the default configured value.
* `IsDisabled` (`bool`): Used to disable the UOW for the current method/class.

Expand Down Expand Up @@ -234,7 +234,7 @@ namespace AbpDemo
* `requiresNew` (`bool`): Set `true` to ignore the surrounding unit of work and start a new UOW with the provided options. **Default value is `false`. If it is `false` and there is a surrounding UOW, `Begin` method doesn't actually begin a new UOW, but silently participates to the existing UOW.**
* `isTransactional` (`bool`). Default value is `false`.
* `isolationLevel` (`IsolationLevel?`): Used to set the [isolation level](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel) of the database transaction, if the UOW is transactional. If not set, uses the default configured value.
* `TimeOut` (`int?`): Used to set the timeout value for this UOW. **Default value is `null`** and fallbacks to the default configured value.
* `timeout` (`int?`): Used to set the timeout value for this UOW. **Default value is `null`** and fallbacks to the default configured value.

### The Current Unit Of Work

Expand Down
Loading
Loading