diff --git a/Directory.Packages.props b/Directory.Packages.props index 9677f6f17b..e8ccc0e7ff 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -113,10 +113,10 @@ - - - - + + + + @@ -128,11 +128,11 @@ - - - - - + + + + + diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index 7ea0fb6708..f5fea908de 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -1890,6 +1890,7 @@ "BiographyContainsUrlValidationMessage": "Biography cannot contain URL.", "CreatePostSEOTitleInfo": "SEO URL is a clean, readable, keyword-rich URL that helps both users and search engines understand what this post is about. Keep it short with 60 characters. SEO titles over 60 characters will be truncated. Use hyphens (-) to separate words (not underscores). Include target keywords near the start. Lowercase only. No stop words unless needed (e.g: \"and\", \"or\", \"the\").", "SEOTitle": "SEO URL", - "InvalidYouTubeUrl": "The URL you entered is not a valid YouTube video link. Please make sure it points to a specific video and try again." + "InvalidYouTubeUrl": "The URL you entered is not a valid YouTube video link. Please make sure it points to a specific video and try again.", + "SelectAnOption": "Select an option" } } diff --git a/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg index 63d1fc9ab6..a829bc28b4 100644 Binary files a/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg and b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg differ diff --git a/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md new file mode 100644 index 0000000000..ddae9a3704 --- /dev/null +++ b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md @@ -0,0 +1,93 @@ +# Solving MongoDB GUID Issues After an ABP Framework Upgrade + +So, you've just upgraded your ABP Framework application to a newer version (like v9.2.0+) and suddenly, your application can't read data from its MongoDB database. You're seeing strange deserialization errors, especially related to `Guid` types. What's going on? + +You've likely run into a classic compatibility issue with the MongoDB .NET driver. + +### The Problem: Legacy vs. Standard GUIDs + +Here's the short version: + +* **Old MongoDB Drivers** (used in older ABP versions) stored `Guid` values in a format called `CSharpLegacy`. +* **New MongoDB Drivers** (v3.0+), now default to a universal `Standard` format. + +When your newly upgraded app tries to read old data, the new driver expects the `Standard` format but finds `CSharpLegacy`. The byte orders don't match, and... boom. Deserialization fails. + +The ABP Framework team has an excellent official guide covering this topic in detail. We highly recommend reading their **[MongoDB Driver 2 to 3 Migration Guide](https://abp.io/docs/latest/release-info/migration-guides/MongoDB-Driver-2-to-3)** for a full understanding. + +Our tip below serves as a fast, application-level fix if you need to get your system back online quickly without performing a full data migration. + +### The Quick Fix: Tell the Driver to Use the Old Format + +Instead of changing your data, you can simply tell the new driver to continue using the old `CSharpLegacy` format for all `Guid` and `Guid?` properties. This provides immediate backward compatibility without touching your database. + +It’s a simple, two-step process. + +#### Step 1: Create a Custom Convention + +First, create this class in your `.MongoDb` project. It tells the serializer how to handle `Guid` types. + +```csharp +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.Serializers; +using System; + +public class LegacyGuidConvention : ConventionBase, IMemberMapConvention +{ + public void Apply(BsonMemberMap memberMap) + { + if (memberMap.MemberType == typeof(Guid)) + { + memberMap.SetSerializer(new GuidSerializer(GuidRepresentation.CSharpLegacy)); + } + else if (memberMap.MemberType == typeof(Guid?)) + { + var guidSerializer = new GuidSerializer(GuidRepresentation.CSharpLegacy); + var nullableGuidSerializer = new NullableSerializer(guidSerializer); + memberMap.SetSerializer(nullableGuidSerializer); + } + } +} +``` + +#### Step 2: Register the Convention at Startup + +Now, register this convention in your `YourProjectMongoDbModule.cs` file. Add this code to the top of the `ConfigureServices` method. This ensures your rule is applied globally as soon as the application starts. + +```csharp +using Volo.Abp.Modularity; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; + +public class YourProjectMongoDbModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + // Fix Start + var conventionPack = new ConventionPack { new LegacyGuidConvention() }; + ConventionRegistry.Register( + "LegacyGuidConvention", + conventionPack, + t => true); // Apply to all types + // Fix End + + // ... Your existing ConfigureServices code + } +} +``` + +### An Alternative to Full Data Migration + +It's important to note that the method described here is an **application-level fix**. It's a fantastic alternative to performing a full data migration, which involves writing scripts to convert every legacy GUID in your database. + +If you are interested in the more permanent, data-centric approach, the ABP.IO community has a detailed guide on [**Migrating MongoDB GUIDs from Legacy to Standard Format**](https://abp.io/community/articles/migrating-mongodb-guids-from-legacy-to-standard-format-mongodb-v2-to-v3-dqwybdtw). + +Our quick fix is ideal for getting a system back online fast or when a database migration is too complex. The full migration is better for long-term standards compliance. Choose the path that best fits your project's needs! + +### That's It! + +Restart your application, and the errors should be gone. Your app can now correctly read its old `Guid` data, and it will continue to write new data in the same legacy format, ensuring consistency. + +This approach is a lifesaver for existing projects, saving you from a risky and time-consuming data migration. For brand-new projects, you might consider starting with the `Standard` representation, but for everything else, this is a clean and effective fix. Happy coding! diff --git a/docs/en/get-started/maui.md b/docs/en/get-started/maui.md index 657a217d44..21497fb2f7 100644 --- a/docs/en/get-started/maui.md +++ b/docs/en/get-started/maui.md @@ -13,9 +13,11 @@ dotnet tool install -g Volo.Abp.Studio.Cli Then use the `abp new` command in an empty folder to create a new solution: ````bash -abp new Acme.MyMauiApp -t maui +abp new Acme.MyMauiApp -t maui --old ```` +> **Note**: Since this startup template is not provided by the new ABP Studio Templates yet, you need to pass the `--old` parameter at the end of the command to use the old CLI & templating system for this startup template. + `Acme.MyMauiApp` is the solution name, like *YourCompany.YourProduct*. You can use single level, two-levels or three-levels naming. ## Solution Structure diff --git a/docs/en/release-info/release-notes.md b/docs/en/release-info/release-notes.md index 4c6bec206e..ce35f8b87c 100644 --- a/docs/en/release-info/release-notes.md +++ b/docs/en/release-info/release-notes.md @@ -8,9 +8,9 @@ Also see the following notes about ABP releases: * [Change logs for ABP pro packages](https://abp.io/pro-releases) -## 9.2 (2025-03-25) +## 9.2 (2025-06-02) -This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/articles/abp-platform-9.2-rc-has-been-released-jpq072nh)** for the v9.2 release. +See the detailed **[blog post / announcement](https://abp.io/community/articles/announcing-abp-9-2-stable-release-061qmtzb)** for the v9.2 release. * Added `ApplicationName` Property to Isolate Background Jobs & Background Workers * Docs Module: Added "Alternative Words" to Filter Items diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs index f63bc2bb88..1a6cb6a9e9 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs @@ -68,7 +68,7 @@ public class AbpBackgroundJobOptions public void AddJob(Type jobType) { - AddJob(new BackgroundJobConfiguration(jobType, GetBackgroundJobName(jobType))); + AddJob(new BackgroundJobConfiguration(jobType, GetBackgroundJobName(BackgroundJobArgsHelper.GetJobArgsType(jobType)))); } public void AddJob(BackgroundJobConfiguration jobConfiguration) diff --git a/npm/ng-packs/packages/components/extensible/src/lib/components/multi-select/extensible-form-multiselect.component.ts b/npm/ng-packs/packages/components/extensible/src/lib/components/multi-select/extensible-form-multiselect.component.ts index d55d55614d..96860b31b4 100644 --- a/npm/ng-packs/packages/components/extensible/src/lib/components/multi-select/extensible-form-multiselect.component.ts +++ b/npm/ng-packs/packages/components/extensible/src/lib/components/multi-select/extensible-form-multiselect.component.ts @@ -1,8 +1,9 @@ import { Component, ChangeDetectionStrategy, forwardRef, input } from '@angular/core'; import { NG_VALUE_ACCESSOR, ControlValueAccessor, ReactiveFormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; -import { ABP, LocalizationModule } from '@abp/ng.core'; +import { ABP, LocalizationPipe } from '@abp/ng.core'; import { FormProp } from '../../models/form-props'; +import { NgxValidateCoreModule } from '@ngx-validate/core'; const EXTENSIBLE_FORM_MULTI_SELECT_CONTROL_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, @@ -19,21 +20,24 @@ const EXTENSIBLE_FORM_MULTI_SELECT_CONTROL_VALUE_ACCESSOR = { - @if (prop().isExtra) { - {{ '::' + option.key | abpLocalization }} - } @else { - {{ option.key }} - } + } `, providers: [EXTENSIBLE_FORM_MULTI_SELECT_CONTROL_VALUE_ACCESSOR], - imports: [LocalizationModule, CommonModule, ReactiveFormsModule], + imports: [LocalizationPipe, CommonModule, ReactiveFormsModule, NgxValidateCoreModule], changeDetection: ChangeDetectionStrategy.OnPush, }) export class ExtensibleFormMultiselectComponent implements ControlValueAccessor { diff --git a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html index 82b3048868..8cd2058699 100644 --- a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html +++ b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html @@ -12,7 +12,7 @@ (nzCheckboxChange)="onCheckboxChange($event)" (nzOnDrop)="onDrop($event)" [nzNoAnimation]="noAnimation" - (nzContextMenu)="dropdowns[$event.node?.key]?.toggle()" + (nzContextMenu)="onContextMenuChange($event)" />
{ + if (key !== dropdownKey && dropdown?.isOpen()) { + dropdown.close(); + } + }); + this.dropdowns[dropdownKey]?.toggle(); + } + setSelectedNode(node: any) { const newSelectedNode = this.findNode(node, this.nodes); this.selectedNode = { ...newSelectedNode }; diff --git a/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html b/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html index b5dc440c76..a81444e56c 100644 --- a/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html +++ b/npm/ng-packs/packages/feature-management/src/lib/components/feature-management/feature-management.component.html @@ -28,6 +28,10 @@
@for (feature of features[group.name]; track feature.id || i; let i = $index) { + @let provider = feature.provider.name; + @let isFeatureDisabled = + provider !== providerName && provider !== defaultProviderName; +
@switch (feature.valueType?.name) { @case (valueTypes.ToggleStringValueType) { @@ -38,11 +42,15 @@ [id]="feature.name" [(ngModel)]="feature.value" (ngModelChange)="onCheckboxClick($event, feature)" + [disabled]="isFeatureDisabled" /> - + - + - +