diff --git a/Directory.Packages.props b/Directory.Packages.props
index fa951f8d7d..6a900d2ab6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -181,7 +181,7 @@
-
+
diff --git a/docs/en/release-info/release-notes.md b/docs/en/release-info/release-notes.md
index bf335fa7a2..08d0bcde31 100644
--- a/docs/en/release-info/release-notes.md
+++ b/docs/en/release-info/release-notes.md
@@ -14,8 +14,23 @@ 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.1 (2026-01-06)
+
+> This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/announcements/announcing-abp-10-1-release-candidate-cyqui19d)** for the v10.1 release.
+
+* Resource-Based Authorization
+* Introducing the [TickerQ Background Worker Provider](../framework/infrastructure/background-workers/tickerq.md)
+* Angular UI: Version Upgrade to **v21**
+* [File Management Module](../modules/file-management.md): Public File Sharing Support
+* [Payment Module](../modules/payment.md): Public Page Implementation for Blazor & Angular UIs
+* [AI Management Module](../modules/ai-management/index.md) for Blazor & Angular UIs
+* [Identity PRO Module](../modules/identity-pro.md): Password History Support
+* [Account PRO Module](../modules/account-pro.md): Introducing WebAuthn Passkeys
+
## 10.0 (2025-11-18)
+> **Note**: ABP has upgraded to .NET 10.0, so if you plan to use ABP 10.0, you’ll need to migrate your solutions to .NET 10.0. You can refer to the [Migrate from ASP.NET Core 9.0 to 10.0](https://learn.microsoft.com/en-us/aspnet/core/migration/90-to-100) documentation for guidance. However, ABP’s NuGet packages are compatible with both .NET 9 and .NET 10, allowing developers to continue using .NET 9 while still enjoying the latest features and improvements of the ABP Framework without upgrading their SDK.
+
See the detailed **[blog post / announcement](https://abp.io/community/announcements/abp.io-platform-10.0-final-has-been-released-spknn925)** for the v10.0 release.
* Upgraded to .NET 10.0
diff --git a/docs/en/release-info/road-map.md b/docs/en/release-info/road-map.md
index 0df94ec157..70a9b392c4 100644
--- a/docs/en/release-info/road-map.md
+++ b/docs/en/release-info/road-map.md
@@ -1,7 +1,7 @@
```json
//[doc-seo]
{
- "Description": "Explore the ABP Platform Road Map for insights on upcoming features, release schedules, and improvements in version 9.1, launching January 2025."
+ "Description": "Explore the ABP Platform Road Map for insights on upcoming features, release schedules, and improvements in version 10.1, launching January 2026."
}
```
@@ -11,33 +11,35 @@ This document provides a road map, release schedule, and planned features for th
## Next Versions
-### v10.1
+### v10.2
-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:
+The next version will be 10.2 and planned to release the stable 10.2 version in April 2026. We will be mostly working on the following topics:
* Framework
- * OpenTelemetry Protocol Support for 3rd-party Integrations
- * Resource Based Authorization Integration
+ * Resource-Based Authorization Improvements
+ * Handle datetime/timezon in `AbpExtensibleDataGrid` Component
* Upgrading 3rd-party Dependencies
* Enhancements in the Core Points
* ABP Suite
- * Define Navigation Properties Without Target String Property Dependency
+ * Creating enums on-the-fly (without needing to create manually on the code side)
+ * Improvements on the generated codes for nullability
* 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
+ * Integrate AI Management Module with all solution templates and UIs
* Automate More Details on New Service Creation for a Microservice Solution
* Allow to Download ABP Samples from ABP Studio
- * Task Panel Enhancements (and Documentation)
+ * Task Panel 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
+ * AI Management: MCP & RAG Supports
+ * File Management: Using Resource-Based Permission (on file-sharing and more...)
* CMS Kit: Enhancements for Some Features (Rating, Dynamic Widgets, FAQ and more...)
* UI/UX Improvements on Existing Application Modules
diff --git a/docs/en/studio/release-notes.md b/docs/en/studio/release-notes.md
index d2eba88e0f..13e206127e 100644
--- a/docs/en/studio/release-notes.md
+++ b/docs/en/studio/release-notes.md
@@ -9,7 +9,14 @@
This document contains **brief release notes** for each ABP Studio release. Release notes only include **major features** and **visible enhancements**. Therefore, they don't include all the development done in the related version.
-## 2.1.3 (2025-12-15) Latest
+## 2.1.4 (2025-12-30) Latest
+
+* Fixed books sample for blazor-webapp tiered solution.
+* Fixed K8s cluster deployment issues for microservices.
+* Fixed docker build problem on microservice template.
+* Showed logs of the executed tasks.
+
+## 2.1.3 (2025-12-15)
* Updated `createCommand` and CLI help for multi-tenancy.
* Fixed `BookController` templating problem.
diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs
index 7d6955f08b..85cc987b61 100644
--- a/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/Extensions/DependencyInjection/CookieAuthenticationOptionsExtensions.cs
@@ -61,11 +61,13 @@ public static class CookieAuthenticationOptionsExtensions
return;
}
+ var clientId = principalContext.Properties.GetString("client_id");
+ var clientSecret = principalContext.Properties.GetString("client_secret");
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest
{
Address = introspectionEndpoint,
- ClientId = openIdConnectOptions.ClientId!,
- ClientSecret = openIdConnectOptions.ClientSecret,
+ ClientId = clientId ?? openIdConnectOptions.ClientId!,
+ ClientSecret = clientSecret ?? openIdConnectOptions.ClientSecret,
Token = accessToken
});
diff --git a/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/TimeZoneHelper.cs b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/TimeZoneHelper.cs
index 6101585878..23446069a9 100644
--- a/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/TimeZoneHelper.cs
+++ b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/TimeZoneHelper.cs
@@ -7,14 +7,43 @@ namespace Volo.Abp.Timing;
public static class TimeZoneHelper
{
+ ///
+ /// Returns timezone list ordered by display name, enriched with UTC offset, filtering out invalid ids.
+ ///
public static List GetTimezones(List timezones)
{
return timezones
.OrderBy(x => x.Name)
- .Select(x => new NameValue( $"{x.Name} ({GetTimezoneOffset(TZConvert.GetTimeZoneInfo(x.Name))})", x.Name))
+ .Select(TryCreateNameValueWithOffset)
+ .OfType()
.ToList();
}
+ ///
+ /// Builds a with the original timezone ID in Value and a display name that includes
+ /// the UTC offset in the Name property; returns null if the id is not found.
+ ///
+ public static NameValue? TryCreateNameValueWithOffset(NameValue timeZone)
+ {
+ try
+ {
+ var timeZoneInfo = TZConvert.GetTimeZoneInfo(timeZone.Name);
+ var name = $"{timeZone.Name} ({GetTimezoneOffset(timeZoneInfo)})";
+ return new NameValue(name, timeZone.Name);
+ }
+ catch (Exception)
+ {
+ // Invalid or unknown timezone IDs are expected here (e.g. from user input or
+ // external sources). We intentionally swallow this exception and return null
+ // so callers (like GetTimezones) can filter out invalid entries.
+ }
+
+ return null;
+ }
+
+ ///
+ /// Formats the base UTC offset as "+hh:mm" or "-hh:mm" for display purposes.
+ ///
public static string GetTimezoneOffset(TimeZoneInfo timeZoneInfo)
{
if (timeZoneInfo.BaseUtcOffset < TimeSpan.Zero)
diff --git a/framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/TimeZoneHelper_Tests.cs b/framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/TimeZoneHelper_Tests.cs
new file mode 100644
index 0000000000..54d8d37361
--- /dev/null
+++ b/framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/TimeZoneHelper_Tests.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using Shouldly;
+using TimeZoneConverter;
+using Volo.Abp.Testing;
+using Xunit;
+
+namespace Volo.Abp.Timing;
+
+public class TimeZoneHelper_Tests : AbpIntegratedTest
+{
+ [Fact]
+ public void GetTimezones_Should_Filter_Invalid_Timezones()
+ {
+ var validTimeZoneId = "UTC";
+ var invalidTimeZoneId = "Invalid/Zone";
+
+ var timezones = new List
+ {
+ new(invalidTimeZoneId, invalidTimeZoneId),
+ new(validTimeZoneId, validTimeZoneId)
+ };
+
+ var result = TimeZoneHelper.GetTimezones(timezones);
+
+ result.Count.ShouldBe(1);
+
+ var expectedTimeZoneInfo = TZConvert.GetTimeZoneInfo(validTimeZoneId);
+ var expectedName = $"{validTimeZoneId} ({TimeZoneHelper.GetTimezoneOffset(expectedTimeZoneInfo)})";
+
+ result[0].Name.ShouldBe(expectedName);
+ result[0].Value.ShouldBe(validTimeZoneId);
+ }
+
+ [Fact]
+ public void TryCreateNameValueWithOffset_Should_Return_Null_For_Invalid_Timezone()
+ {
+ TimeZoneHelper.TryCreateNameValueWithOffset(new NameValue("Invalid/Zone", "Invalid/Zone")).ShouldBeNull();
+ }
+}
diff --git a/npm/ng-packs/packages/schematics/src/utils/methods.ts b/npm/ng-packs/packages/schematics/src/utils/methods.ts
index d3fc935819..6d31903a78 100644
--- a/npm/ng-packs/packages/schematics/src/utils/methods.ts
+++ b/npm/ng-packs/packages/schematics/src/utils/methods.ts
@@ -19,4 +19,9 @@ export const getParamValueName = (paramName: string, descriptorName: string) =>
export function isDictionaryType(type?: string, typeSimple?: string): boolean {
const haystacks = [type || '', typeSimple || ''];
return haystacks.some(t => /(^|\b)(System\.Collections\.Generic\.)?(I)?Dictionary\s* /(^|\b)(System\.Collections\.Generic\.)?(I)?(List|Enumerable|Collection)\s* `${x}[]`).some(x => x === type);
+ // Check for array types like Volo.Abp.Content.IRemoteStreamContent[]
+ if (VOLO_REMOTE_STREAM_CONTENT.map(x => `${x}[]`).some(x => x === type)) {
+ return true;
+ }
+
+ // Check for collection types like List, IEnumerable, ICollection, Collection, IList
+ // This matches any generic type from System.Collections.Generic that implements IEnumerable
+ if (isCollectionType(type)) {
+ const { generics } = extractGenerics(type);
+ if (generics.length > 0 && VOLO_REMOTE_STREAM_CONTENT.includes(generics[0])) {
+ return true;
+ }
+ }
+
+ return false;
}
function getMethodNameFromAction(action: Action): string {