diff --git a/Directory.Packages.props b/Directory.Packages.props
index 64143a8501..1e5898dbc4 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -11,18 +11,19 @@
-
+
+
-
-
-
-
+
+
+
+
@@ -53,7 +54,7 @@
-
+
@@ -88,9 +89,8 @@
-
-
-
+
+
@@ -132,11 +132,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -174,6 +174,7 @@
+
@@ -193,6 +194,6 @@
-
+
-
+
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
index 7cccf12cde..622f30420c 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
@@ -262,11 +262,14 @@
"LicenseBanner:CallToAction": "Please extend your license.",
"Referral.CreatorUserIdIsRequired": "Creator user ID is required.",
"Referral.TargetEmailIsRequired": "Target email is required.",
- "Referral.TargetEmailAlreadyExists": "A referral link for this email address already exists.",
+ "Referral.YouAlreadyHaveLinkForThisEmail": "You have already created a referral link for this email address.",
"Referral.MaxLinkLimitExceeded": "You have reached the maximum limit of {Limit} active referral links.",
"Referral.LinkNotFound": "Referral link not found.",
"Referral.LinkNotFoundOrNotOwned": "Referral link not found or you don't have permission to access it.",
"Referral.CannotDeleteUsedLink": "You cannot delete a referral link that has already been used.",
+ "Referral.CannotReferYourself": "You cannot create a referral link for your own email address.",
+ "Referral:TargetEmail": "Target Email",
+ "Referral.CannotReferSameOrganizationMember": "You cannot create a referral link for a user who is already a member of your organization.",
"LinkCopiedToClipboard": "Link copied to clipboard",
"AreYouSureToDeleteReferralLink": "Are you sure you want to delete this referral link?",
"DefaultErrorMessage": "An error occurred."
diff --git a/common.props b/common.props
index 82d1e8abbf..42e230791c 100644
--- a/common.props
+++ b/common.props
@@ -18,11 +18,6 @@
-
-
-
-
- all
diff --git a/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/coverimage.png b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/coverimage.png
new file mode 100644
index 0000000000..b4f2222acd
Binary files /dev/null and b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/coverimage.png differ
diff --git a/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/images/auth-flow.svg b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/images/auth-flow.svg
new file mode 100644
index 0000000000..0ae07fec22
--- /dev/null
+++ b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/images/auth-flow.svg
@@ -0,0 +1,70 @@
+
diff --git a/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/post.md b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/post.md
new file mode 100644
index 0000000000..87dc698b1d
--- /dev/null
+++ b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/post.md
@@ -0,0 +1,354 @@
+# Building an API Key Management System with ABP Framework
+
+API keys are one of the most common authentication methods for APIs, especially for machine-to-machine communication. In this article, I'll explain what API key authentication is, when to use it, and how to implement a complete API key management system using ABP Framework.
+
+## What is API Key Authentication?
+
+An API key is a unique identifier used to authenticate requests to an API. Unlike user credentials (username/password) or OAuth tokens, API keys are designed for:
+
+- **Programmatic access** - Scripts, CLI tools, and automated processes
+- **Service-to-service communication** - Microservices authenticating with each other
+- **Third-party integrations** - External systems accessing your API
+- **IoT devices** - Embedded systems with limited authentication capabilities
+- **Mobile/Desktop apps** - Native applications that need persistent authentication
+
+## Why Use API Keys?
+
+While modern authentication methods like OAuth2 and JWT are excellent for user authentication, API keys offer distinct advantages in certain scenarios:
+
+**Simplicity**: No complex OAuth flows or token refresh mechanisms. Just include the key in your request header.
+
+**Long-lived**: Unlike JWT tokens that expire in minutes/hours, API keys can remain valid for months or years, making them ideal for automated systems.
+
+**Revocable**: You can instantly revoke a compromised key without affecting user credentials.
+
+**Granular Control**: Different keys for different purposes (read-only, admin, specific services).
+
+## Real-World Use Cases
+
+Here are some practical scenarios where API key authentication shines:
+
+### 1. Mobile Applications
+Your mobile app needs to call your backend APIs. Instead of storing user credentials or managing token refresh flows, use an API key.
+
+```csharp
+// Mobile app configuration
+var apiClient = new ApiClient("https://api.yourapp.com");
+apiClient.SetApiKey("sk_mobile_prod_abc123...");
+```
+
+### 2. Microservice Communication
+Service A needs to call Service B's protected endpoints.
+
+```csharp
+// Order Service calling Inventory Service
+var request = new HttpRequestMessage(HttpMethod.Get, "https://inventory-service/api/products");
+request.Headers.Add("X-Api-Key", _configuration["InventoryService:ApiKey"]);
+```
+
+### 3. Third-Party Integrations
+You're providing APIs to external partners or customers.
+
+```bash
+# Customer's integration script
+curl -H "X-Api-Key: pk_partner_xyz789..." \
+ https://api.yourplatform.com/api/orders
+```
+
+## Implementing API Key Management in ABP Framework
+
+Now let's see how to build a complete API key management system using ABP Framework. I've created an open-source implementation that you can use in your projects.
+
+### Project Overview
+
+The implementation consists of:
+
+- **User-based API keys** - Each key belongs to a specific user
+- **Permission delegation** - Keys inherit user permissions with optional restrictions
+- **Secure storage** - Keys are hashed with SHA-256
+- **Prefix-based lookup** - Fast key resolution with caching
+- **Web UI** - Manage keys through a user-friendly interface
+- **Multi-tenancy support** - Full ABP multi-tenancy compatibility
+
+
+
+### Architecture Overview
+
+The solution follows ABP's modular architecture with four main layers:
+
+```
+┌─────────────────────────────────────────────┐
+│ Web Layer (UI) │
+│ • Razor Pages for CRUD operations │
+│ • JavaScript for client interactions │
+└─────────────────────────────────────────────┘
+ ↓
+┌─────────────────────────────────────────────┐
+│ AspNetCore Layer (Middleware) │
+│ • Authentication Handler │
+│ • API Key Resolver (Header/Query) │
+└─────────────────────────────────────────────┘
+ ↓
+┌─────────────────────────────────────────────┐
+│ Application Layer (Business Logic) │
+│ • ApiKeyAppService (CRUD operations) │
+│ • DTO mappings and validations │
+└─────────────────────────────────────────────┘
+ ↓
+┌─────────────────────────────────────────────┐
+│ Domain Layer (Core Business) │
+│ • ApiKey Entity & Manager │
+│ • IApiKeyRepository │
+│ • Domain services & events │
+└─────────────────────────────────────────────┘
+```
+
+### Key Components
+
+#### 1. Domain Layer - The Core Entity
+
+```csharp
+public class ApiKey : FullAuditedAggregateRoot, IMultiTenant
+{
+ public virtual Guid? TenantId { get; protected set; }
+ public virtual Guid UserId { get; protected set; }
+ public virtual string Name { get; protected set; }
+ public virtual string Prefix { get; protected set; }
+ public virtual string KeyHash { get; protected set; }
+ public virtual DateTime? ExpiresAt { get; protected set; }
+ public virtual bool IsActive { get; protected set; }
+
+ // Key format: {prefix}_{key}
+ // Only the hash is stored, never the actual key
+}
+```
+
+**Key Design Decisions:**
+
+- **Prefix-based lookup**: Keys have format `prefix_actualkey`. The prefix is indexed for fast database lookups.
+- **SHA-256 hashing**: The actual key is hashed and never stored in plain text.
+- **User association**: Each key belongs to a user, inheriting their permissions.
+- **Soft delete**: Deleted keys are marked as deleted but not removed from database for audit purposes.
+
+#### 2. Authentication Flow
+
+Here's how authentication works when a request arrives:
+
+
+
+```csharp
+// 1. Extract API key from request
+var apiKey = httpContext.Request.Headers["X-Api-Key"].FirstOrDefault();
+if (string.IsNullOrEmpty(apiKey)) return AuthenticateResult.NoResult();
+
+// 2. Split prefix and key
+var parts = apiKey.Split('_', 2);
+var prefix = parts[0];
+var key = parts[1];
+
+// 3. Find key by prefix (cached)
+var apiKeyEntity = await _apiKeyRepository.FindByPrefixAsync(prefix);
+if (apiKeyEntity == null) return AuthenticateResult.Fail("Invalid API key");
+
+// 4. Verify hash
+var keyHash = HashHelper.ComputeSha256(key);
+if (apiKeyEntity.KeyHash != keyHash)
+ return AuthenticateResult.Fail("Invalid API key");
+
+// 5. Check expiration and active status
+if (apiKeyEntity.ExpiresAt < DateTime.UtcNow || !apiKeyEntity.IsActive)
+ return AuthenticateResult.Fail("API key expired or inactive");
+
+// 6. Create claims principal with user identity
+var claims = new List
+{
+ new Claim(AbpClaimTypes.UserId, apiKeyEntity.UserId.ToString()),
+ new Claim(AbpClaimTypes.TenantId, apiKeyEntity.TenantId?.ToString() ?? ""),
+ new Claim("ApiKeyId", apiKeyEntity.Id.ToString())
+};
+
+return AuthenticateResult.Success(ticket);
+```
+
+#### 3. Creating and Managing API Keys
+
+**Creating a new key:**
+
+
+
+```csharp
+public class ApiKeyManager : DomainService
+{
+ public async Task<(ApiKey, string)> CreateAsync(
+ Guid userId,
+ string name,
+ DateTime? expiresAt = null)
+ {
+ // Generate unique prefix
+ var prefix = await GenerateUniquePrefixAsync();
+
+ // Generate secure random key
+ var key = GenerateSecureRandomString(32);
+
+ // Hash the key for storage
+ var keyHash = HashHelper.ComputeSha256(key);
+
+ var apiKey = new ApiKey(
+ GuidGenerator.Create(),
+ userId,
+ name,
+ prefix,
+ keyHash,
+ expiresAt,
+ CurrentTenant.Id
+ );
+
+ await _apiKeyRepository.InsertAsync(apiKey);
+
+ // Return both entity and the full key (prefix_key)
+ // This is the ONLY time the actual key is visible
+ return (apiKey, $"{prefix}_{key}");
+ }
+}
+```
+
+**Important**: The actual key is returned only once during creation. After that, only the hash is stored.
+
+
+
+### Using API Keys in Your Application
+
+Once created, clients can use the API key to authenticate:
+
+**HTTP Header (Recommended):**
+```bash
+curl -H "X-Api-Key: sk_prod_abc123def456..." \
+ https://api.example.com/api/products
+```
+
+**JavaScript:**
+```javascript
+const response = await fetch('https://api.example.com/api/products', {
+ headers: {
+ 'X-Api-Key': 'sk_prod_abc123def456...'
+ }
+});
+```
+
+**C# HttpClient:**
+```csharp
+var client = new HttpClient();
+client.DefaultRequestHeaders.Add("X-Api-Key", "sk_prod_abc123def456...");
+var response = await client.GetAsync("https://api.example.com/api/products");
+```
+
+**Python:**
+```python
+import requests
+
+headers = {'X-Api-Key': 'sk_prod_abc123def456...'}
+response = requests.get('https://api.example.com/api/products', headers=headers)
+```
+
+### Permission Management
+
+API keys inherit the user's permissions, but you can further restrict them:
+
+
+
+This allows scenarios like:
+- Read-only API key for reporting tools
+- Limited scope keys for third-party integrations
+- Service-specific keys with minimal permissions
+
+```csharp
+// Check if current request is authenticated via API key
+if (CurrentUser.FindClaim("ApiKeyId") != null)
+{
+ var apiKeyId = CurrentUser.FindClaim("ApiKeyId").Value;
+ // Additional API key specific logic
+}
+```
+
+## Performance Considerations
+
+The implementation uses several optimizations:
+
+**1. Prefix-based indexing**: Database lookups are done by prefix (indexed column), not the full key hash.
+
+**2. Distributed caching**: API keys are cached after first lookup, dramatically reducing database queries.
+
+```csharp
+// Cache configuration
+Configure(options =>
+{
+ options.KeyPrefix = "ApiKey:";
+});
+```
+
+**3. Cache invalidation**: When a key is modified or deleted, cache is automatically invalidated.
+
+**Typical Performance:**
+- Cached lookup: **< 5ms**
+- Database lookup: **< 50ms**
+- Cache hit rate: **~95%**
+
+## Security Best Practices
+
+When implementing API key authentication, follow these guidelines:
+
+✅ **Always use HTTPS** - Never send API keys over unencrypted connections
+
+✅ **Use different keys per environment** - Separate keys for dev, staging, production
+
+❌ **Don't log the full key** - Only log the prefix for debugging
+
+## Getting Started
+
+The complete source code is available on GitHub:
+
+**Repository**: [github.com/salihozkara/AbpApikeyManagement](https://github.com/salihozkara/AbpApikeyManagement)
+
+To integrate it into your ABP project:
+
+1. Clone or download the repository
+2. Add project references to your solution
+3. Add module dependencies to your modules
+4. Run EF Core migrations to create the database tables
+5. Navigate to `/ApiKeyManagement` to start managing keys
+
+```csharp
+// In your Web module
+[DependsOn(typeof(ApiKeyManagementWebModule))]
+public class YourWebModule : AbpModule
+{
+ // ...
+}
+
+// In your HttpApi.Host module
+[DependsOn(typeof(ApiKeyManagementHttpApiModule))]
+public class YourHttpApiHostModule : AbpModule
+{
+ // ...
+}
+```
+
+## Conclusion
+
+API key authentication remains a crucial part of modern API security, especially for machine-to-machine communication. While it shouldn't replace user authentication methods like OAuth2 for user-facing applications, it's perfect for:
+
+- Automated scripts and tools
+- Service-to-service communication
+- Third-party integrations
+- Long-lived access without token refresh complexity
+
+The implementation shown here demonstrates how ABP Framework's modular architecture, DDD principles, and built-in features (multi-tenancy, caching, permissions) can be leveraged to build a production-ready API key management system.
+
+The solution is open-source and ready to be integrated into your ABP projects. Feel free to explore the code, suggest improvements, or adapt it to your specific needs.
+
+**Resources:**
+- GitHub Repository: [salihozkara/AbpApikeyManagement](https://github.com/salihozkara/AbpApikeyManagement)
+- ABP Framework: [abp.io](https://abp.io)
+- ABP Documentation: [docs.abp.io](https://abp.io/docs/latest)
+
+Happy coding! 🚀
diff --git a/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/summary.md b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/summary.md
new file mode 100644
index 0000000000..4e5abcd224
--- /dev/null
+++ b/docs/en/Community-Articles/2025-11-15-building-an-api-key-management-system/summary.md
@@ -0,0 +1 @@
+Learn how to implement API key authentication in ABP Framework applications. This comprehensive guide covers what API keys are, when to use them over OAuth2/JWT, real-world use cases for mobile apps and microservices, and a complete implementation with user-based key management, SHA-256 hashing, permission delegation, and built-in UI.
diff --git a/docs/en/Community-Articles/2025-11-17-Angular-21-Signals/cover-image.png b/docs/en/Community-Articles/2025-11-17-Angular-21-Signals/cover-image.png
new file mode 100644
index 0000000000..a37bb3d775
Binary files /dev/null and b/docs/en/Community-Articles/2025-11-17-Angular-21-Signals/cover-image.png differ
diff --git a/docs/en/Community-Articles/2025-11-17-Angular-21-Signals/post.md b/docs/en/Community-Articles/2025-11-17-Angular-21-Signals/post.md
new file mode 100644
index 0000000000..60fcc6405b
--- /dev/null
+++ b/docs/en/Community-Articles/2025-11-17-Angular-21-Signals/post.md
@@ -0,0 +1,322 @@
+# Signal-Based Forms in Angular 21: Why You’ll Never Miss Reactive Forms Again
+
+Angular 21 introduces one of the most exciting developments in the modern edition of Angular: **Signal-Based Forms**. Built directly on the reactive foundation of Angular signals, this new experimental API provides a cleaner, more intuitive, strongly typed, and ergonomic approach for managing form state—without the heavy boilerplate of Reactive Forms.
+
+> ⚠️ **Important:** Signal Forms are *experimental*.
+> Their API can change. Avoid using them in critical production scenarios unless you understand the risks.
+
+Despite this, Signal Forms clearly represent Angular’s future direction.
+---
+
+## Why Signal Forms?
+
+Traditionally in Angular, building forms has involved several concerns:
+
+- Tracking values
+- Managing UI interaction states (touched, dirty)
+- Handling validation
+- Keeping UI and model in sync
+
+Reactive Forms solved many challenges but introduced their own:
+
+- Verbosity FormBuilder API
+- Required subscriptions (valueChanges)
+- Manual cleaning
+- Difficult nested forms
+- Weak type-safety
+
+**Signal Forms solve these problems through:**
+
+1." Automatic synchronization
+2." Full type safety
+3." Schema-based validation
+4." Fine-grained reactivity
+5." Drastically reduced boilerplate
+6." Natural integration with Angular Signals
+
+---
+
+### 1. Form Models — The Core of Signal Forms
+
+A **form model** is simply a writable signal holding the structure of your form data.
+
+```ts
+import { Component, signal } from '@angular/core';
+import { form, Field } from '@angular/forms/signals';
+
+@Component({
+ selector: 'app-login',
+ imports: [Field],
+ template: `
+
+
+ `,
+})
+export class LoginComponent {
+ loginModel = signal({
+ email: '',
+ password: '',
+ });
+
+ loginForm = form(this.loginModel);
+}
+```
+
+Calling `form(model)` creates a **Field Tree** that maps directly to your model.
+
+---
+
+### 2. Achieving Full Type Safety
+
+Although TypeScript can infer types from object literals, defining explicit interfaces provides maximum safety and better IDE support.
+
+```ts
+interface LoginData {
+ email: string;
+ password: string;
+}
+
+loginModel = signal({
+ email: '',
+ password: '',
+});
+
+loginForm = form(loginModel);
+```
+
+Now:
+
+- `loginForm.email` → `FieldTree`
+- Accessing invalid fields like `loginForm.username` results in compile-time errors
+
+This level of type safety surpasses Reactive Forms.
+
+---
+
+### 3. Reading Form Values
+
+#### Read from the model (entire form):
+
+```ts
+onSubmit() {
+ const data = this.loginModel();
+ console.log(data.email, data.password);
+}
+```
+
+#### Read from an individual field:
+
+```html
+
Current email: {{ loginForm.email().value() }}
+```
+
+Each field exposes:
+
+- `value()`
+- `valid()`
+- `errors()`
+- `dirty()`
+- `touched()`
+
+All as signals.
+
+---
+
+### 4. Updating Form Models Programmatically
+
+Signal Forms allow three update methods.
+
+#### 1. Replace the entire model
+
+```ts
+this.userModel.set({
+ name: 'Alice',
+ email: 'alice@example.com',
+});
+```
+
+#### 2. Patch specific fields
+
+```ts
+this.userModel.update(prev => ({
+ ...prev,
+ email: newEmail,
+}));
+```
+
+#### 3. Update a single field
+
+```ts
+this.userForm.email().value.set('');
+```
+
+This eliminates the need for:
+
+- `patchValue()`
+- `setValue()`
+- `formGroup.get('field')`
+
+---
+
+### 5. Automatic Two-Way Binding With `[field]`
+
+The `[field]` directive enables perfect two-way data binding:
+
+```html
+
+```
+
+#### How it works:
+
+- **User input → Field state → Model**
+- **Model updates → Field state → Input UI**
+
+No subscriptions.
+No event handlers.
+No boilerplate.
+
+Reactive Forms could never achieve this cleanly.
+
+---
+
+### 6. Nested Models and Arrays
+
+Models can contain nested object structures:
+
+```ts
+userModel = signal({
+ name: '',
+ address: {
+ street: '',
+ city: '',
+ },
+});
+```
+
+Access fields easily:
+
+```html
+
+```
+
+Arrays are also supported:
+
+```ts
+orderModel = signal({
+ items: [
+ { product: '', quantity: 1, price: 0 }
+ ]
+});
+```
+
+Field state persists even when array items move, thanks to identity tracking.
+
+---
+
+### 7. Schema-Based Validation
+
+Validation is clean and centralized:
+
+```ts
+import { required, email } from '@angular/forms/signals';
+
+const model = signal({ email: '' });
+
+const formRef = form(model, {
+ email: [required(), email()],
+});
+```
+
+Field validation state is reactive:
+
+```ts
+formRef.email().valid()
+formRef.email().errors()
+formRef.email().touched()
+```
+
+Validation no longer scatters across components.
+
+---
+
+### 8. When Should You Use Signal Forms?
+
+#### New Angular 21+ apps
+Signal-first architecture is the new standard.
+
+#### Teams wanting stronger type safety
+Every field is exactly typed.
+
+#### Devs tired of Reactive Form boilerplate
+Signal Forms drastically simplify code.
+
+#### Complex UI with computed reactive form state
+Signals integrate perfectly.
+
+#### ❌ Avoid if:
+- You need long-term stability
+- You rely on mature Reactive Forms features
+- Your app must avoid experimental APIs
+
+---
+
+### 9. Reactive Forms vs Signal Forms
+
+| Feature | Reactive Forms | Signal Forms |
+|--------|----------------|--------------|
+| Boilerplate | High | Very low |
+| Type-safety | Weak | Strong |
+| Two-way binding | Manual | Automatic |
+| Validation | Scattered | Centralized schema |
+| Nested forms | Verbose | Natural |
+| Subscriptions | Required | None |
+| Change detection | Zone-heavy | Fine-grained |
+
+Signal Forms feel like the "modern Angular mode," while Reactive Forms increasingly feel legacy.
+
+---
+
+### 10. Full Example: Login Form
+
+```ts
+@Component({
+ selector: 'app-login',
+ imports: [Field],
+ template: `
+
+ `,
+})
+export class LoginComponent {
+ model = signal({ email: '', password: '' });
+ form = form(this.model);
+
+ submit() {
+ console.log(this.model());
+ }
+}
+```
+
+Minimal. Reactive. Completely type-safe.
+
+---
+
+## **Conclusion**
+
+Signal Forms in Angular 21 represent a big step forward:
+
+- Cleaner API
+- Stronger type safety
+- Automatic two-way binding
+- Centralized validation
+- Fine-grained reactivity
+- Dramatically better developer experience
+
+
+Although these are experimental, they clearly show the future of Angular's form ecosystem.
+Once you get into using Signal Forms, you may never want to use Reactive Forms again.
+
+---
diff --git a/docs/en/framework/architecture/domain-driven-design/repositories.md b/docs/en/framework/architecture/domain-driven-design/repositories.md
index a5753e3808..eed0529112 100644
--- a/docs/en/framework/architecture/domain-driven-design/repositories.md
+++ b/docs/en/framework/architecture/domain-driven-design/repositories.md
@@ -254,6 +254,35 @@ ABP uses dynamic proxying to make these attributes work. There are some rules he
> 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.
+#### Check If Change Tracking Is Enabled
+
+In case of you need to check if change tracking is enabled or disabled on a repository object, you can simply read the `IsChangeTrackingEnabled` property. It is `false` by default for read only repositories (see the *Read Only Repositories* section below). It is `null` by default for other repository objects. If it is `null`, change tracking is enabled unless you've explicitly used the change tracking attributes (see the *Attributes for Change Tracking* section).
+
+### The `EntityName` Property
+
+The `EntityName` property is to set the related entity's name on the repository object in some advanced scenarios. For example, you can use this property to use the [Shared-type entity types](https://learn.microsoft.com/en-us/ef/core/modeling/entity-types?tabs=data-annotations#shared-type-entity-types) feature of Entity Framework Core (it allows you to use a single entity class to work on multiple tables in the database). In other cases, you can just ignore it.
+
+Default value is `null` unless you explicitly set it.
+
+**Example usage:**
+
+````csharp
+IRepository _repository; // You can inject it into your class
+...
+_repository.SetEntityName("Product"); //Set the entity name before using the repository
+//use the _repository object as always
+````
+
+### The `ProviderName` Property
+
+The `ProviderName` property of a repository object returns the underlying database provider name. It may return one of the following string values for the built-in providers:
+
+* `Volo.Abp.EntityFrameworkCore` (from the constant `AbpEfCoreConsts.ProviderName` value)
+* `Volo.Abp.MongoDB` (from the constant `AbpMongoDbConsts.ProviderName` value)
+* `Volo.Abp.MemoryDb` (from the constant `AbpMemoryDbConsts.ProviderName` value)
+
+This property is not used in most cases. It is mainly available for internal usage of the ABP framework.
+
## Other Generic Repository Types
Standard `IRepository` interface exposes the standard `IQueryable` and you can freely query using the standard LINQ methods. This is fine for most of the applications. However, some ORM providers or database systems may not support standard `IQueryable` interface. If you want to use such providers, you can't rely on the `IQueryable`.
diff --git a/docs/en/framework/infrastructure/event-bus/distributed/azure.md b/docs/en/framework/infrastructure/event-bus/distributed/azure.md
index 8e1bff3e63..92a961230d 100644
--- a/docs/en/framework/infrastructure/event-bus/distributed/azure.md
+++ b/docs/en/framework/infrastructure/event-bus/distributed/azure.md
@@ -137,4 +137,14 @@ Configure(options =>
});
````
+Use `TokenCredential` instead of `ConnectionString` if you want to use custom credential.
+
+````csharp
+Configure(options =>
+{
+ options.Connections.Default.FullyQualifiedNamespace = "sb-my-app.servicebus.windows.net";
+ options.Connections.Default.TokenCredential = new DefaultAzureCredential();
+});
+````
+
Using these options classes can be combined with the `appsettings.json` way. Configuring an option property in the code overrides the value in the configuration file.
diff --git a/docs/en/release-info/migration-guides/abp-10-0.md b/docs/en/release-info/migration-guides/abp-10-0.md
index f1ad4e0397..b5fb4e0ed9 100644
--- a/docs/en/release-info/migration-guides/abp-10-0.md
+++ b/docs/en/release-info/migration-guides/abp-10-0.md
@@ -7,19 +7,19 @@
# ABP Version 10.0 Migration Guide
-This document is a guide for upgrading ABP v9.x solutions to ABP v10.0. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application.
+This document is a guide for upgrading ABP v9.x solutions to ABP v10.0. There are some changes in this version that may affect your applications. Please read them carefully and apply the necessary changes to your application.
## Open-Source (Framework)
-### Upgraded to .NET 10.0
+### Upgrade to .NET 10.0
-We've upgraded ABP to .NET 10.0, so you need to move your solutions to .NET 10.0 if you want to use ABP 10.0. You can check Microsoft’s [Migrate from ASP.NET Core 9.0 to 10.0](https://learn.microsoft.com/en-us/aspnet/core/migration/90-to-100) documentation, to see how to update an existing ASP.NET Core 9.0 project to ASP.NET Core 10.0.
+We've upgraded ABP to .NET 10.0, so you need to move your solutions to .NET 10.0 if you want to use ABP 10.0. You can check Microsoft’s [Migrate from ASP.NET Core 9.0 to 10.0](https://learn.microsoft.com/en-us/aspnet/core/migration/90-to-100) documentation to see how to update an existing ASP.NET Core 9.0 project to ASP.NET Core 10.0.
-### Add new EF Core Migrations
+### Add New EF Core Migrations
Some entities in certain modules have been modified. If you are using Entity Framework Core, please create a new EF Core migration in your project after upgrading to ABP 10.0.
-> If the migration file is empty, you can remove it by `dotnet ef migrations remove` command.
+> If the migration file is empty, you can remove it by using the `dotnet ef migrations remove` command.
### Razor Runtime Compilation Obsolete
@@ -53,31 +53,25 @@ For more information, you can check the [Razor Runtime Compilation Obsolete](htt
### IActionContextAccessor Obsolete
-We removed the `IActionContextAccessor` from dependency injection.
-
-> We are not using `IActionContextAccessor` in ABP core framework and modules.
+We removed the `IActionContextAccessor` from dependency injection and are not using the `IActionContextAccessor` in ABP's core framework and modules.
See [IActionContextAccessor Obsolete](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/10/iactioncontextaccessor-obsolete) for more information.
### Add `BLOB Storing Memory Provider` module.
-In this version, we added the `BLOB Storing Memory Provider` module for unit testing purposes.
+In this version, we have added the `BLOB Storing Memory Provider` module for unit testing purposes.
See the [BLOB Storing Memory Provider](https://github.com/abpframework/abp/blob/dev/docs/en/framework/infrastructure/blob-storing/memory.md) document for more information.
### Always use `MapStaticAssets`
-Provious, the `MapStaticAssets` has performance problems if there are too many static files. and we will use `StaticFileMiddleware` to serve the static files in development mode. NET 10.0 has fixed this problem. We will always use `MapStaticAssets` to serve the static files.
+Previously, the `MapStaticAssets` had performance problems if there were too many static files. NET 10.0 has fixed this problem. We will always use `MapStaticAssets` to serve the static files.
See [Static file serving performance issues](https://github.com/dotnet/aspnetcore/issues/59673) for more information.
### C# 14 overload resolution with span parameters
-NET Core will redirect `array.Contains` extension method to `MemoryExtensions.Contains`, This will cause `MongoDB.Driver` to be unable to translate `IQueryable`, If you are using `array.Contains` in your code, you should use following code to avoid this problem.
-
-> Only array has this problem, other types are not affected. eg List, HashSet, etc.
-
-> MongoDB.Driver will be fixed in the future.
+NET Core will redirect the `array.Contains` extension method to `MemoryExtensions.Contains`. This will cause `MongoDB.Driver` to be unable to translate `IQueryable`. If you are using `array.Contains` in your code, you should use the following code to avoid this problem:
```csharp
M((array, num) => array.Contains(num)); // fails, binds to MemoryExtensions.Contains
@@ -86,13 +80,15 @@ M((array, num) => array.AsEnumerable().Contains(num)); // ok, binds to Enumerabl
M((array, num) => Enumerable.Contains(array, num)); // ok, binds to Enumerable.Contains
```
+> Please note that only the `array` type has this problem. Other types are not affected (e.g. `List`, `HashSet`, etc). **MongoDB.Driver** provider will be fixed in future versions, and we will immediately apply the changes if needed.
+
See the [C# 14 overload resolution with span parameters](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/10.0/csharp-overload-resolution#recommended-action) for more information.
-### OpenIddict 7.X
+### OpenIddict Upgrade to 7.X
-We upgraded OpenIddict to 7.X. See the [OpenIddict 6.x to 7.x Migration Guide](https://documentation.openiddict.com/guides/migration/60-to-70.html) for more information.
+We have upgraded **OpenIddict** to **v7.x**. For detailed information about the changes introduced in this release, refer to the [OpenIddict 6.x to 7.x Migration Guide](https://documentation.openiddict.com/guides/migration/60-to-70.html).
-OpenIddict 7.X changed the `OpenIddictToken` entity, you must create a new database migration if you use Entity Framework Core.
+As a developer, you typically only need to **create a new Entity Framework Core migration** and **apply it to your database**, since **OpenIddict v7.x** introduces a modification in the `OpenIddictToken` entity.
### Migrating from AutoMapper to Mapperly
@@ -118,6 +114,3 @@ Starting from **ABP 10.0**, the [`HideErrors`](../../framework/fundamentals/cach
By default, ABP hides and logs cache server errors to keep the application running even when the cache is unavailable.
However, in the **development environment**, errors are no longer hidden so that developers can immediately detect and fix **any cache server issues** (such as connection, configuration, or runtime errors).
-
-## PRO
-
diff --git a/docs/en/release-info/release-notes.md b/docs/en/release-info/release-notes.md
index cb6d5f421d..f0c58f0013 100644
--- a/docs/en/release-info/release-notes.md
+++ b/docs/en/release-info/release-notes.md
@@ -14,9 +14,21 @@ Also see the following notes about ABP releases:
* [ABP Studio release notes](../studio/release-notes.md)
* [Change logs for ABP pro packages](https://abp.io/pro-releases)
+## 10.0 (2025-10-01)
+
+This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/announcements/announcing-abp-10-0-release-candidate-86lrnyox)** for the v10.0 release.
+
+* Upgraded to .NET 10.0
+* Upgraded to `Blazorise` **v1.8.6**
+* New PRO Module: [Elsa Workflows](../modules/elsa-pro.md)
+* New Object Mapper: **Mapperly**
+* Localization: Nested Object Support in JSON Files
+* EF Core Shared Entity Types on Repositories
+* Angular SSR Support
+
## 9.3 (2025-06-17)
-This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/articles/announcing-abp-9-3-release-candidate-4dqgiryf)** for the v9.3 release.
+See the detailed **[blog post / announcement](https://abp.io/community/announcements/announcing-abp-9-3-stable-release-fw4n9sng)** for the v9.3 release.
* Cron Expression Support for Background Workers
* Docs Module: PDF Export
diff --git a/docs/en/release-info/road-map.md b/docs/en/release-info/road-map.md
index f7b432a39d..0df94ec157 100644
--- a/docs/en/release-info/road-map.md
+++ b/docs/en/release-info/road-map.md
@@ -11,36 +11,39 @@ This document provides a road map, release schedule, and planned features for th
## Next Versions
-### v10.0
+### v10.1
-The next version will be 10.0 and planned to release the stable 10.0 version in December 2025. We will be mostly working on the following topics:
+The next version will be 10.1 and planned to release the stable 10.1 version in January 2026. We will be mostly working on the following topics:
* Framework
- * Upgrading to .NET 10
- * Upgrading 3rd-party dependencies
- * Enhancements in the core points
+ * OpenTelemetry Protocol Support for 3rd-party Integrations
+ * Resource Based Authorization Integration
+ * Upgrading 3rd-party Dependencies
+ * Enhancements in the Core Points
* ABP Suite
- * Define navigation properties without target string property dependency
- * Improvements one-to-many scenarios
- * File Upload Modal enhancements
-
+ * Define Navigation Properties Without Target String Property Dependency
+ * Improvements on Master-Detail Page Desing (making it more compact)
+ * Improvements One-To-Many Scenarios
+ * File Upload Modal Enhancements
* ABP Studio
- * Allow to directly create new solutions with ABP's RC (Release Candidate) versions
- * Automate more details on new service creation for a microservice solution
- * Support multiple concurrent Kubernetes deployment/integration scenarios
- * Improve the module installation experience / installation guides
- * Improve client proxy generation experience
- * Modular Monolith Application Startup Template
-
-* Application modules
- * Account module: Support mixed social/local login scenarios & adding security related features
- * UI/UX improvements on existing application modules
-
-* Updating existing tutorials & documents (with other UI & DB options)
- * Microservice development
- * Modular monolith development
+ * Allow to Directly Create New Solutions with ABP's RC (Release Candidate) Versions
+ * Automate More Details on New Service Creation for a Microservice Solution
+ * Allow to Download ABP Samples from ABP Studio
+ * Task Panel Enhancements (and Documentation)
+ * Support Multiple Concurrent Kubernetes Deployment/Integration Scenarios
+ * Improve the Module Installation Experience / Installation Guides
+
+* Application Modules
+ * Payment Module: Public Page Implementation (for Blazor & Angular UIs)
+ * AI Management Module: UI Implementation for Blazor & Angular UIs
+ * CMS Kit: Enhancements for Some Features (Rating, Dynamic Widgets, FAQ and more...)
+ * UI/UX Improvements on Existing Application Modules
+
+* Updating Existing Tutorials & Documents (with Other UI & DB Options)
+ * Microservice Development
+ * Modular Monolith Development
## Backlog Items
@@ -50,7 +53,6 @@ The *Next Versions* section above shows the main focus of the planned versions.
The ABP framework is [open source](https://github.com/abpframework/abp) and free for everyone. You can see its [public backlog](https://github.com/abpframework/abp/milestone/2). Here, are some of the important features you can expect from next versions:
-* [#236](https://github.com/abpframework/abp/issues/236) / Resource based authorization system
* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](../modules/index.md))
* [#57](https://github.com/abpframework/abp/issues/57) / Built-in CQRS infrastructure
* [#58](https://github.com/abpframework/abp/issues/58) / Content localization system (multilingual entities)
@@ -85,12 +87,9 @@ Here, are some of the important planned features for next ABP Studio versions:
* Analyze user solutions to explore entities, domain services, application services, pages and other fundamental objects.
* Swagger authentication support for the built-in browser
* Show related requests/events (traces) together in the solution runner panel
-* Integrate common tool dashboards into ABP Studio (such a Garana, Redis, RabbitMQ, Kibana, etc)
* Built-in command terminal
* Automate all steps of new service creation for microservice solutions
-* Container application type support for Solution Runner (to individually control docker dependencies)
* More options while creating new solutions
-* Downloading samples in ABP studio
* Built-in ABP documentation experience
* Auto-execute terminal commands in markdown files
* Compare changes on the startup templates when a new ABP version is published
diff --git a/docs/en/studio/installation.md b/docs/en/studio/installation.md
index 1b1ba2cf04..6f12953f99 100644
--- a/docs/en/studio/installation.md
+++ b/docs/en/studio/installation.md
@@ -11,7 +11,7 @@ This document explains how to install the ABP Studio tool.
## Pre-requirements
-ABP Studio automatically instals most of the required dependencies. When you first launch the application, it will check for and install the following components if missed:
+ABP Studio automatically installs most of the required dependencies. When you first launch the application, it will check for and install the following components if missed:
* .NET SDK
* Node.js
@@ -19,7 +19,7 @@ ABP Studio automatically instals most of the required dependencies. When you fir
* mkcert (for HTTPS development)
* WireGuard (for Kubernetes operations)
-However, the followings should be manually installed:
+However, the following should be manually installed:
### Docker (Required for Kubernetes Operations)
@@ -55,7 +55,7 @@ ABP Studio allows you to customize the user interface theme according to your pr
## Upgrading
ABP Studio periodically checks for updates in the background, and when a new version of ABP Studio is available, you will be notified through a modal.
-The modal will prompt you to update to the latest version as below:
+The modal will prompt you to update to the latest version as follows:

diff --git a/docs/en/testing/integration-tests.md b/docs/en/testing/integration-tests.md
index dce7813e45..c87d270747 100644
--- a/docs/en/testing/integration-tests.md
+++ b/docs/en/testing/integration-tests.md
@@ -350,7 +350,7 @@ There are multiple overloads of the `WithUnitOfWorkAsync` method that you can us
## Working with DbContext
-In some cases, you may want to directory work with the [Entity Framework's `DbContext` object](https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext) to perform database operations in your test methods. In this case, you can use `IDbContextProvider`service to obtain a `DbContext` instance inside a unit of work.
+In some cases, you may want to directly work with the [Entity Framework's `DbContext` object](https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext) to perform database operations in your test methods. In this case, you can use `IDbContextProvider`service to obtain a `DbContext` instance inside a unit of work.
The following example shows how you can create a `DbContext` object in a test method:
diff --git a/docs/en/tutorials/todo/layered/index.md b/docs/en/tutorials/todo/layered/index.md
index 08c463e81c..1cc2f9030c 100644
--- a/docs/en/tutorials/todo/layered/index.md
+++ b/docs/en/tutorials/todo/layered/index.md
@@ -756,45 +756,46 @@ We can then use `todoService` to use the server-side HTTP APIs, as we'll do in t
Open the `/angular/src/app/home/home.component.ts` file and replace its content with the following code block:
-```js
+```ts
+import {Component, inject, OnInit} from '@angular/core';
+import {FormsModule} from '@angular/forms';
import { ToasterService } from '@abp/ng.theme.shared';
-import { Component, OnInit, inject } from '@angular/core';
import { TodoItemDto, TodoService } from '@proxy';
@Component({
- selector: 'app-home',
- standalone: false,
- templateUrl: './home.component.html',
- styleUrls: ['./home.component.scss']
+ selector: 'app-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.scss'],
+ imports: [FormsModule]
})
export class HomeComponent implements OnInit {
- todoItems: TodoItemDto[];
- newTodoText: string;
+ todoItems: TodoItemDto[];
+ newTodoText: string;
+ readonly todoService = inject(TodoService);
+ readonly toasterService = inject(ToasterService);
- private readonly todoService = inject(TodoService);
- private readonly toasterService = inject(ToasterService);
+ ngOnInit(): void {
+ this.todoService.getList().subscribe(response => {
+ this.todoItems = response;
+ });
+ }
- ngOnInit(): void {
- this.todoService.getList().subscribe(response => {
- this.todoItems = response;
- });
- }
-
- create(): void {
- this.todoService.create(this.newTodoText).subscribe((result) => {
- this.todoItems = this.todoItems.concat(result);
- this.newTodoText = null;
- });
- }
+ create(): void{
+ this.todoService.create(this.newTodoText).subscribe((result) => {
+ this.todoItems = this.todoItems.concat(result);
+ this.newTodoText = null;
+ });
+ }
- delete(id: string): void {
- this.todoService.delete(id).subscribe(() => {
- this.todoItems = this.todoItems.filter(item => item.id !== id);
- this.toasterService.info('Deleted the todo item.');
- });
- }
+ delete(id: string): void {
+ this.todoService.delete(id).subscribe(() => {
+ this.todoItems = this.todoItems.filter(item => item.id !== id);
+ this.toasterService.info('Deleted the todo item.');
+ });
+ }
}
+
```
We've used `todoService` to get the list of todo items and assigned the returning value to the `todoItems` array. We've also added `create` and `delete` methods. These methods will be used on the view side.
@@ -805,31 +806,35 @@ Open the `/angular/src/app/home/home.component.html` file and replace its conten
```html