diff --git a/Directory.Packages.props b/Directory.Packages.props
index 39c98ea5de..b1398663ee 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -38,8 +38,8 @@
-
-
+
+
@@ -174,4 +174,4 @@
-
\ No newline at end of file
+
diff --git a/README.md b/README.md
index ccc31da4b5..dd953a6431 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,18 @@
# ABP Framework
-
-[](https://codecov.io/gh/abpframework/abp)
-[](https://www.nuget.org/packages/Volo.Abp.Core)
-[](https://www.nuget.org/packages/Volo.Abp.Core)
-[](https://docs.abp.io/en/abp/latest/Nightly-Builds)
-[](https://www.nuget.org/packages/Volo.Abp.Core)
-[](https://github.com/abpframework/abp/blob/dev/CODE_OF_CONDUCT.md)
-[](https://cla-assistant.io/abpframework/abp)
-[](https://discord.gg/abp)
-
-ABP Framework is a complete **infrastructure** based on **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**. Check out https://abp.io
+ 🔹 [](https://codecov.io/gh/abpframework/abp) 🔹 [](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [](https://docs.abp.io/en/abp/latest/Nightly-Builds) 🔹
+[](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [](https://github.com/abpframework/abp/blob/dev/CODE_OF_CONDUCT.md) 🔹 [](https://cla-assistant.io/abpframework/abp) 🔹 [](https://discord.gg/abp)
+
+ABP Framework is a complete **infrastructure** based on **ASP.NET Core** that creates **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**.
+
+[](https://abp.io)
+
## Getting Started
-- [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index) is a single-part, quick-start tutorial to build a simple application with the ABP Framework. Start with this tutorial if you want to quickly understand how ABP works.
-- [Getting Started guide](https://docs.abp.io/en/abp/latest/Getting-Started) can be used to create and run ABP based solutions with different options and details.
-- [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1) is a complete tutorial to develop a full stack web application with all aspects of a real-life solution.
+- [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index) is a single-part, quick-start tutorial to build a simple application with the ABP Framework. Start with this tutorial if you want to understand how ABP works quickly.
+- [Getting Started guide](https://docs.abp.io/en/abp/latest/Getting-Started) can be used to create and run ABP-based solutions with different options and details.
+- [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1) is a complete tutorial on developing a full-stack web application with all aspects of a real-life solution.
### Quick Start
@@ -34,28 +30,26 @@ Create a new solution:
> See the [CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all available options.
+
+
### UI Framework Options
+
+
### Database Provider Options
-## The Book: Mastering ABP Framework
-Written by the creator of ABP Framework, this book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques.
-
-* [Buy on Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q)
-* [Buy on Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242)
-* [More details about the book](https://abp.io/books/mastering-abp-framework)
-
-
## What ABP Provides?
ABP provides a **full stack developer experience**.
+
+
### Architecture
@@ -64,30 +58,48 @@ ABP offers a complete, **modular** and **layered** software architecture based o
ABP Framework is suitable for **[microservice solutions](https://docs.abp.io/en/abp/latest/Microservice-Architecture)** as well as monolithic applications.
+
+
### Infrastructure
-There are a lot of features provided by the ABP Framework to achieve real world scenarios easier, like [Event Bus](https://docs.abp.io/en/abp/latest/Event-Bus), [Background Job System](https://docs.abp.io/en/abp/latest/Background-Jobs), [Audit Logging](https://docs.abp.io/en/abp/latest/Audit-Logging), [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing), [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding), [Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering), etc.
+There are a lot of features provided by the ABP Framework to achieve real-world scenarios easier, like [Event Bus](https://docs.abp.io/en/abp/latest/Event-Bus), [Background Job System](https://docs.abp.io/en/abp/latest/Background-Jobs), [Audit Logging](https://docs.abp.io/en/abp/latest/Audit-Logging), [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing), [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding), [Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering), etc.
+
+
+
+### Cross-Cutting Concerns
+
+ABP also simplifies (and even automates wherever possible) cross-cutting concerns and common non-functional requirements like [Exception Handling](https://docs.abp.io/en/abp/latest/Exception-Handling), [Validation](https://docs.abp.io/en/abp/latest/Validation), [Authorization](https://docs.abp.io/en/abp/latest/Authorization), [Localization](https://docs.abp.io/en/abp/latest/Localization), [Caching](https://docs.abp.io/en/abp/latest/Caching), [Dependency Injection](https://docs.abp.io/en/abp/latest/Dependency-Injection), [Setting Management](https://docs.abp.io/en/abp/latest/Settings), etc.
-### Cross Cutting Concerns
-ABP also simplifies (and even automates wherever possible) cross cutting concerns and common non-functional requirements like [Exception Handling](https://docs.abp.io/en/abp/latest/Exception-Handling), [Validation](https://docs.abp.io/en/abp/latest/Validation), [Authorization](https://docs.abp.io/en/abp/latest/Authorization), [Localization](https://docs.abp.io/en/abp/latest/Localization), [Caching](https://docs.abp.io/en/abp/latest/Caching), [Dependency Injection](https://docs.abp.io/en/abp/latest/Dependency-Injection), [Setting Management](https://docs.abp.io/en/abp/latest/Settings), etc.
### Application Modules
ABP is a modular framework and the Application Modules provide **pre-built application functionalities**;
- [**Account**](https://docs.abp.io/en/abp/latest/Modules/Account): Provides UI for the account management and allows user to login/register to the application.
-- **[Identity](https://docs.abp.io/en/abp/latest/Modules/Identity)**: Manages organization units, roles, users and their permissions, based on the Microsoft Identity library.
+- **[Identity](https://docs.abp.io/en/abp/latest/Modules/Identity)**: Manages organization units, roles, users and their permissions based on the Microsoft Identity library.
- [**OpenIddict**](https://docs.abp.io/en/abp/latest/Modules/OpenIddict): Integrates to OpenIddict.
- [**Tenant Management**](https://docs.abp.io/en/abp/latest/Modules/Tenant-Management): Manages tenants for a [multi-tenant](https://docs.abp.io/en/abp/latest/Multi-Tenancy) (SaaS) application.
See the [Application Modules](https://docs.abp.io/en/abp/latest/Modules/Index) document for all pre-built modules.
+
+
### Startup Templates
The [Startup templates](https://docs.abp.io/en/abp/latest/Startup-Templates/Index) are pre-built Visual Studio solution templates. You can create your own solution based on these templates to **immediately start your development**.
-## ABP Community
+
+
+## Mastering ABP Framework Book
+
+This book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques. It is written by the creator and team lead of the ABP Framework. You can buy from [Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q) or [Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242). Find further info about the book at [abp.io/books/mastering-abp-framework](https://abp.io/books/mastering-abp-framework).
+
+
+
+
+
+## The Community
### ABP Community Web Site
@@ -103,28 +115,31 @@ See the [sample projects](https://docs.abp.io/en/abp/latest/Samples/Index) built
### Want to Contribute?
-ABP is a community-driven open source project. See [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index) if you want to be a part of this project.
+ABP is a community-driven open-source project. See [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index) if you want to participate in this project.
+
+
## Official Links
-* Main Web Site
- * Get Started
- * Features
-* Documentation
-* Samples
-* Blog
-* Community
-* Stack overflow
-* Twitter
+* [Home Website](https://abp.io)
+ * [Get Started](https://abp.io/get-started)
+ * [Features](https://abp.io/features)
+* [Documents](https://docs.abp.io/)
+* [Samples](https://docs.abp.io/en/abp/latest/Samples/Index)
+* [Blog](https://blog.abp.io/)
+* [Community](https://community.abp.io/)
+* [Stackoverflow](https://stackoverflow.com/questions/tagged/abp)
+* [Twitter](https://twitter.com/abpframework)
+
+
+
+## Support ABP
-## Support the ABP Framework
+GitHub repository stars are an important indicator of popularity and the size of the community. If you like ABP Framework, support us by clicking the star :star: on the repository.
-Love ABP Framework? **Please give a star** to this repository :star:
-## Discord Channel
-You can use this link to join the ABP Community Discord Server: https://discord.gg/abp
+## Discord Server
-## ABP Commercial
+We have a Discord server where you can chat with other ABP users. Share your ideas, report technical issues, showcase your creations, share the tips that worked for you and catch up with the latest news and announcements about ABP Framework. Join 👉 https://discord.gg/abp.
-See also [ABP Commercial](https://commercial.abp.io/) if you are looking for pre-built application modules, professional themes, code generation tooling and premium support for the ABP Framework.
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
index c667591160..cbe186e97c 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
@@ -632,6 +632,7 @@
"Menu:ReportsMenu": "Reports",
"Permission:HeroSections": "Hero Sections",
"RedirectLink": "Redirect link",
- "HeroSectionsDeletionConfirmationMessage": "Are you sure you want to delete the hero section?"
+ "HeroSectionsDeletionConfirmationMessage": "Are you sure you want to delete the hero section?",
+ "AbpStudioName": "Abp Studio name"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
index 347b18ce4b..dc59234777 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
@@ -59,7 +59,7 @@
"MilestoneErrorMessage": "Couldn't get the current milestone details from Github.",
"QuestionItemErrorMessage": "Couldn't get the latest question details from Stackoverflow.",
"Oops": "Oops!",
- "CreatePostSuccessMessage": "The Post has been successfully submitted. It will be published once it has been reviewed by the site admin.",
+ "CreatePostSuccessMessage": "Your post has been successfully submitted. It will be published after review by the site administrator.",
"ChooseCoverImage": "Choose a cover image...",
"CoverImage": "Cover Image",
"ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
index ef07928c83..78231bb1af 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
@@ -16,7 +16,7 @@
"Title": "Title",
"CreationTime": "Creation time",
"Save": "Save",
- "SameUrlAlreadyExist": "Same url already exists if you want to add this post, you should change the url!",
+ "SameUrlAlreadyExist": "Same URL already exists! You must change the URL!",
"UrlIsNotValid": "Url is not valid.",
"UrlNotFound": "Url not found.",
"UrlContentNotFound": "Url content not found.",
@@ -33,7 +33,7 @@
"FeatureRequest": "Feature Request",
"CreatePostTitleInfo": "Title of the post to be shown on the post list.",
"CreatePostSummaryInfo": "A short summary of the post to be shown on the post list. Maximum length: {0}",
- "CreatePostCoverInfo": "For creating an effective post, add a cover photo. Upload 16:9 aspect ratio pictures for the best view. Maximum file size: 1MB.",
+ "CreatePostCoverInfo": "To create an effective post, add a cover photo. Upload 16:9 aspect ratio pictures for the best view. Maximum file size is 1MB.",
"ThisExtensionIsNotAllowed": "This extension is not allowed.",
"TheFileIsTooLarge": "The file is too large.",
"GoToThePost": "Go to the Post",
@@ -56,7 +56,7 @@
"MilestoneErrorMessage": "Could not get the current milestone details from Github.",
"QuestionItemErrorMessage": "Could not get the latest question details from Stackoverflow.",
"Oops": "Oops!",
- "CreatePostSuccessMessage": "The Post has been successfully submitted. It will be published after a review from the site admin.",
+ "CreatePostSuccessMessage": "Your post has been successfully submitted. It will be published after review by the site administrator.",
"Browse": "Browse",
"CoverImage": "Cover Image",
"ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!",
@@ -125,7 +125,7 @@
"YoutubeVideoSubmitStepTwo": "2. Submit the video URL using the form.",
"YoutubeVideoSubmitStepThree": "3. Visitors will be able to watch your video content directly on this website.",
"ExternalContent": "External Content",
- "ExternalContentSubmitStepOne": "1. Create a content on any public platform (Medium, your own blog or anywhere you like).",
+ "ExternalContentSubmitStepOne": "1. Create content on any public platform (Medium, your own blog or anywhere you like).",
"ExternalContentSubmitStepTwo": "2. Submit your content URL using the form.",
"ExternalContentSubmitStepThree": "3. Visitors are redirected to the content on the original website.",
"ChooseYourContentType": "Please choose the way you want to add your content.",
@@ -135,12 +135,12 @@
"GitHubUserNameValidationMessage": "Your Github username can not include whitespace, please make sure your Github username is correct.",
"PersonalSiteUrlValidationMessage": "Your personal site URL can not include whitespace, please make sure your personal site URL is correct.",
"TwitterUserNameValidationMessage": "Your Twitter username can not include whitespace, please make sure your Twitter username is correct.",
- "LinkedinUrlValidationMessage": "Your Linkedin URL can not include whitespace, please make sure your Linkedin URL is correct.",
+ "LinkedinUrlValidationMessage": "Your LinkedIn URL can not include whitespace, please make sure your LinkedIn URL is correct.",
"NoPostsFound": "No posts found!",
"SearchInPosts": "Search in posts...",
"MinimumSearchContent": "You must enter at least 3 characters!",
"Volo.AbpIo.Domain:060001": "Source URL(\"{PostUrl}\") is not Github URL",
- "Volo.AbpIo.Domain:060002": "Post Content is not available from Github(\"{PostUrl}\") resource.",
+ "Volo.AbpIo.Domain:060002": "Post Content is not available from GitHub(\"{PostUrl}\") resource.",
"Volo.AbpIo.Domain:060003": "No post content found!",
"SeeMore": "See More",
"JoinTheABPCommunity": "Join the ABP Community",
@@ -171,14 +171,14 @@
"Discord_Page_Announce": "We are happy to announce ABP Community Discord Server!",
"Discord_Page_Description_1": "ABP Community has been growing since day one. We wanted to take it to the next step by creating an official ABP Discord server so the ABP Community can interact with each other using the wonders of instant messaging.",
"Discord_Page_Description_2": "ABP Community Discord Server is the place where you can showcase your creations using ABP Framework, share the tips that worked for you, catch up with the latest news and announcements about ABP Framework, just chat with community members to exchange ideas, and have fun!",
- "Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team is present on the server to monitor.",
+ "Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team present on the server to monitor.",
"Discord_Page_JoinToServer": "Join ABP Discord Server",
"Events_Page_MetaTitle": "ABP Community Events",
"Events_Page_MetaDescription": "The live shows, hosted by the ABP Team, are casual sessions full of community content, demos, Q&A, and discussions around what's happening in ABP.",
"Events_Page_Title": "ABP Community Talks",
"Members_Page_WritingFromUser": "Read writing from {0} on ABP Community.",
"Post_Create_Page_MetaTitle": "New Post",
- "Post_Create_Page_MetaDescription": "Create your post for sharing your experiences about ABP framework and contributing the ABP Community.",
+ "Post_Create_Page_MetaDescription": "Create your post for sharing your experiences about the ABP framework and contributing to the ABP Community.",
"Post_Create_Page_CreateNewPost": "Create New Post",
"Post_Index_Page_MetaDescription": "ABP Community's purpose is to create a contribution environment for developers who use the ABP framework.",
"Layout_Title": "{0} | ABP Community",
@@ -193,7 +193,7 @@
"AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework",
"CommunitySlogan": "A unique community platform for ABP Lovers",
"RaffleIsNotActive": "Raffle is not active",
- "YouAreAlreadyJoinedToThisRaffle": "You already joined to this raffle!",
+ "YouAreAlreadyJoinedToThisRaffle": "You already joined this raffle!",
"InvalidSubscriptionCode": "Invalid subscription code",
"Raffle:{0}": "Raffle: {0}",
"Join": "Join",
@@ -266,4 +266,4 @@
"DailyPostCreateLimitation": "You have reached the daily post creation limit. You can create a new post in {0}.",
"YourAccountDisabled": "Your user account is disabled!"
}
-}
\ No newline at end of file
+}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
index b8972317cf..0dc5f525b1 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
@@ -158,7 +158,7 @@
"IndexPageHeroSection": "open sourceWeb Application Frameworkfor asp.net core",
"UiFramework": "UI框架",
"EmailAddress": "电子邮件地址",
- "Mobile": "移动电话",
+ "Mobile": "选择移动应用程序框架",
"ReactNative": "React Native",
"Strong": "强大",
"Complete": "完整",
@@ -476,4 +476,4 @@
"ABPVideoCoursesPageDescription": "通过ABP团队创建的视频课程学习ABP框架的基础知识。在本视频系列中,您将学习ABP框架的基本主题。每个视频上的数字都是根据学习流程编写的。",
"ABPVideoCoursesTitle": "ABP 基本视频"
}
-}
\ No newline at end of file
+}
diff --git a/docs/en/CLI.md b/docs/en/CLI.md
index e0eede9241..cb16fb2897 100644
--- a/docs/en/CLI.md
+++ b/docs/en/CLI.md
@@ -131,7 +131,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
- * `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes:
+ * `--theme`: Specifies the theme. Default theme is `leptonx-lite`. Available themes:
* `leptonx-lite`: [LeptonX Lite Theme](Themes/LeptonXLite/AspNetCore.md).
* `basic`: [Basic Theme](UI/AspNetCore/Basic-Theme.md).
* **`module`**: [Module template](Startup-Templates/Module.md). Additional options:
@@ -147,7 +147,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
- * `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes:
+ * `--theme`: Specifies the theme. Default theme is `leptonx-lite`. Available themes:
* `leptonx-lite`: [LeptonX Lite Theme](Themes/LeptonXLite/AspNetCore.md).
* `basic`: [Basic Theme](UI/AspNetCore/Basic-Theme.md).
* **`maui`**: .NET MAUI. A minimalist .NET MAUI application will be created if you specify this option.
diff --git a/docs/en/Data-Filtering.md b/docs/en/Data-Filtering.md
index 830979e710..4706912fe7 100644
--- a/docs/en/Data-Filtering.md
+++ b/docs/en/Data-Filtering.md
@@ -217,17 +217,14 @@ protected override bool ShouldFilterEntity(IMutableEntityType entityTyp
return base.ShouldFilterEntity(entityType);
}
-protected override Expression> CreateFilterExpression()
+protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder)
{
- var expression = base.CreateFilterExpression();
+ var expression = base.CreateFilterExpression(modelBuilder);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{
- Expression> isActiveFilter =
- e => !IsActiveFilterEnabled || EF.Property(e, "IsActive");
- expression = expression == null
- ? isActiveFilter
- : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
+ Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive");
+ expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
}
return expression;
@@ -251,6 +248,78 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
}
````
+#### Using User-defined function mapping for global filters
+
+Using [User-defined function mapping](https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping) for global filters will gain performance improvements.
+
+To use this feature, you need to change your DbContext like below:
+
+````csharp
+protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled() ?? false;
+
+protected override bool ShouldFilterEntity(IMutableEntityType entityType)
+{
+ if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
+ {
+ return true;
+ }
+
+ return base.ShouldFilterEntity(entityType);
+}
+
+protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder)
+{
+ var expression = base.CreateFilterExpression(modelBuilder);
+
+ if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
+ {
+ Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive");
+
+ if (UseDbFunction())
+ {
+ isActiveFilter = e => IsActiveFilter(((IIsActive)e).IsActive, true);
+
+ var abpEfCoreCurrentDbContext = this.GetService();
+ modelBuilder.HasDbFunction(typeof(MyProjectNameDbContext).GetMethod(nameof(IsActiveFilter))!)
+ .HasTranslation(args =>
+ {
+ // (bool isActive, bool boolParam)
+ var isActive = args[0];
+ var boolParam = args[1];
+
+ if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled() == true)
+ {
+ // isActive == true
+ return new SqlBinaryExpression(
+ ExpressionType.Equal,
+ isActive,
+ new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping),
+ boolParam.Type,
+ boolParam.TypeMapping);
+ }
+
+ // empty where sql
+ return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping);
+ });
+ }
+
+ expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
+ }
+
+ return expression;
+}
+
+public static bool IsActiveFilter(bool isActive, bool boolParam)
+{
+ throw new NotSupportedException(AbpEfCoreDataFilterDbFunctionMethods.NotSupportedExceptionMessage);
+}
+
+public override string GetCompiledQueryCacheKey()
+{
+ return $"{base.GetCompiledQueryCacheKey()}:{IsActiveFilterEnabled}";
+}
+````
+
### MongoDB
ABP abstracts the `IMongoDbRepositoryFilterer` interface to implement data filtering for the [MongoDB Integration](MongoDB.md), it works only if you use the repositories properly. Otherwise, you should manually filter the data.
diff --git a/docs/en/Local-Event-Bus.md b/docs/en/Local-Event-Bus.md
index 81c0c5a171..5c5d967f5f 100644
--- a/docs/en/Local-Event-Bus.md
+++ b/docs/en/Local-Event-Bus.md
@@ -235,6 +235,13 @@ Pre-build events are published when you save changes to the database;
* For EF Core, they are published on `DbContext.SaveChanges`.
* For MongoDB, they are published when you call repository's `InsertAsync`, `UpdateAsync` or `DeleteAsync` methods (since MongoDB has not a change tracking system).
+#### AbpEntityChangeOptions
+
+There is a `PublishEntityUpdatedEventWhenNavigationChanges` option in the `AbpEntityChangeOptions` class with a default value of `true`.
+If you set it to `false`, the `EntityUpdatedEventData` will not be published when a navigation property changes.
+
+> This option is only used for the EF Core.
+
## See Also
* [Distributed Event Bus](Distributed-Event-Bus.md)
diff --git a/docs/en/Modules/Cms-Kit/Comments.md b/docs/en/Modules/Cms-Kit/Comments.md
index ddd39fc675..4eca4cb93d 100644
--- a/docs/en/Modules/Cms-Kit/Comments.md
+++ b/docs/en/Modules/Cms-Kit/Comments.md
@@ -80,6 +80,12 @@ You can also view and manage replies on this page.

+## Settings
+
+You can configure the approval status of comments using the "Comment" tab under the "Cms" section on the Settings page. When this feature is enabled, you can approve and reject comments. In this way, users can only see the comments that you approve. By default, this feature is set to "false."
+
+
+
## Internals
### Domain Layer
diff --git a/docs/en/UI/AspNetCore/Static-JavaScript-Proxies.md b/docs/en/UI/AspNetCore/Static-JavaScript-Proxies.md
index fffc53cf83..2ad46a2f9d 100644
--- a/docs/en/UI/AspNetCore/Static-JavaScript-Proxies.md
+++ b/docs/en/UI/AspNetCore/Static-JavaScript-Proxies.md
@@ -66,7 +66,7 @@ acme.bookStore.authors.author.get = function(id, ajaxParams) {
};
````
-> `generate-proxy` command generates proxies for only the APIs you've defined in your application (assumes `app` as the module name). If you are developing a modular application, you can specify the `-m` (or `--module`) parameter to specify the module you want to generate proxies. See the *generate-proxy* section in the [ABP CLI](../CLI.md) documentation for other options.
+> `generate-proxy` command generates proxies for only the APIs you've defined in your application (assumes `app` as the module name). If you are developing a modular application, you can specify the `-m` (or `--module`) parameter to specify the module you want to generate proxies. See the *generate-proxy* section in the [ABP CLI](../../CLI.md) documentation for other options.
### Using the Proxy Functions
@@ -154,4 +154,4 @@ See the [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) documentation for all
* [Dynamic JavaScript API Client Proxies](Dynamic-JavaScript-Proxies.md)
* [Auto API Controllers](../../API/Auto-API-Controllers.md)
-* [Web Application Development Tutorial](../../Tutorials/Part-1.md)
\ No newline at end of file
+* [Web Application Development Tutorial](../../Tutorials/Part-1.md)
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index d30322e277..d45a304039 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -1165,6 +1165,10 @@
"text": "Ellipsis",
"path": "UI/Angular/Ellipsis-Directive.md"
},
+ {
+ "text": "Projection Strategy",
+ "path": "UI/Angular/Projection-Strategy.md"
+ },
{
"text": "Context Strategy",
"path": "UI/Angular/Context-Strategy.md"
diff --git a/docs/en/images/book-mastering-abp-framework.png b/docs/en/images/book-mastering-abp-framework.png
index c2a98a02a5..7a25f583d3 100644
Binary files a/docs/en/images/book-mastering-abp-framework.png and b/docs/en/images/book-mastering-abp-framework.png differ
diff --git a/docs/en/images/cmskit-module-comments-settings.png b/docs/en/images/cmskit-module-comments-settings.png
new file mode 100644
index 0000000000..3c5a60d571
Binary files /dev/null and b/docs/en/images/cmskit-module-comments-settings.png differ
diff --git a/docs/en/images/db-options.png b/docs/en/images/db-options.png
index 368377f5a3..0c581c4883 100644
Binary files a/docs/en/images/db-options.png and b/docs/en/images/db-options.png differ
diff --git a/docs/en/images/ddd-microservice-simple.png b/docs/en/images/ddd-microservice-simple.png
index f4195bff9d..6588c2c753 100644
Binary files a/docs/en/images/ddd-microservice-simple.png and b/docs/en/images/ddd-microservice-simple.png differ
diff --git a/docs/en/images/ui-options.png b/docs/en/images/ui-options.png
index 6f0d19b73e..6affab9d21 100644
Binary files a/docs/en/images/ui-options.png and b/docs/en/images/ui-options.png differ
diff --git a/docs/zh-Hans/Data-Filtering.md b/docs/zh-Hans/Data-Filtering.md
index 8a43ad93b1..01c4590761 100644
--- a/docs/zh-Hans/Data-Filtering.md
+++ b/docs/zh-Hans/Data-Filtering.md
@@ -166,17 +166,14 @@ protected override bool ShouldFilterEntity(IMutableEntityType entityTyp
return base.ShouldFilterEntity(entityType);
}
-protected override Expression> CreateFilterExpression()
+protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder)
{
- var expression = base.CreateFilterExpression();
+ var expression = base.CreateFilterExpression(modelBuilder);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
{
- Expression> isActiveFilter =
- e => !IsActiveFilterEnabled || EF.Property(e, "IsActive");
- expression = expression == null
- ? isActiveFilter
- : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
+ Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive");
+ expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
}
return expression;
@@ -186,6 +183,78 @@ protected override Expression> CreateFilterExpression DataFilter?.IsEnabled() ?? false;
+
+protected override bool ShouldFilterEntity(IMutableEntityType entityType)
+{
+ if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
+ {
+ return true;
+ }
+
+ return base.ShouldFilterEntity(entityType);
+}
+
+protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder)
+{
+ var expression = base.CreateFilterExpression(modelBuilder);
+
+ if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity)))
+ {
+ Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive");
+
+ if (UseDbFunction())
+ {
+ isActiveFilter = e => IsActiveFilter(((IIsActive)e).IsActive, true);
+
+ var abpEfCoreCurrentDbContext = this.GetService();
+ modelBuilder.HasDbFunction(typeof(MyProjectNameDbContext).GetMethod(nameof(IsActiveFilter))!)
+ .HasTranslation(args =>
+ {
+ // (bool isActive, bool boolParam)
+ var isActive = args[0];
+ var boolParam = args[1];
+
+ if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled() == true)
+ {
+ // isActive == true
+ return new SqlBinaryExpression(
+ ExpressionType.Equal,
+ isActive,
+ new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping),
+ boolParam.Type,
+ boolParam.TypeMapping);
+ }
+
+ // empty where sql
+ return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping);
+ });
+ }
+
+ expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter);
+ }
+
+ return expression;
+}
+
+public static bool IsActiveFilter(bool isActive, bool boolParam)
+{
+ throw new NotSupportedException(AbpEfCoreDataFilterDbFunctionMethods.NotSupportedExceptionMessage);
+}
+
+public override string GetCompiledQueryCacheKey()
+{
+ return $"{base.GetCompiledQueryCacheKey()}:{IsActiveFilterEnabled}";
+}
+````
+
### MongoDB
ABP抽象了 `IMongoDbRepositoryFilterer` 接口为[MongoDB 集成](MongoDB.md)实现数据过滤, 只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据.
diff --git a/docs/zh-Hans/Local-Event-Bus.md b/docs/zh-Hans/Local-Event-Bus.md
index 7a842a9e98..ebdb3f20a6 100644
--- a/docs/zh-Hans/Local-Event-Bus.md
+++ b/docs/zh-Hans/Local-Event-Bus.md
@@ -211,6 +211,14 @@ namespace AbpDemo
* 对于 EF Core, 他们在 `DbContext.SaveChanges` 发布.
* 对于 MongoDB, 在你调用仓储的 `InsertAsync`, `UpdateAsync` 或 `DeleteAsync` 方法发布(因为MongoDB没有更改追踪系统).
+
+#### AbpEntityChangeOptions
+
+`AbpEntityChangeOptions`类中有一个`PublishEntityUpdatedEventWhenNavigationChanges`选项,默认值为`true`。
+如果将其设置为`false`,则当导航属性更改时,将不会发布`EntityUpdatedEventData`事件。
+
+> 此选项仅用于EF Core
+
## 另请参阅
* [分布式事件总线](Distributed-Event-Bus.md)
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
index e518b54a95..b54c90abf8 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
+using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling;
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
index 42d354dc5d..3e186b9d0f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
@@ -2,7 +2,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.AspNetCore.Components.DependencyInjection;
-using Volo.Abp.AspNetCore.Components.Server;
+using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.Modularity;
using Volo.Abp.UI;
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebOptions.cs
index 2f5b8ca886..7ea40e6170 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebOptions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebOptions.cs
@@ -1,4 +1,4 @@
-namespace Volo.Abp.AspNetCore.Components.Server;
+namespace Volo.Abp.AspNetCore.Components.Web;
public class AbpAspNetCoreComponentsWebOptions
{
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
index 25a57616e4..b4ea3cb50c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
@@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
-using Volo.Abp.AspNetCore.Components.Server;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Components.Web.ExceptionHandling;
using Volo.Abp.AspNetCore.Components.Web.Security;
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ClientProxyExceptionEventHandler.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ClientProxyExceptionEventHandler.cs
index d6a4257496..a4d615123c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ClientProxyExceptionEventHandler.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/ClientProxyExceptionEventHandler.cs
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
-using Volo.Abp.AspNetCore.Components.Server;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs
index 91bc360f72..0d70ae6aa9 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerBase.cs
@@ -22,8 +22,9 @@ public abstract class BackgroundWorkerBase : IBackgroundWorker
protected ILogger Logger => LazyServiceProvider.LazyGetService(provider => LoggerFactory?.CreateLogger(GetType().FullName!) ?? NullLogger.Instance);
- protected CancellationTokenSource StoppingTokenSource { get; }
- protected CancellationToken StoppingToken { get; }
+ protected CancellationTokenSource StoppingTokenSource { get; set; }
+
+ protected CancellationToken StoppingToken { get; set; }
public BackgroundWorkerBase()
{
diff --git a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs
index a3cd7372a6..2773b88bed 100644
--- a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs
+++ b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs
@@ -46,6 +46,12 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions
public static string? GetDateEditInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property)
{
+ var dataFormatString = property.GetDataFormatStringOrNull();
+ if (dataFormatString != null)
+ {
+ return dataFormatString;
+ }
+
if (property.IsDate())
{
return "{0:yyyy-MM-dd}";
@@ -59,6 +65,14 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions
return null;
}
+ public static string? GetDataFormatStringOrNull(this IBasicObjectExtensionPropertyInfo property)
+ {
+ return property
+ .Attributes
+ .OfType()
+ .FirstOrDefault()?.DataFormatString;
+ }
+
public static string? GetTextInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object? value)
{
if (value == null)
diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/UiPageProgress.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/UiPageProgress.razor.cs
index 8e494cba2f..ad0f996654 100644
--- a/framework/src/Volo.Abp.BlazoriseUI/Components/UiPageProgress.razor.cs
+++ b/framework/src/Volo.Abp.BlazoriseUI/Components/UiPageProgress.razor.cs
@@ -7,7 +7,7 @@ namespace Volo.Abp.BlazoriseUI.Components;
public partial class UiPageProgress : ComponentBase, IDisposable
{
- protected PageProgress PageProgressRef { get; set; } = default!;
+ protected PageProgress? PageProgressRef { get; set; }
protected int? Percentage { get; set; }
@@ -33,8 +33,11 @@ public partial class UiPageProgress : ComponentBase, IDisposable
Visible = e.Percentage == null || (e.Percentage >= 0 && e.Percentage <= 100);
Color = GetColor(e.Options.Type);
- await PageProgressRef.SetValueAsync(e.Percentage);
-
+ if(PageProgressRef != null)
+ {
+ await PageProgressRef.SetValueAsync(e.Percentage);
+ }
+
await InvokeAsync(StateHasChanged);
}
diff --git a/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs b/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs
index 768a9ba171..c5ae0b5393 100644
--- a/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs
+++ b/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
@@ -19,6 +20,8 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
protected static readonly string SlidingExpirationKey;
protected static readonly string DataKey;
protected static readonly long NotPresent;
+ protected static readonly RedisValue[] HashMembersAbsoluteExpirationSlidingExpirationData;
+ protected static readonly RedisValue[] HashMembersAbsoluteExpirationSlidingExpiration;
private readonly static FieldInfo SetScriptField;
private readonly static FieldInfo RedisDatabaseField;
@@ -27,29 +30,29 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
private readonly static MethodInfo MapMetadataMethod;
private readonly static MethodInfo GetAbsoluteExpirationMethod;
private readonly static MethodInfo GetExpirationInSecondsMethod;
+ private readonly static MethodInfo OnRedisErrorMethod;
- protected IDatabase RedisDatabase => GetRedisDatabase()!;
- private IDatabase? _redisDatabase;
-
- protected string Instance { get; }
+ protected RedisKey InstancePrefix { get; }
static AbpRedisCache()
{
var type = typeof(RedisCache);
- RedisDatabaseField = Check.NotNull(type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic), nameof(RedisDatabaseField))!;
+ RedisDatabaseField = Check.NotNull(type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic), nameof(RedisDatabaseField));
- SetScriptField = Check.NotNull(type.GetField("_setScript", BindingFlags.Instance | BindingFlags.NonPublic), nameof(SetScriptField))!;
+ SetScriptField = Check.NotNull(type.GetField("_setScript", BindingFlags.Instance | BindingFlags.NonPublic), nameof(SetScriptField));
- ConnectMethod = Check.NotNull(type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectMethod))!;
+ ConnectMethod = Check.NotNull(type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectMethod));
- ConnectAsyncMethod = Check.NotNull(type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectAsyncMethod))!;
+ ConnectAsyncMethod = Check.NotNull(type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic), nameof(ConnectAsyncMethod));
- MapMetadataMethod = Check.NotNull(type.GetMethod("MapMetadata", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static), nameof(MapMetadataMethod))!;
+ MapMetadataMethod = Check.NotNull(type.GetMethod("MapMetadata", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static), nameof(MapMetadataMethod));
- GetAbsoluteExpirationMethod = Check.NotNull(type.GetMethod("GetAbsoluteExpiration", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetAbsoluteExpirationMethod))!;
+ GetAbsoluteExpirationMethod = Check.NotNull(type.GetMethod("GetAbsoluteExpiration", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetAbsoluteExpirationMethod));
- GetExpirationInSecondsMethod = Check.NotNull(type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetExpirationInSecondsMethod))!;
+ GetExpirationInSecondsMethod = Check.NotNull(type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic), nameof(GetExpirationInSecondsMethod));
+
+ OnRedisErrorMethod = Check.NotNull(type.GetMethod("OnRedisError", BindingFlags.Instance | BindingFlags.NonPublic), nameof(OnRedisErrorMethod));
AbsoluteExpirationKey = type.GetField("AbsoluteExpirationKey", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.ToString()!;
@@ -58,32 +61,30 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems
DataKey = type.GetField("DataKey", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.ToString()!;
NotPresent = type.GetField("NotPresent", BindingFlags.Static | BindingFlags.NonPublic)!.GetValue(null)!.To();
+
+ HashMembersAbsoluteExpirationSlidingExpirationData = [AbsoluteExpirationKey, SlidingExpirationKey, DataKey];
+
+ HashMembersAbsoluteExpirationSlidingExpiration = [AbsoluteExpirationKey, SlidingExpirationKey];
}
public AbpRedisCache(IOptions optionsAccessor)
: base(optionsAccessor)
{
- Instance = optionsAccessor.Value.InstanceName ?? string.Empty;
- }
-
- protected virtual void Connect()
- {
- if (GetRedisDatabase() != null)
+ var instanceName = optionsAccessor.Value.InstanceName;
+ if (!string.IsNullOrEmpty(instanceName))
{
- return;
+ InstancePrefix = (RedisKey)Encoding.UTF8.GetBytes(instanceName);
}
+ }
- ConnectMethod.Invoke(this, Array.Empty