diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln
index 7d6295555..d1d055c97 100644
--- a/aspnet-core/LINGYUN.MicroService.All.sln
+++ b/aspnet-core/LINGYUN.MicroService.All.sln
@@ -573,6 +573,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TextTemplating.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TextTemplating.Razor", "modules\text-templating\LINGYUN.Abp.TextTemplating.Razor\LINGYUN.Abp.TextTemplating.Razor.csproj", "{5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.PermissionManagement.Application.Contracts", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application.Contracts\LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj", "{35D17AF3-FDCD-4704-969C-E82DBCC0A232}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.PermissionManagement.Application", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application\LINGYUN.Abp.PermissionManagement.Application.csproj", "{984F481B-79FF-4825-917B-944F151694BC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.PermissionManagement.HttpApi", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.HttpApi\LINGYUN.Abp.PermissionManagement.HttpApi.csproj", "{B12BECC4-8A58-4DBD-A5CD-144A507972BB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "feature-management", "feature-management", "{12896A3F-5F7E-4192-8A58-E1D2527109D1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.Application.Contracts", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application.Contracts\LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj", "{F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.Application", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application\LINGYUN.Abp.FeatureManagement.Application.csproj", "{4E8DA436-8FAF-4028-8A0C-E4EEB3615972}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.HttpApi", "modules\feature-management\LINGYUN.Abp.FeatureManagement.HttpApi\LINGYUN.Abp.FeatureManagement.HttpApi.csproj", "{405694F8-0051-4DAE-A991-919FAC36C7DA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1459,6 +1473,30 @@ Global
{5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Release|Any CPU.Build.0 = Release|Any CPU
+ {984F481B-79FF-4825-917B-944F151694BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {984F481B-79FF-4825-917B-944F151694BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {984F481B-79FF-4825-917B-944F151694BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {984F481B-79FF-4825-917B-944F151694BC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Release|Any CPU.Build.0 = Release|Any CPU
+ {405694F8-0051-4DAE-A991-919FAC36C7DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {405694F8-0051-4DAE-A991-919FAC36C7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {405694F8-0051-4DAE-A991-919FAC36C7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {405694F8-0051-4DAE-A991-919FAC36C7DA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1735,6 +1773,13 @@ Global
{6AC6AC37-0163-4EF2-A49C-2E0B87F73AE9} = {B1AC656F-8F4C-43D5-B5A0-CCF5F119EA44}
{E2019836-1C67-47E4-B3AF-D62F4AFC7679} = {ABD89F39-62D9-439E-8662-BE4F36BFA04F}
{5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2} = {ABD89F39-62D9-439E-8662-BE4F36BFA04F}
+ {35D17AF3-FDCD-4704-969C-E82DBCC0A232} = {CC362C67-6FC1-42B3-A130-8120AA8D790C}
+ {984F481B-79FF-4825-917B-944F151694BC} = {CC362C67-6FC1-42B3-A130-8120AA8D790C}
+ {B12BECC4-8A58-4DBD-A5CD-144A507972BB} = {CC362C67-6FC1-42B3-A130-8120AA8D790C}
+ {12896A3F-5F7E-4192-8A58-E1D2527109D1} = {C5CAD011-DF84-4914-939C-0C029DCEF26F}
+ {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012} = {12896A3F-5F7E-4192-8A58-E1D2527109D1}
+ {4E8DA436-8FAF-4028-8A0C-E4EEB3615972} = {12896A3F-5F7E-4192-8A58-E1D2527109D1}
+ {405694F8-0051-4DAE-A991-919FAC36C7DA} = {12896A3F-5F7E-4192-8A58-E1D2527109D1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718}
diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
index 6bc440a13..7c3928366 100644
--- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln
+++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
@@ -287,7 +287,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.Pe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.CultureMap", "modules\localization\LINGYUN.Abp.Localization.CultureMap\LINGYUN.Abp.Localization.CultureMap.csproj", "{86ED8028-5533-4B5D-8594-C09929F2A553}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization", "localization", "{C056C11F-EC74-4720-ACEA-D4C57DC4736F}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization-management", "localization-management", "{C056C11F-EC74-4720-ACEA-D4C57DC4736F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Mvc.Localization", "modules\localization\LINGYUN.Abp.AspNetCore.Mvc.Localization\LINGYUN.Abp.AspNetCore.Mvc.Localization.csproj", "{A09032AD-D895-4D83-8D3D-67FF3285F7A6}"
EndProject
@@ -444,6 +444,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.MicroService.Internal.ApiGateway", "..\gateways\internal\LINGYUN.MicroService.Internal.ApiGateway\src\LINGYUN.MicroService.Internal.ApiGateway\LINGYUN.MicroService.Internal.ApiGateway.csproj", "{21878B72-9801-41CE-88CD-7195714AE9BA}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "feature-management", "feature-management", "{97C36EF3-805E-4B93-9AF6-C1E22AA583B1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "permissions-management", "permissions-management", "{99CB6AD9-92E8-4B9B-99E3-28404AA41655}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FeatureManagement.Application.Contracts", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application.Contracts\LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj", "{2263600B-30CB-4188-925D-92F12F904163}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FeatureManagement.Application", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application\LINGYUN.Abp.FeatureManagement.Application.csproj", "{2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FeatureManagement.HttpApi", "modules\feature-management\LINGYUN.Abp.FeatureManagement.HttpApi\LINGYUN.Abp.FeatureManagement.HttpApi.csproj", "{C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.PermissionManagement.Application.Contracts", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application.Contracts\LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj", "{FAD86432-6A95-47DE-8E3A-FC2101753C52}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.PermissionManagement.Application", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application\LINGYUN.Abp.PermissionManagement.Application.csproj", "{5F278E32-3A2A-4654-BD3C-B183301382FB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.PermissionManagement.HttpApi", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.HttpApi\LINGYUN.Abp.PermissionManagement.HttpApi.csproj", "{1DB57C74-1C40-4414-B968-937C3C1C157E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1158,6 +1174,30 @@ Global
{21878B72-9801-41CE-88CD-7195714AE9BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21878B72-9801-41CE-88CD-7195714AE9BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21878B72-9801-41CE-88CD-7195714AE9BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2263600B-30CB-4188-925D-92F12F904163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2263600B-30CB-4188-925D-92F12F904163}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2263600B-30CB-4188-925D-92F12F904163}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2263600B-30CB-4188-925D-92F12F904163}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5F278E32-3A2A-4654-BD3C-B183301382FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F278E32-3A2A-4654-BD3C-B183301382FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F278E32-3A2A-4654-BD3C-B183301382FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F278E32-3A2A-4654-BD3C-B183301382FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1DB57C74-1C40-4414-B968-937C3C1C157E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1DB57C74-1C40-4414-B968-937C3C1C157E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1DB57C74-1C40-4414-B968-937C3C1C157E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1DB57C74-1C40-4414-B968-937C3C1C157E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1375,6 +1415,14 @@ Global
{E2BA59EA-769B-4D5B-8032-CB9682D0D73A} = {0D69B63D-F082-4D57-9FF0-355642C56993}
{5F0926F3-463D-445B-9746-0A037DC431F9} = {42F31C68-B8B2-4BE0-9AD0-A7DFA6092629}
{21878B72-9801-41CE-88CD-7195714AE9BA} = {B4247B78-34BC-4A3F-91A4-661F7DCD6E10}
+ {97C36EF3-805E-4B93-9AF6-C1E22AA583B1} = {0B58AA48-665A-443F-A6A8-751FB9629DAF}
+ {99CB6AD9-92E8-4B9B-99E3-28404AA41655} = {0B58AA48-665A-443F-A6A8-751FB9629DAF}
+ {2263600B-30CB-4188-925D-92F12F904163} = {97C36EF3-805E-4B93-9AF6-C1E22AA583B1}
+ {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E} = {97C36EF3-805E-4B93-9AF6-C1E22AA583B1}
+ {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8} = {97C36EF3-805E-4B93-9AF6-C1E22AA583B1}
+ {FAD86432-6A95-47DE-8E3A-FC2101753C52} = {99CB6AD9-92E8-4B9B-99E3-28404AA41655}
+ {5F278E32-3A2A-4654-BD3C-B183301382FB} = {99CB6AD9-92E8-4B9B-99E3-28404AA41655}
+ {1DB57C74-1C40-4414-B968-937C3C1C157E} = {99CB6AD9-92E8-4B9B-99E3-28404AA41655}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj
new file mode 100644
index 000000000..415515fbf
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs
new file mode 100644
index 000000000..e4fbd5a9b
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs
@@ -0,0 +1,33 @@
+using Volo.Abp.FeatureManagement.Localization;
+using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
+using Volo.Abp.Modularity;
+using Volo.Abp.VirtualFileSystem;
+using VoloAbpFeatureManagementApplicationContractsModule = Volo.Abp.FeatureManagement.AbpFeatureManagementApplicationContractsModule;
+
+namespace LINGYUN.Abp.FeatureManagement;
+
+[DependsOn(
+ typeof(VoloAbpFeatureManagementApplicationContractsModule))]
+public class AbpFeatureManagementApplicationContractsModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Get()
+ .AddVirtualJson("/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts");
+ });
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace(FeatureManagementErrorCodes.Namespace, typeof(AbpFeatureManagementResource));
+ });
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateDto.cs
new file mode 100644
index 000000000..8eba14954
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateDto.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public class FeatureDefinitionCreateDto : FeatureDefinitionCreateOrUpdateDto
+{
+ [Required]
+ [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxNameLength))]
+ public string Name { get; set; }
+
+ [Required]
+ [DynamicStringLength(typeof(FeatureGroupDefinitionRecordConsts), nameof(FeatureGroupDefinitionRecordConsts.MaxNameLength))]
+ public string GroupName { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateOrUpdateDto.cs
new file mode 100644
index 000000000..437dbb7f9
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateOrUpdateDto.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Data;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public abstract class FeatureDefinitionCreateOrUpdateDto : IHasExtraProperties
+{
+ [Required]
+ [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxDisplayNameLength))]
+ public string DisplayName { get; set; }
+
+ [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxNameLength))]
+ public string ParentName { get; set; }
+
+ [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxDescriptionLength))]
+ public string Description { get; set; }
+
+ [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxDefaultValueLength))]
+ public string DefaultValue { get; set; }
+
+ public bool IsVisibleToClients { get; set; }
+
+ public bool IsAvailableToHost { get; set; }
+
+ public List AllowedProviders { get; set; } = new List();
+
+ [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxValueTypeLength))]
+ public string ValueType { get; set; }
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary();
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionDto.cs
new file mode 100644
index 000000000..413ab0563
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionDto.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using Volo.Abp.Data;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public class FeatureDefinitionDto : IHasExtraProperties
+{
+ public string GroupName { get; set; }
+
+ public string Name { get; set; }
+
+ public string ParentName { get; set; }
+
+ public string DisplayName { get; set; }
+
+ public string FormatedDisplayName { get; set; }
+
+ public string Description { get; set; }
+
+ public string FormatedDescription { get; set; }
+
+ public string DefaultValue { get; set; }
+
+ public bool IsVisibleToClients { get; set; }
+
+ public bool IsAvailableToHost { get; set; }
+
+ public List AllowedProviders { get; set; } = new List();
+
+ public string ValueType { get; set; }
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary();
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionGetListInput.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionGetListInput.cs
new file mode 100644
index 000000000..a81654c74
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionGetListInput.cs
@@ -0,0 +1,9 @@
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+public class FeatureDefinitionGetListInput : PagedAndSortedResultRequestDto
+{
+ public string Filter { get; set; }
+
+ public string GroupName { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionUpdateDto.cs
new file mode 100644
index 000000000..9be0e4b3e
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionUpdateDto.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Domain.Entities;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+public class FeatureDefinitionUpdateDto : FeatureDefinitionCreateOrUpdateDto, IHasConcurrencyStamp
+{
+ [StringLength(40)]
+ public string ConcurrencyStamp { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateDto.cs
new file mode 100644
index 000000000..1b465d53e
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateDto.cs
@@ -0,0 +1,11 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+public class FeatureGroupDefinitionCreateDto : FeatureGroupDefinitionCreateOrUpdateDto
+{
+ [Required]
+ [DynamicStringLength(typeof(FeatureGroupDefinitionRecordConsts), nameof(FeatureGroupDefinitionRecordConsts.MaxNameLength))]
+ public string Name { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateOrUpdateDto.cs
new file mode 100644
index 000000000..67cdb9794
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateOrUpdateDto.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Data;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public abstract class FeatureGroupDefinitionCreateOrUpdateDto : IHasExtraProperties
+{
+ [Required]
+ [DynamicStringLength(typeof(FeatureGroupDefinitionRecordConsts), nameof(FeatureGroupDefinitionRecordConsts.MaxDisplayNameLength))]
+ public string DisplayName { get; set; }
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary();
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionDto.cs
new file mode 100644
index 000000000..1ab58525a
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionDto.cs
@@ -0,0 +1,14 @@
+using Volo.Abp.Data;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public class FeatureGroupDefinitionDto : IHasExtraProperties
+{
+ public string Name { get; set; }
+
+ public string DisplayName { get; set; }
+
+ public string FormatedDisplayName { get; set; }
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionGetListInput.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionGetListInput.cs
new file mode 100644
index 000000000..dfeea833e
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionGetListInput.cs
@@ -0,0 +1,7 @@
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+public class FeatureGroupDefinitionGetListInput : PagedAndSortedResultRequestDto
+{
+ public string Filter { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionUpdateDto.cs
new file mode 100644
index 000000000..dafa11775
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionUpdateDto.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Domain.Entities;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+public class FeatureGroupDefinitionUpdateDto : FeatureGroupDefinitionCreateOrUpdateDto, IHasConcurrencyStamp
+{
+ [StringLength(40)]
+ public string ConcurrencyStamp { get; set; }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureDefinitionAppService.cs
new file mode 100644
index 000000000..48fda8bf4
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureDefinitionAppService.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public interface IFeatureDefinitionAppService : IApplicationService
+{
+ Task GetAsync(string name);
+
+ Task DeleteAsync(string name);
+
+ Task CreateAsync(FeatureDefinitionCreateDto input);
+
+ Task UpdateAsync(string name, FeatureDefinitionUpdateDto input);
+
+ Task> GetListAsync(FeatureDefinitionGetListInput input);
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureGroupDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureGroupDefinitionAppService.cs
new file mode 100644
index 000000000..c4aa9f19a
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureGroupDefinitionAppService.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+public interface IFeatureGroupDefinitionAppService : IApplicationService
+{
+ Task GetAsync(string name);
+
+ Task DeleteAsync(string name);
+
+ Task CreateAsync(FeatureGroupDefinitionCreateDto input);
+
+ Task UpdateAsync(string name, FeatureGroupDefinitionUpdateDto input);
+
+ Task> GetListAsync(FeatureGroupDefinitionGetListInput input);
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/FeatureManagementErrorCodes.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/FeatureManagementErrorCodes.cs
new file mode 100644
index 000000000..9e3de97e0
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/FeatureManagementErrorCodes.cs
@@ -0,0 +1,25 @@
+namespace LINGYUN.Abp.FeatureManagement;
+public static class FeatureManagementErrorCodes
+{
+ public const string Namespace = "FeatureManagement";
+
+ public static class GroupDefinition
+ {
+ private const string Prefix = Namespace + ":001";
+
+ public const string AlreayNameExists = Prefix + "100";
+
+ public const string NameNotFount = Prefix + "404";
+ }
+
+ public static class Definition
+ {
+ private const string Prefix = Namespace + ":002";
+
+ public const string AlreayNameExists = Prefix + "100";
+
+ public const string FailedGetGroup = Prefix + "101";
+
+ public const string NameNotFount = Prefix + "404";
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/en.json b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/en.json
new file mode 100644
index 000000000..e8df379f9
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/en.json
@@ -0,0 +1,16 @@
+{
+ "culture": "en",
+ "texts": {
+ "Permission:FeatureManagement": "Feature Management",
+ "Permission:GroupDefinitions": "Group Definitions",
+ "Permission:FeatureDefinitions": "Permission Definitions",
+ "Permission:Create": "Create",
+ "Permission:Edit": "Edit",
+ "Permission:Delete": "Delete",
+ "FeatureManagement:001100": "Feature group {Name} already exists!",
+ "FeatureManagement:001404": "Feature group named {Name} not found!",
+ "FeatureManagement:002100": "Feature {Name} already exists!",
+ "FeatureManagement:002101": "The group definition of feature {Name} could not be retrieved!",
+ "FeatureManagement:0021404": "Feature named {Name} not found!"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/zh-Hans.json b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/zh-Hans.json
new file mode 100644
index 000000000..3d7bcf834
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/zh-Hans.json
@@ -0,0 +1,15 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "Permission:GroupDefinitions": "分组定义",
+ "Permission:FeatureDefinitions": "功能定义",
+ "Permission:Create": "新增",
+ "Permission:Edit": "修改",
+ "Permission:Delete": "删除",
+ "FeatureManagement:001100": "功能分组 {Name} 已经存在!",
+ "FeatureManagement:001404": "没有找到名为 {Name} 的功能分组!",
+ "FeatureManagement:002100": "功能 {Name} 已经存在!",
+ "FeatureManagement:002101": "未能检索到功能 {Name} 所在分组定义!",
+ "FeatureManagement:0021404": "没有找到名为 {Name} 的功能定义!"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionDefinitionProvider.cs
new file mode 100644
index 000000000..5c2eb752d
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionDefinitionProvider.cs
@@ -0,0 +1,53 @@
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.FeatureManagement.Localization;
+using Volo.Abp.Localization;
+using Volo.Abp.MultiTenancy;
+
+namespace LINGYUN.Abp.FeatureManagement.Permissions;
+
+public class FeatureManagementPermissionDefinitionProvider : PermissionDefinitionProvider
+{
+ public override void Define(IPermissionDefinitionContext context)
+ {
+ var featureGroup = context.GetGroup(FeatureManagementPermissionNames.GroupName);
+
+ var groupDefinition = featureGroup.AddPermission(
+ FeatureManagementPermissionNames.GroupDefinition.Default,
+ L("Permission:GroupDefinitions"),
+ MultiTenancySides.Host);
+ groupDefinition.AddChild(
+ FeatureManagementPermissionNames.GroupDefinition.Create,
+ L("Permission:Create"),
+ MultiTenancySides.Host);
+ groupDefinition.AddChild(
+ FeatureManagementPermissionNames.GroupDefinition.Update,
+ L("Permission:Edit"),
+ MultiTenancySides.Host);
+ groupDefinition.AddChild(
+ FeatureManagementPermissionNames.GroupDefinition.Delete,
+ L("Permission:Delete"),
+ MultiTenancySides.Host);
+
+ var featureDefinition = featureGroup.AddPermission(
+ FeatureManagementPermissionNames.Definition.Default,
+ L("Permission:FeatureDefinitions"),
+ MultiTenancySides.Host);
+ featureDefinition.AddChild(
+ FeatureManagementPermissionNames.Definition.Create,
+ L("Permission:Create"),
+ MultiTenancySides.Host);
+ featureDefinition.AddChild(
+ FeatureManagementPermissionNames.Definition.Update,
+ L("Permission:Edit"),
+ MultiTenancySides.Host);
+ featureDefinition.AddChild(
+ FeatureManagementPermissionNames.Definition.Delete,
+ L("Permission:Delete"),
+ MultiTenancySides.Host);
+ }
+
+ private static LocalizableString L(string name)
+ {
+ return LocalizableString.Create(name);
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionNames.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionNames.cs
new file mode 100644
index 000000000..ea138177e
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionNames.cs
@@ -0,0 +1,25 @@
+using Volo.Abp.FeatureManagement;
+
+namespace LINGYUN.Abp.FeatureManagement.Permissions;
+public static class FeatureManagementPermissionNames
+{
+ public const string GroupName = FeatureManagementPermissions.GroupName;
+
+ public static class GroupDefinition
+ {
+ public const string Default = GroupName + ".GroupDefinitions";
+
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ }
+
+ public static class Definition
+ {
+ public const string Default = GroupName + ".Definitions";
+
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xml b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xsd b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN.Abp.FeatureManagement.Application.csproj b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN.Abp.FeatureManagement.Application.csproj
new file mode 100644
index 000000000..3e961d82a
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN.Abp.FeatureManagement.Application.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs
new file mode 100644
index 000000000..bc5573f63
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs
@@ -0,0 +1,11 @@
+using Volo.Abp.Modularity;
+using VoloAbpFeatureManagementApplicationModule = Volo.Abp.FeatureManagement.AbpFeatureManagementApplicationModule;
+
+namespace LINGYUN.Abp.FeatureManagement;
+
+[DependsOn(
+ typeof(AbpFeatureManagementApplicationContractsModule),
+ typeof(VoloAbpFeatureManagementApplicationModule))]
+public class AbpFeatureManagementApplicationModule : AbpModule
+{
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/DynamicFeatureDefinitionStoreCacheInvalidator.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/DynamicFeatureDefinitionStoreCacheInvalidator.cs
new file mode 100644
index 000000000..d7403b7a5
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/DynamicFeatureDefinitionStoreCacheInvalidator.cs
@@ -0,0 +1,64 @@
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Caching;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Domain.Entities.Events;
+using Volo.Abp.EventBus;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Threading;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+public class DynamicPermissionDefinitionStoreCacheInvalidator :
+ ILocalEventHandler>,
+ ILocalEventHandler>,
+ ITransientDependency
+{
+ private readonly IDynamicFeatureDefinitionStoreInMemoryCache _storeCache;
+
+ private readonly IClock _clock;
+ private readonly IDistributedCache _distributedCache;
+ private readonly AbpDistributedCacheOptions _cacheOptions;
+
+ public DynamicPermissionDefinitionStoreCacheInvalidator(
+ IClock clock,
+ IDistributedCache distributedCache,
+ IDynamicFeatureDefinitionStoreInMemoryCache storeCache,
+ IOptions cacheOptions)
+ {
+ _storeCache = storeCache;
+ _clock = clock;
+ _distributedCache = distributedCache;
+ _cacheOptions = cacheOptions.Value;
+ }
+
+ public async virtual Task HandleEventAsync(EntityChangedEventData eventData)
+ {
+ await RemoveStampInDistributedCacheAsync();
+ }
+
+ public async virtual Task HandleEventAsync(EntityChangedEventData eventData)
+ {
+ await RemoveStampInDistributedCacheAsync();
+ }
+
+ protected async virtual Task RemoveStampInDistributedCacheAsync()
+ {
+ using (await _storeCache.SyncSemaphore.LockAsync())
+ {
+ var cacheKey = GetCommonStampCacheKey();
+
+ await _distributedCache.RemoveAsync(cacheKey);
+
+ _storeCache.CacheStamp = Guid.NewGuid().ToString();
+ _storeCache.LastCheckTime = _clock.Now.AddMinutes(-5);
+ }
+ }
+
+ protected virtual string GetCommonStampCacheKey()
+ {
+ return $"{_cacheOptions.KeyPrefix}_AbpInMemoryFeatureCacheStamp";
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionAppService.cs
new file mode 100644
index 000000000..1d801c1c2
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionAppService.cs
@@ -0,0 +1,334 @@
+using LINGYUN.Abp.FeatureManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.Localization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Data;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Features;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+[Authorize(FeatureManagementPermissionNames.Definition.Default)]
+public class FeatureDefinitionAppService : FeatureManagementAppServiceBase, IFeatureDefinitionAppService
+{
+ private readonly ILocalizableStringSerializer _localizableStringSerializer;
+ private readonly IFeatureDefinitionManager _featureDefinitionManager;
+
+ private readonly IFeatureDefinitionRecordRepository _definitionRepository;
+ private readonly IRepository _definitionBasicRepository;
+
+ public FeatureDefinitionAppService(
+ ILocalizableStringSerializer localizableStringSerializer,
+ IFeatureDefinitionManager featureDefinitionManager,
+ IFeatureDefinitionRecordRepository definitionRepository,
+ IRepository definitionBasicRepository)
+ {
+ _localizableStringSerializer = localizableStringSerializer;
+ _featureDefinitionManager = featureDefinitionManager;
+ _definitionRepository = definitionRepository;
+ _definitionBasicRepository = definitionBasicRepository;
+ }
+
+ [Authorize(FeatureManagementPermissionNames.Definition.Create)]
+ public async virtual Task CreateAsync(FeatureDefinitionCreateDto input)
+ {
+ if (await _featureDefinitionManager.GetOrNullAsync(input.Name) != null)
+ {
+ throw new BusinessException(FeatureManagementErrorCodes.Definition.AlreayNameExists)
+ .WithData(nameof(FeatureDefinitionRecord.Name), input.Name);
+ }
+
+ var groupDefinition = await _featureDefinitionManager.GetGroupOrNullAsync(input.GroupName);
+ if (groupDefinition == null)
+ {
+ throw new BusinessException(FeatureManagementErrorCodes.GroupDefinition.NameNotFount)
+ .WithData(nameof(FeatureGroupDefinitionRecord.Name), input.GroupName);
+ }
+
+ var definitionRecord = new FeatureDefinitionRecord(
+ GuidGenerator.Create(),
+ groupDefinition.Name,
+ input.Name,
+ input.ParentName,
+ input.DisplayName,
+ input.Description,
+ input.DefaultValue,
+ input.IsVisibleToClients,
+ input.IsAvailableToHost,
+ valueType: input.ValueType);
+
+ if (input.AllowedProviders.Any())
+ {
+ definitionRecord.AllowedProviders = input.AllowedProviders.JoinAsString(",");
+ }
+
+ foreach (var property in input.ExtraProperties)
+ {
+ definitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ await _definitionRepository.InsertAsync(definitionRecord);
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await DefinitionRecordToDto(definitionRecord);
+
+ return dto;
+ }
+
+ [Authorize(FeatureManagementPermissionNames.Definition.Delete)]
+ public async virtual Task DeleteAsync(string name)
+ {
+ var definitionRecord = await FindByNameAsync(name);
+
+ if (definitionRecord == null)
+ {
+ return;
+ }
+
+ await _definitionRepository.DeleteAsync(definitionRecord);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ var definition = await _featureDefinitionManager.GetOrNullAsync(name);
+ if (definition == null)
+ {
+ throw new BusinessException(FeatureManagementErrorCodes.Definition.NameNotFount)
+ .WithData(nameof(FeatureDefinitionRecord.Name), name);
+ }
+
+ var groupDefinition = await GetGroupDefinition(definition);
+
+ var dto = await DefinitionToDto(groupDefinition, definition);
+
+ return dto;
+ }
+
+ public async virtual Task> GetListAsync(FeatureDefinitionGetListInput input)
+ {
+ var permissions = new List();
+
+ IReadOnlyList definitionPermissions;
+
+ if (!input.GroupName.IsNullOrWhiteSpace())
+ {
+ var group = await _featureDefinitionManager.GetGroupOrNullAsync(input.GroupName);
+ if (group == null)
+ {
+ return new PagedResultDto(0, permissions);
+ }
+
+ definitionPermissions = group.GetFeaturesWithChildren();
+ }
+ else
+ {
+ definitionPermissions = await _featureDefinitionManager.GetAllAsync();
+ }
+
+ var definitionFilter = definitionPermissions.AsQueryable()
+ .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter) ||
+ (x.Parent != null && x.Parent.Name.Contains(input.Filter)));
+
+ var sorting = input.Sorting;
+ if (sorting.IsNullOrWhiteSpace())
+ {
+ sorting = nameof(FeatureDefinitionRecord.Name);
+ }
+
+ var filterDefinitionCount = definitionFilter.Count();
+ var filterDefinitions = definitionFilter
+ .OrderBy(sorting)
+ .PageBy(input.SkipCount, input.MaxResultCount);
+
+ foreach (var definition in filterDefinitions)
+ {
+ var groupDefinition = await GetGroupDefinition(definition);
+ var Dto = await DefinitionToDto(groupDefinition, definition);
+
+ permissions.Add(Dto);
+ }
+
+ return new PagedResultDto(filterDefinitionCount, permissions);
+ }
+
+ [Authorize(FeatureManagementPermissionNames.Definition.Update)]
+ public async virtual Task UpdateAsync(string name, FeatureDefinitionUpdateDto input)
+ {
+ var definition = await _featureDefinitionManager.GetAsync(name);
+ var definitionRecord = await FindByNameAsync(name);
+
+ if (definitionRecord == null)
+ {
+ var groupDefinition = await GetGroupDefinition(definition);
+ definitionRecord = new FeatureDefinitionRecord(
+ GuidGenerator.Create(),
+ groupDefinition.Name,
+ name,
+ input.ParentName,
+ input.DisplayName,
+ input.Description,
+ input.DefaultValue,
+ input.IsVisibleToClients,
+ input.IsAvailableToHost,
+ valueType: input.ValueType);
+
+ if (input.AllowedProviders.Any())
+ {
+ definitionRecord.AllowedProviders = input.AllowedProviders.JoinAsString(",");
+ }
+
+ foreach (var property in input.ExtraProperties)
+ {
+ definitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ definitionRecord = await _definitionBasicRepository.InsertAsync(definitionRecord);
+ }
+ else
+ {
+ definitionRecord.ExtraProperties.Clear();
+ foreach (var property in input.ExtraProperties)
+ {
+ definitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ if (input.AllowedProviders.Any())
+ {
+ definitionRecord.AllowedProviders = input.AllowedProviders.JoinAsString(",");
+ }
+
+ if (!string.Equals(definitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ definitionRecord.DisplayName = input.DisplayName;
+ }
+
+ if (!string.Equals(definitionRecord.Description, input.Description, StringComparison.InvariantCultureIgnoreCase))
+ {
+ definitionRecord.Description = input.Description;
+ }
+
+ if (!string.Equals(definitionRecord.DefaultValue, input.DefaultValue, StringComparison.InvariantCultureIgnoreCase))
+ {
+ definitionRecord.DefaultValue = input.DefaultValue;
+ }
+
+ if (!string.Equals(definitionRecord.ValueType, input.ValueType, StringComparison.InvariantCultureIgnoreCase))
+ {
+ definitionRecord.ValueType = input.ValueType;
+ }
+
+ definitionRecord.IsAvailableToHost = input.IsAvailableToHost;
+ definitionRecord.IsVisibleToClients = input.IsVisibleToClients;
+
+ definitionRecord = await _definitionBasicRepository.UpdateAsync(definitionRecord);
+ }
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await DefinitionRecordToDto(definitionRecord);
+
+ return dto;
+ }
+
+ protected async virtual Task FindByNameAsync(string name)
+ {
+ var DefinitionFilter = await _definitionBasicRepository.GetQueryableAsync();
+
+ var definitionRecord = await AsyncExecuter.FirstOrDefaultAsync(
+ DefinitionFilter.Where(x => x.Name == name));
+
+ return definitionRecord;
+ }
+
+ protected async virtual Task GetGroupDefinition(FeatureDefinition definition)
+ {
+ var groups = await _featureDefinitionManager.GetGroupsAsync();
+
+ foreach (var group in groups)
+ {
+ if (group.GetFeatureOrNull(definition.Name) != null)
+ {
+ return group;
+ }
+ }
+
+ throw new BusinessException(FeatureManagementErrorCodes.Definition.FailedGetGroup)
+ .WithData(nameof(FeatureDefinitionRecord.Name), definition.Name);
+ }
+
+ protected async virtual Task DefinitionRecordToDto(FeatureDefinitionRecord definitionRecord)
+ {
+ var dto = new FeatureDefinitionDto
+ {
+ Name = definitionRecord.Name,
+ GroupName = definitionRecord.GroupName,
+ ParentName = definitionRecord.ParentName,
+ IsAvailableToHost = definitionRecord.IsAvailableToHost,
+ IsVisibleToClients = definitionRecord.IsVisibleToClients,
+ DefaultValue = definitionRecord.DefaultValue,
+ ValueType = definitionRecord.ValueType,
+ AllowedProviders = definitionRecord.AllowedProviders.Split(',').ToList(),
+ FormatedDescription = definitionRecord.Description,
+ FormatedDisplayName = definitionRecord.DisplayName,
+ };
+
+ var displayName = _localizableStringSerializer.Deserialize(definitionRecord.DisplayName);
+ dto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory);
+
+ if (!definitionRecord.Description.IsNullOrWhiteSpace())
+ {
+ var description = _localizableStringSerializer.Deserialize(definitionRecord.Description);
+ dto.Description = await description.LocalizeAsync(StringLocalizerFactory);
+ }
+
+ foreach (var property in definitionRecord.ExtraProperties)
+ {
+ dto.SetProperty(property.Key, property.Value);
+ }
+
+ return dto;
+ }
+
+ protected async virtual Task DefinitionToDto(FeatureGroupDefinition groupDefinition, FeatureDefinition definition)
+ {
+ var dto = new FeatureDefinitionDto
+ {
+ Name = definition.Name,
+ GroupName = groupDefinition.Name,
+ ParentName = definition.Parent?.Name,
+ DefaultValue = definition.DefaultValue,
+ AllowedProviders = definition.AllowedProviders,
+ IsAvailableToHost = definition.IsAvailableToHost,
+ IsVisibleToClients = definition.IsVisibleToClients,
+ ValueType = definition.ValueType.Name,
+ };
+
+ if (definition.DisplayName != null)
+ {
+ dto.DisplayName = await definition.DisplayName.LocalizeAsync(StringLocalizerFactory);
+ dto.FormatedDisplayName = _localizableStringSerializer.Serialize(definition.DisplayName);
+ }
+
+ if (definition.Description != null)
+ {
+ dto.Description = await definition.Description.LocalizeAsync(StringLocalizerFactory);
+ dto.FormatedDescription = _localizableStringSerializer.Serialize(definition.Description);
+ }
+
+ foreach (var property in definition.Properties)
+ {
+ dto.SetProperty(property.Key, property.Value);
+ }
+
+ return dto;
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionAppService.cs
new file mode 100644
index 000000000..d186b2006
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionAppService.cs
@@ -0,0 +1,215 @@
+using LINGYUN.Abp.FeatureManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Data;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Features;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.FeatureManagement.Definitions;
+
+[Authorize(FeatureManagementPermissionNames.GroupDefinition.Default)]
+public class FeatureGroupDefinitionAppService : FeatureManagementAppServiceBase, IFeatureGroupDefinitionAppService
+{
+ private readonly ILocalizableStringSerializer _localizableStringSerializer;
+ private readonly IFeatureDefinitionManager _featureDefinitionManager;
+
+ private readonly IFeatureGroupDefinitionRecordRepository _groupDefinitionRepository;
+ private readonly IRepository _groupDefinitionBasicRepository;
+
+ public FeatureGroupDefinitionAppService(
+ ILocalizableStringSerializer localizableStringSerializer,
+ IFeatureDefinitionManager featureDefinitionManager,
+ IFeatureGroupDefinitionRecordRepository groupDefinitionRepository,
+ IRepository groupDefinitionBasicRepository)
+ {
+ _localizableStringSerializer = localizableStringSerializer;
+ _featureDefinitionManager = featureDefinitionManager;
+ _groupDefinitionRepository = groupDefinitionRepository;
+ _groupDefinitionBasicRepository = groupDefinitionBasicRepository;
+ }
+
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Create)]
+ public async virtual Task CreateAsync(FeatureGroupDefinitionCreateDto input)
+ {
+ if (await _featureDefinitionManager.GetGroupOrNullAsync(input.Name) != null)
+ {
+ throw new BusinessException(FeatureManagementErrorCodes.GroupDefinition.AlreayNameExists)
+ .WithData(nameof(FeatureGroupDefinitionRecord.Name), input.Name);
+ }
+
+ var groupDefinitionRecord = new FeatureGroupDefinitionRecord(
+ GuidGenerator.Create(),
+ input.Name,
+ input.DisplayName);
+
+ foreach (var property in input.ExtraProperties)
+ {
+ groupDefinitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ await _groupDefinitionRepository.InsertAsync(groupDefinitionRecord);
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord);
+
+ return dto;
+ }
+
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)]
+ public async virtual Task DeleteAsync(string name)
+ {
+ var groupDefinitionRecord = await FindByNameAsync(name);
+
+ if (groupDefinitionRecord == null)
+ {
+ return;
+ }
+
+ await _groupDefinitionRepository.DeleteAsync(groupDefinitionRecord);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ var groupDefinition = await _featureDefinitionManager.GetGroupOrNullAsync(name);
+ if (groupDefinition == null)
+ {
+ throw new BusinessException(FeatureManagementErrorCodes.GroupDefinition.NameNotFount)
+ .WithData(nameof(FeatureGroupDefinitionRecord.Name), name);
+ }
+
+ var dto = await GroupDefinitionToDto(groupDefinition);
+
+ return dto;
+ }
+
+ public async virtual Task> GetListAsync(FeatureGroupDefinitionGetListInput input)
+ {
+ var groups = new List();
+
+ var groupDefinitions = await _featureDefinitionManager.GetGroupsAsync();
+
+ var groupDefinitionFilter = groupDefinitions.AsQueryable()
+ .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter));
+
+ var sorting = input.Sorting;
+ if (sorting.IsNullOrWhiteSpace())
+ {
+ sorting = nameof(FeatureDefinitionRecord.Name);
+ }
+
+ var filterGroupDefinitionCount = groupDefinitionFilter.Count();
+ var filterGroupDefinitions = groupDefinitionFilter
+ .OrderBy(sorting)
+ .PageBy(input.SkipCount, input.MaxResultCount);
+
+ foreach (var groupDefinition in filterGroupDefinitions)
+ {
+ var groupDto = await GroupDefinitionToDto(groupDefinition);
+
+ groups.Add(groupDto);
+ }
+
+ return new PagedResultDto(filterGroupDefinitionCount, groups);
+ }
+
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Update)]
+ public async virtual Task UpdateAsync(string name, FeatureGroupDefinitionUpdateDto input)
+ {
+ var groupDefinitionRecord = await FindByNameAsync(name);
+
+ if (groupDefinitionRecord == null)
+ {
+ groupDefinitionRecord = new FeatureGroupDefinitionRecord(
+ GuidGenerator.Create(),
+ name,
+ input.DisplayName);
+
+ foreach (var property in input.ExtraProperties)
+ {
+ groupDefinitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ groupDefinitionRecord = await _groupDefinitionBasicRepository.InsertAsync(groupDefinitionRecord);
+ }
+ else
+ {
+ groupDefinitionRecord.ExtraProperties.Clear();
+ foreach (var property in input.ExtraProperties)
+ {
+ groupDefinitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ if (!string.Equals(groupDefinitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ groupDefinitionRecord.DisplayName = input.DisplayName;
+ }
+
+ groupDefinitionRecord = await _groupDefinitionBasicRepository.UpdateAsync(groupDefinitionRecord);
+ }
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord);
+
+ return dto;
+ }
+
+ protected async virtual Task FindByNameAsync(string name)
+ {
+ var groupDefinitionFilter = await _groupDefinitionBasicRepository.GetQueryableAsync();
+
+ var groupDefinitionRecord = await AsyncExecuter.FirstOrDefaultAsync(
+ groupDefinitionFilter.Where(x => x.Name == name));
+
+ return groupDefinitionRecord;
+ }
+
+ protected async virtual Task GroupDefinitionRecordToDto(FeatureGroupDefinitionRecord groupDefinitionRecord)
+ {
+ var groupDto = new FeatureGroupDefinitionDto
+ {
+ Name = groupDefinitionRecord.Name,
+ FormatedDisplayName = groupDefinitionRecord.DisplayName,
+ };
+
+ var displayName = _localizableStringSerializer.Deserialize(groupDefinitionRecord.DisplayName);
+ groupDto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory);
+
+ foreach (var property in groupDefinitionRecord.ExtraProperties)
+ {
+ groupDto.SetProperty(property.Key, property.Value);
+ }
+
+ return groupDto;
+ }
+
+ protected async virtual Task GroupDefinitionToDto(FeatureGroupDefinition groupDefinition)
+ {
+ var groupDto = new FeatureGroupDefinitionDto
+ {
+ Name = groupDefinition.Name
+ };
+
+ if (groupDefinition.DisplayName != null)
+ {
+ groupDto.DisplayName = await groupDefinition.DisplayName.LocalizeAsync(StringLocalizerFactory);
+ groupDto.FormatedDisplayName = _localizableStringSerializer.Serialize(groupDefinition.DisplayName);
+ }
+
+ foreach (var property in groupDefinition.Properties)
+ {
+ groupDto.SetProperty(property.Key, property.Value);
+ }
+
+ return groupDto;
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/FeatureGroupDefinitionExtensions.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/FeatureGroupDefinitionExtensions.cs
new file mode 100644
index 000000000..d712d9c48
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/FeatureGroupDefinitionExtensions.cs
@@ -0,0 +1,36 @@
+using JetBrains.Annotations;
+using System.Collections.Generic;
+
+namespace Volo.Abp.Features;
+public static class FeatureGroupDefinitionExtensions
+{
+ public static FeatureDefinition GetFeatureOrNull(
+ this FeatureGroupDefinition group,
+ [NotNull] string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ return GetFeatureOrNullRecursively(group.Features, name);
+ }
+
+ private static FeatureDefinition GetFeatureOrNullRecursively(
+ IReadOnlyList features,
+ string name)
+ {
+ foreach (var feature in features)
+ {
+ if (feature.Name == name)
+ {
+ return feature;
+ }
+
+ var childFeature = GetFeatureOrNullRecursively(feature.Children, name);
+ if (childFeature != null)
+ {
+ return childFeature;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/IFeatureDefinitionManagerExtensions.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/IFeatureDefinitionManagerExtensions.cs
new file mode 100644
index 000000000..c19f8f8d0
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/IFeatureDefinitionManagerExtensions.cs
@@ -0,0 +1,16 @@
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.Features;
+public static class IPermissionDefinitionManagerExtensions
+{
+ public async static Task GetGroupOrNullAsync(
+ this IFeatureDefinitionManager featureDefinitionManager,
+ string name
+ )
+ {
+ var groups = await featureDefinitionManager.GetGroupsAsync();
+
+ return groups.FirstOrDefault(x => x.Name == name);
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xml b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN.Abp.FeatureManagement.HttpApi.csproj b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN.Abp.FeatureManagement.HttpApi.csproj
new file mode 100644
index 000000000..ba8a44267
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN.Abp.FeatureManagement.HttpApi.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs
new file mode 100644
index 000000000..a2069e501
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.AspNetCore.Mvc.Localization;
+using Volo.Abp.FeatureManagement.Localization;
+using Volo.Abp.Modularity;
+using VoloAbpFeatureManagementHttpApiModule = Volo.Abp.FeatureManagement.AbpFeatureManagementHttpApiModule;
+
+namespace LINGYUN.Abp.FeatureManagement.HttpApi;
+
+[DependsOn(
+ typeof(AbpFeatureManagementApplicationContractsModule),
+ typeof(VoloAbpFeatureManagementHttpApiModule))]
+public class AbpFeatureManagementHttpApiModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ PreConfigure(delegate (IMvcBuilder mvcBuilder)
+ {
+ mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFeatureManagementHttpApiModule)!.Assembly);
+ });
+
+ PreConfigure(options =>
+ {
+ options.AddAssemblyResource(
+ typeof(AbpFeatureManagementResource),
+ typeof(AbpFeatureManagementApplicationContractsModule).Assembly);
+ });
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionController.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionController.cs
new file mode 100644
index 000000000..e7bb8be4d
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionController.cs
@@ -0,0 +1,62 @@
+using LINGYUN.Abp.FeatureManagement.Definitions;
+using LINGYUN.Abp.FeatureManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.FeatureManagement;
+
+namespace LINGYUN.Abp.FeatureManagement.HttpApi.Definitions;
+
+[Controller]
+[Authorize(FeatureManagementPermissionNames.Definition.Default)]
+[RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)]
+[Area(FeatureManagementRemoteServiceConsts.ModuleName)]
+[Route("api/feature-management/definitions")]
+public class FeatureDefinitionController : FeatureManagementControllerBase, IFeatureDefinitionAppService
+{
+ private readonly IFeatureDefinitionAppService _service;
+
+ public FeatureDefinitionController(IFeatureDefinitionAppService service)
+ {
+ _service = service;
+ }
+
+ [HttpPost]
+ [Authorize(FeatureManagementPermissionNames.Definition.Create)]
+ public virtual Task CreateAsync(FeatureDefinitionCreateDto input)
+ {
+ return _service.CreateAsync(input);
+ }
+
+ [HttpDelete]
+ [Route("{name}")]
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)]
+ public virtual Task DeleteAsync(string name)
+ {
+ return _service.DeleteAsync(name);
+ }
+
+ [HttpGet]
+ [Route("{name}")]
+ [Authorize(FeatureManagementPermissionNames.Definition.Delete)]
+ public virtual Task GetAsync(string name)
+ {
+ return _service.GetAsync(name);
+ }
+
+ [HttpGet]
+ public virtual Task> GetListAsync(FeatureDefinitionGetListInput input)
+ {
+ return _service.GetListAsync(input);
+ }
+
+ [HttpPut]
+ [Route("{name}")]
+ [Authorize(FeatureManagementPermissionNames.Definition.Update)]
+ public virtual Task UpdateAsync(string name, FeatureDefinitionUpdateDto input)
+ {
+ return _service.UpdateAsync(name, input);
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionController.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionController.cs
new file mode 100644
index 000000000..0df8db38b
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionController.cs
@@ -0,0 +1,62 @@
+using LINGYUN.Abp.FeatureManagement.Definitions;
+using LINGYUN.Abp.FeatureManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.FeatureManagement;
+
+namespace LINGYUN.Abp.FeatureManagement.HttpApi.Definitions;
+
+[Controller]
+[Authorize(FeatureManagementPermissionNames.GroupDefinition.Default)]
+[RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)]
+[Area(FeatureManagementRemoteServiceConsts.ModuleName)]
+[Route("api/feature-management/definitions/groups")]
+public class FeatureGroupDefinitionController : FeatureManagementControllerBase, IFeatureGroupDefinitionAppService
+{
+ private readonly IFeatureGroupDefinitionAppService _service;
+
+ public FeatureGroupDefinitionController(IFeatureGroupDefinitionAppService service)
+ {
+ _service = service;
+ }
+
+ [HttpPost]
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Create)]
+ public virtual Task CreateAsync(FeatureGroupDefinitionCreateDto input)
+ {
+ return _service.CreateAsync(input);
+ }
+
+ [HttpDelete]
+ [Route("{name}")]
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)]
+ public virtual Task DeleteAsync(string name)
+ {
+ return _service.DeleteAsync(name);
+ }
+
+ [HttpGet]
+ [Route("{name}")]
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)]
+ public virtual Task GetAsync(string name)
+ {
+ return _service.GetAsync(name);
+ }
+
+ [HttpGet]
+ public virtual Task> GetListAsync(FeatureGroupDefinitionGetListInput input)
+ {
+ return _service.GetListAsync(input);
+ }
+
+ [HttpPut]
+ [Route("{name}")]
+ [Authorize(FeatureManagementPermissionNames.GroupDefinition.Update)]
+ public virtual Task UpdateAsync(string name, FeatureGroupDefinitionUpdateDto input)
+ {
+ return _service.UpdateAsync(name, input);
+ }
+}
diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/FeatureManagementControllerBase.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/FeatureManagementControllerBase.cs
new file mode 100644
index 000000000..81aa88098
--- /dev/null
+++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/FeatureManagementControllerBase.cs
@@ -0,0 +1,12 @@
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.FeatureManagement.Localization;
+
+namespace LINGYUN.Abp.FeatureManagement.HttpApi;
+
+public abstract class FeatureManagementControllerBase : AbpControllerBase
+{
+ protected FeatureManagementControllerBase()
+ {
+ LocalizationResource = typeof(AbpFeatureManagementResource);
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs
index 7ca157451..2e92f56ee 100644
--- a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs
@@ -11,5 +11,10 @@ public class AbpLocalizationPersistenceModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHostedService();
+
+ Configure(options =>
+ {
+ options.GlobalContributors.Add();
+ });
}
}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/DefaultStaticLocalizationSaver.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/DefaultStaticLocalizationSaver.cs
new file mode 100644
index 000000000..ba3262c45
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/DefaultStaticLocalizationSaver.cs
@@ -0,0 +1,135 @@
+using Microsoft.Extensions.Localization;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Localization;
+using Volo.Abp.Uow;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+
+[Dependency(ReplaceServices = true)]
+public class DefaultStaticLocalizationSaver : IStaticLocalizationSaver, ITransientDependency
+{
+ protected ILocalizationPersistenceWriter LocalizationPersistenceWriter { get; }
+
+ protected AbpLocalizationOptions LocalizationOptions { get; }
+ protected IServiceProvider ServiceProvider { get; }
+ protected AbpLocalizationPersistenceOptions LocalizationPersistenceOptions { get; }
+
+ public DefaultStaticLocalizationSaver(
+ IServiceProvider serviceProvider,
+ ILocalizationPersistenceWriter localizationPersistenceWriter,
+ IOptions localizationOptions,
+ IOptions localizationPersistenceOptions)
+ {
+ ServiceProvider = serviceProvider;
+ LocalizationPersistenceWriter = localizationPersistenceWriter;
+ LocalizationOptions = localizationOptions.Value;
+ LocalizationPersistenceOptions = localizationPersistenceOptions.Value;
+ }
+
+ [UnitOfWork]
+ public async virtual Task SaveAsync()
+ {
+ if (!LocalizationPersistenceOptions.SaveStaticLocalizationsToPersistence)
+ {
+ return;
+ }
+
+ var canWriterTexts = new List();
+
+ foreach (var localizationResource in LocalizationOptions.Resources)
+ {
+ if (ShouldSaveToPersistence(localizationResource.Value))
+ {
+ if (!await LocalizationPersistenceWriter.WriteResourceAsync(localizationResource.Value))
+ {
+ continue;
+ }
+
+ foreach (var language in LocalizationOptions.Languages)
+ {
+ if (!await LocalizationPersistenceWriter.WriteLanguageAsync(language))
+ {
+ continue;
+ }
+
+ using (CultureHelper.Use(language.CultureName, language.UiCultureName))
+ {
+ await FillCanWriterTextxAsync(localizationResource.Value, language, canWriterTexts);
+ }
+ }
+ }
+ }
+
+ if (canWriterTexts.Any())
+ {
+ await LocalizationPersistenceWriter.WriteTextsAsync(canWriterTexts);
+ }
+ }
+
+ protected virtual bool ShouldSaveToPersistence(LocalizationResourceBase localizationResource)
+ {
+ var saveResource = false;
+ if (localizationResource.Contributors.Exists(IsMatchSaveToPersistenceContributor))
+ {
+ saveResource = true;
+ }
+ if (!saveResource)
+ {
+ saveResource = LocalizationPersistenceOptions
+ .SaveToPersistenceResources
+ .Contains(localizationResource.ResourceName);
+ }
+
+ return saveResource;
+ }
+
+ protected virtual bool IsMatchSaveToPersistenceContributor(ILocalizationResourceContributor contributor)
+ {
+ return typeof(LocalizationSaveToPersistenceContributor).IsAssignableFrom(contributor.GetType());
+ }
+
+ protected async virtual Task FillCanWriterTextxAsync(
+ LocalizationResourceBase localizationResource,
+ LanguageInfo language,
+ List canWriterTexts)
+ {
+ var fillTexts = new Dictionary();
+ var context = new LocalizationResourceInitializationContext(localizationResource, ServiceProvider);
+ foreach (var contributor in localizationResource.Contributors)
+ {
+ if (contributor.IsDynamic)
+ {
+ continue;
+ }
+
+ contributor.Initialize(context);
+
+ await contributor.FillAsync(language.CultureName, fillTexts);
+ }
+
+ var existsKeys = await LocalizationPersistenceWriter.GetExistsTextsAsync(
+ localizationResource.ResourceName,
+ language.CultureName,
+ fillTexts.Values.Select(x => x.Name));
+
+ var notExistsKeys = fillTexts.Values.Where(x => !existsKeys.Contains(x.Name));
+
+ foreach (var notExistsKey in notExistsKeys)
+ {
+ if (!canWriterTexts.Any(x => x.CultureName == language.CultureName && x.Name == notExistsKey.Name))
+ {
+ canWriterTexts.Add(
+ new LocalizableStringText(
+ localizationResource.ResourceName,
+ language.CultureName,
+ notExistsKey.Name,
+ notExistsKey.Value));
+ }
+ }
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceReader.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceReader.cs
new file mode 100644
index 000000000..7f2bc4388
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceReader.cs
@@ -0,0 +1,16 @@
+using Microsoft.Extensions.Localization;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+
+public interface ILocalizationPersistenceReader
+{
+ LocalizedString GetOrNull(string resourceName, string cultureName, string name);
+
+ void Fill(string resourceName, string cultureName, Dictionary dictionary);
+
+ Task FillAsync(string resourceName, string cultureName, Dictionary dictionary);
+
+ Task> GetSupportedCulturesAsync();
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceWriter.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceWriter.cs
new file mode 100644
index 000000000..ee5826b6f
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceWriter.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+public interface ILocalizationPersistenceWriter
+{
+ Task WriteLanguageAsync(
+ LanguageInfo language,
+ CancellationToken cancellationToken = default);
+
+ Task WriteResourceAsync(
+ LocalizationResourceBase resource,
+ CancellationToken cancellationToken = default);
+
+ Task> GetExistsTextsAsync(
+ string resourceName,
+ string cultureName,
+ IEnumerable keys,
+ CancellationToken cancellationToken = default);
+
+ Task WriteTextsAsync(
+ IEnumerable texts,
+ CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizableStringText.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizableStringText.cs
new file mode 100644
index 000000000..07dd33a80
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizableStringText.cs
@@ -0,0 +1,24 @@
+namespace LINGYUN.Abp.Localization.Persistence;
+public class LocalizableStringText
+{
+ public LocalizableStringText(
+ string resourceName,
+ string cultureName,
+ string name,
+ string value)
+ {
+ ResourceName = resourceName;
+ CultureName = cultureName;
+ Name = name;
+ Value = value;
+ }
+
+ public string ResourceName { get; set; }
+ public string CultureName { get; set; }
+ public string Name { get; set; }
+ public string Value { get; set; }
+ public override string ToString()
+ {
+ return $"[R]:{ResourceName},[C]:{CultureName ?? ""},[N]:{Name},[V]:{Value ?? ""}";
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationPersistenceContributor.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationPersistenceContributor.cs
new file mode 100644
index 000000000..e6a9477d4
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationPersistenceContributor.cs
@@ -0,0 +1,40 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Localization;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+
+public class LocalizationPersistenceContributor : ILocalizationResourceContributor
+{
+ public bool IsDynamic => true;
+
+ private LocalizationResourceBase _resource;
+ private ILocalizationPersistenceReader _persistenceSupport;
+ public void Initialize(LocalizationResourceInitializationContext context)
+ {
+ _resource = context.Resource;
+ _persistenceSupport = context.ServiceProvider.GetRequiredService();
+ }
+
+ public virtual void Fill(string cultureName, Dictionary dictionary)
+ {
+ _persistenceSupport.Fill(_resource.ResourceName, cultureName, dictionary);
+ }
+
+ public async virtual Task FillAsync(string cultureName, Dictionary dictionary)
+ {
+ await _persistenceSupport.FillAsync(_resource.ResourceName, cultureName, dictionary);
+ }
+
+ public virtual LocalizedString GetOrNull(string cultureName, string name)
+ {
+ return _persistenceSupport.GetOrNull(_resource.ResourceName, cultureName, name);
+ }
+
+ public async virtual Task> GetSupportedCulturesAsync()
+ {
+ return await _persistenceSupport.GetSupportedCulturesAsync();
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationSaveToPersistenceContributor.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationSaveToPersistenceContributor.cs
new file mode 100644
index 000000000..192604dfa
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationSaveToPersistenceContributor.cs
@@ -0,0 +1,39 @@
+using Microsoft.Extensions.Localization;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+
+///
+/// 空接口, 使用此提供者可持久化本地化资源到持久设施
+///
+public class LocalizationSaveToPersistenceContributor : ILocalizationResourceContributor
+{
+ public bool IsDynamic => true;
+
+ public void Fill(string cultureName, Dictionary dictionary)
+ {
+ }
+
+ public Task FillAsync(string cultureName, Dictionary dictionary)
+ {
+ return Task.CompletedTask;
+ }
+
+ public LocalizedString GetOrNull(string cultureName, string name)
+ {
+ return null;
+ }
+
+ public Task> GetSupportedCulturesAsync()
+ {
+ IEnumerable emptyCultures = new string[0];
+
+ return Task.FromResult(emptyCultures);
+ }
+
+ public void Initialize(LocalizationResourceInitializationContext context)
+ {
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceReader.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceReader.cs
new file mode 100644
index 000000000..c2509aebe
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceReader.cs
@@ -0,0 +1,32 @@
+using Microsoft.Extensions.Localization;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+
+[Dependency(TryRegister = true)]
+public class NoneLocalizationPersistenceReader : ILocalizationPersistenceReader, ISingletonDependency
+{
+ public void Fill(string resourceName, string cultureName, Dictionary dictionary)
+ {
+
+ }
+
+ public Task FillAsync(string resourceName, string cultureName, Dictionary dictionary)
+ {
+ return Task.CompletedTask;
+ }
+
+ public LocalizedString GetOrNull(string resourceName, string cultureName, string name)
+ {
+ return null;
+ }
+
+ public Task> GetSupportedCulturesAsync()
+ {
+ IEnumerable emptyCultures = new string[0];
+
+ return Task.FromResult(emptyCultures);
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceWriter.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceWriter.cs
new file mode 100644
index 000000000..b6faa0da4
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceWriter.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.Localization.Persistence;
+
+[Dependency(TryRegister = true)]
+public class NoneLocalizationPersistenceWriter : ILocalizationPersistenceWriter, ISingletonDependency
+{
+ public Task> GetExistsTextsAsync(
+ string resourceName,
+ string cultureName,
+ IEnumerable keys,
+ CancellationToken cancellationToken = default)
+ {
+ return Task.FromResult(keys);
+ }
+
+ public Task WriteLanguageAsync(LanguageInfo language, CancellationToken cancellationToken = default)
+ {
+ return Task.FromResult(false);
+ }
+
+ public Task WriteResourceAsync(LocalizationResourceBase resource, CancellationToken cancellationToken = default)
+ {
+ return Task.FromResult(false);
+ }
+
+ public Task WriteTextsAsync(IEnumerable texts, CancellationToken cancellationToken = default)
+ {
+ return Task.FromResult(false);
+ }
+}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md
index 85a964815..2c36cd63c 100644
--- a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md
@@ -33,6 +33,13 @@
// 指定你的本地化资源类型, 此类型下定义的静态文档将被持久化到存储设施
options.AddPersistenceResource();
});
+
+ // 或者使用扩展方法持久化本地化资源类型
+ Configure(options =>
+ {
+ // 效果如上
+ options.UsePersistence();
+ });
}
}
diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs
new file mode 100644
index 000000000..84170dc60
--- /dev/null
+++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs
@@ -0,0 +1,44 @@
+using LINGYUN.Abp.Localization.Persistence;
+using System;
+
+namespace Volo.Abp.Localization;
+public static class AbpLocalizationOptionsExtensions
+{
+ public static void UsePersistence(
+ this AbpLocalizationOptions options)
+ {
+ options.Resources
+ .Get()
+ .Contributors
+ .Add(new LocalizationSaveToPersistenceContributor());
+ }
+
+ public static void UsePersistence(
+ this AbpLocalizationOptions options,
+ Type localizationResourceType)
+ {
+ options.Resources
+ .Get(localizationResourceType)
+ .Contributors
+ .Add(new LocalizationSaveToPersistenceContributor());
+ }
+
+ public static void UsePersistences(
+ this AbpLocalizationOptions options,
+ params Type[] localizationResourceTypes)
+ {
+ foreach (var localizationResourceType in localizationResourceTypes)
+ {
+ options.UsePersistence(localizationResourceType);
+ }
+ }
+
+ public static void UseAllPersistence(
+ this AbpLocalizationOptions options)
+ {
+ foreach (var resource in options.Resources)
+ {
+ resource.Value.Contributors.Add(new LocalizationSaveToPersistenceContributor());
+ }
+ }
+}
diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs
index 47d253f82..eb710de0b 100644
--- a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs
+++ b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs
@@ -1,10 +1,9 @@
-using Microsoft.Extensions.DependencyInjection;
+using LINGYUN.Abp.Localization.Persistence;
+using LINGYUN.Abp.LocalizationManagement.Localization;
+using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain;
-using Volo.Abp.Localization;
using Volo.Abp.Modularity;
-using LINGYUN.Abp.Localization.Persistence;
-using LINGYUN.Abp.LocalizationManagement.Localization;
namespace LINGYUN.Abp.LocalizationManagement
{
@@ -24,11 +23,6 @@ namespace LINGYUN.Abp.LocalizationManagement
options.AddProfile(validate: true);
});
- Configure(options =>
- {
- options.GlobalContributors.Add();
- });
-
Configure(options =>
{
options.AddPersistenceResource();
diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementExternalContributor.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementExternalContributor.cs
deleted file mode 100644
index 2f0c334ed..000000000
--- a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementExternalContributor.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Localization;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Volo.Abp.Localization;
-using Volo.Abp.Threading;
-
-namespace LINGYUN.Abp.LocalizationManagement;
-
-public class LocalizationManagementExternalContributor : ILocalizationResourceContributor
-{
- public bool IsDynamic => true;
-
- private LocalizationResourceBase _resource;
-
- private ILocalizationStoreCache _localizationStoreCache;
- private LocalizationStoreCacheInitializeContext _cacheInitializeContext;
-
- public void Initialize(LocalizationResourceInitializationContext context)
- {
- _resource = context.Resource;
-
- _cacheInitializeContext = new LocalizationStoreCacheInitializeContext(context.ServiceProvider);
- _localizationStoreCache = context.ServiceProvider.GetRequiredService();
- }
-
- public virtual void Fill(string cultureName, Dictionary dictionary)
- {
- AsyncHelper.RunSync(async () => await FillAsync(cultureName, dictionary));
- }
-
- public async virtual Task FillAsync(string cultureName, Dictionary dictionary)
- {
- await _localizationStoreCache.InitializeAsync(_cacheInitializeContext);
-
- var localizedStrings = _localizationStoreCache.GetAllLocalizedStrings(cultureName);
-
- var localizedStringsInResource = localizedStrings.GetOrDefault(_resource.ResourceName);
- if (localizedStringsInResource != null)
- {
- foreach (var localizedString in localizedStringsInResource)
- {
- dictionary[localizedString.Key] = localizedString.Value;
- }
- }
- }
-
- public virtual LocalizedString GetOrNull(string cultureName, string name)
- {
- return _localizationStoreCache
- .GetLocalizedStringOrNull(_resource.ResourceName, cultureName, name);
- }
-
- public virtual Task> GetSupportedCulturesAsync()
- {
- var languageInfos = _localizationStoreCache.GetLanguages();
-
- IEnumerable languages = languageInfos
- .Select(x => x.CultureName)
- .ToList();
-
- return Task.FromResult(languages);
- }
-}
diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceReader.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceReader.cs
new file mode 100644
index 000000000..9ec5f9757
--- /dev/null
+++ b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceReader.cs
@@ -0,0 +1,65 @@
+using LINGYUN.Abp.Localization.Persistence;
+using Microsoft.Extensions.Localization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Threading;
+
+namespace LINGYUN.Abp.LocalizationManagement;
+
+[Dependency(ReplaceServices = true)]
+[ExposeServices(
+ typeof(ILocalizationPersistenceReader),
+ typeof(LocalizationManagementPersistenceReader))]
+public class LocalizationManagementPersistenceReader : ILocalizationPersistenceReader, ITransientDependency
+{
+ private readonly ILocalizationStoreCache _localizationStoreCache;
+ private readonly LocalizationStoreCacheInitializeContext _cacheInitializeContext;
+
+ public LocalizationManagementPersistenceReader(
+ IServiceProvider serviceProvider,
+ ILocalizationStoreCache localizationStoreCache)
+ {
+ _localizationStoreCache = localizationStoreCache;
+ _cacheInitializeContext = new LocalizationStoreCacheInitializeContext(serviceProvider);
+ }
+
+ public virtual void Fill(string resourceName, string cultureName, Dictionary dictionary)
+ {
+ AsyncHelper.RunSync(async () => await FillAsync(resourceName, cultureName, dictionary));
+ }
+
+ public async virtual Task FillAsync(string resourceName, string cultureName, Dictionary dictionary)
+ {
+ await _localizationStoreCache.InitializeAsync(_cacheInitializeContext);
+
+ var localizedStrings = _localizationStoreCache.GetAllLocalizedStrings(cultureName);
+
+ var localizedStringsInResource = localizedStrings.GetOrDefault(resourceName);
+ if (localizedStringsInResource != null)
+ {
+ foreach (var localizedString in localizedStringsInResource)
+ {
+ dictionary[localizedString.Key] = localizedString.Value;
+ }
+ }
+ }
+
+ public virtual LocalizedString GetOrNull(string resourceName, string cultureName, string name)
+ {
+ return _localizationStoreCache.GetLocalizedStringOrNull(resourceName, cultureName, name);
+ }
+
+ public virtual Task> GetSupportedCulturesAsync()
+ {
+ var languageInfos = _localizationStoreCache.GetLanguages();
+
+ IEnumerable languages = languageInfos
+ .Select(x => x.CultureName)
+ .ToList();
+
+ return Task.FromResult(languages);
+ }
+}
diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceWriter.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceWriter.cs
new file mode 100644
index 000000000..0d7fde110
--- /dev/null
+++ b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceWriter.cs
@@ -0,0 +1,203 @@
+using LINGYUN.Abp.Localization.Persistence;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Caching;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.DistributedLocking;
+using Volo.Abp.Guids;
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.LocalizationManagement;
+
+[Dependency(ReplaceServices = true)]
+[ExposeServices(
+ typeof(ILocalizationPersistenceWriter),
+ typeof(LocalizationManagementPersistenceWriter))]
+public class LocalizationManagementPersistenceWriter : ILocalizationPersistenceWriter, ITransientDependency
+{
+ protected IDistributedCache Cache { get; }
+ protected IAbpDistributedLock DistributedLock { get; }
+ protected AbpDistributedCacheOptions CacheOptions { get; }
+ protected IApplicationInfoAccessor ApplicationInfoAccessor { get; }
+
+ protected IGuidGenerator GuidGenerator { get; }
+ protected ILanguageRepository LanguageRepository { get; }
+ protected ITextRepository TextRepository { get; }
+ protected IResourceRepository ResourceRepository { get; }
+
+ public LocalizationManagementPersistenceWriter(
+ IDistributedCache cache,
+ IGuidGenerator guidGenerator,
+ IAbpDistributedLock distributedLock,
+ ITextRepository textRepository,
+ ILanguageRepository languageRepository,
+ IResourceRepository resourceRepository,
+ IApplicationInfoAccessor applicationInfoAccessor,
+ IOptions cacheOptions)
+ {
+ Cache = cache;
+ GuidGenerator = guidGenerator;
+ DistributedLock = distributedLock;
+ LanguageRepository = languageRepository;
+ TextRepository = textRepository;
+ ResourceRepository = resourceRepository;
+ ApplicationInfoAccessor = applicationInfoAccessor;
+ CacheOptions = cacheOptions.Value;
+ }
+
+ public async virtual Task> GetExistsTextsAsync(
+ string resourceName,
+ string cultureName,
+ IEnumerable keys,
+ CancellationToken cancellationToken = default)
+ {
+ if (!await ShouldCalculateTextsHash(keys, cancellationToken))
+ {
+ return keys;
+ }
+
+ return await TextRepository.GetExistsKeysAsync(
+ resourceName,
+ cultureName,
+ keys,
+ cancellationToken);
+ }
+
+
+
+ public async virtual Task WriteLanguageAsync(
+ LanguageInfo language,
+ CancellationToken cancellationToken = default)
+ {
+ var commonDistributedLockKey = GetCommonDistributedLockKey("Language", language.CultureName);
+ await using var lockHandle = await DistributedLock.TryAcquireAsync(commonDistributedLockKey);
+ if (lockHandle == null)
+ {
+ return false;
+ }
+
+ if (await LanguageRepository.FindByCultureNameAsync(language.CultureName, cancellationToken) == null)
+ {
+ await LanguageRepository.InsertAsync(
+ new Language(
+ GuidGenerator.Create(),
+ language.CultureName,
+ language.UiCultureName,
+ language.DisplayName,
+ language.FlagIcon),
+ autoSave: true,
+ cancellationToken: cancellationToken);
+ }
+
+ return true;
+ }
+
+ public async virtual Task WriteResourceAsync(
+ LocalizationResourceBase resource,
+ CancellationToken cancellationToken = default)
+ {
+ var commonDistributedLockKey = GetCommonDistributedLockKey("Resource", resource.ResourceName);
+ await using var lockHandle = await DistributedLock.TryAcquireAsync(commonDistributedLockKey);
+ if (lockHandle == null)
+ {
+ return false;
+ }
+
+ if (await ResourceRepository.FindByNameAsync(resource.ResourceName, cancellationToken) == null)
+ {
+ await ResourceRepository.InsertAsync(
+ new Resource(
+ GuidGenerator.Create(),
+ resource.ResourceName,
+ resource.ResourceName,
+ resource.ResourceName,
+ resource.DefaultCultureName),
+ autoSave: true,
+ cancellationToken: cancellationToken);
+ }
+
+ return true;
+ }
+
+ public async virtual Task WriteTextsAsync(
+ IEnumerable texts,
+ CancellationToken cancellationToken = default)
+ {
+ if (!await ShouldCalculateTextsHash(texts.Select(x => x.Name), cancellationToken))
+ {
+ return false;
+ }
+
+ var cacheKey = GetApplicationHashCacheKey();
+ var currentHash = CalculateTextsHash(texts.Select(x => x.Name));
+
+ var savedTexts = texts.Select(text =>
+ new Text(
+ text.ResourceName,
+ text.CultureName,
+ text.Name,
+ text.Value));
+
+ await TextRepository.InsertManyAsync(
+ savedTexts,
+ autoSave: true,
+ cancellationToken: cancellationToken);
+
+ await Cache.SetStringAsync(
+ cacheKey,
+ currentHash,
+ new DistributedCacheEntryOptions
+ {
+ SlidingExpiration = TimeSpan.FromDays(30)
+ },
+ cancellationToken);
+
+ return true;
+ }
+
+ private async Task ShouldCalculateTextsHash(IEnumerable texts, CancellationToken cancellationToken = default)
+ {
+ var cacheKey = GetApplicationHashCacheKey();
+ var cachedHash = await Cache.GetStringAsync(cacheKey, cancellationToken);
+
+ var currentHash = CalculateTextsHash(texts);
+
+ if (cachedHash == currentHash)
+ {
+ return false;
+ }
+
+ return cachedHash != currentHash;
+ }
+
+ private static string CalculateTextsHash(IEnumerable texts)
+ {
+ var stringBuilder = new StringBuilder();
+
+ stringBuilder.Append("LocalizableStrings:");
+ stringBuilder.Append(texts.JoinAsString(","));
+
+ return stringBuilder
+ .ToString()
+ .ToMd5();
+ }
+
+ private string GetCommonDistributedLockKey(
+ string lockResourceName,
+ string lockResourceKey)
+ {
+ return $"{CacheOptions.KeyPrefix}_Common_AbpLocalizationWriter_{lockResourceName}_{lockResourceKey}_Lock";
+ }
+
+ private string GetApplicationHashCacheKey()
+ {
+ return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_AbpLocalizationHash";
+ }
+}
diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs
deleted file mode 100644
index 9ecb9acd6..000000000
--- a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-using LINGYUN.Abp.Localization.Persistence;
-using Microsoft.Extensions.Localization;
-using Microsoft.Extensions.Options;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Volo.Abp.DependencyInjection;
-using Volo.Abp.Guids;
-using Volo.Abp.Localization;
-using Volo.Abp.Uow;
-
-namespace LINGYUN.Abp.LocalizationManagement;
-
-[Dependency(ReplaceServices = true)]
-public class StaticLocalizationSaver : IStaticLocalizationSaver, ITransientDependency
-{
- protected IGuidGenerator GuidGenerator { get; }
- protected ILanguageRepository LanguageRepository { get; }
- protected ITextRepository TextRepository { get; }
- protected IResourceRepository ResourceRepository { get; }
- protected IStringLocalizerFactory StringLocalizerFactory { get; }
- protected AbpLocalizationOptions LocalizationOptions { get; }
- protected IServiceProvider ServiceProvider { get; }
- protected AbpLocalizationPersistenceOptions LocalizationPersistenceOptions { get; }
-
- public StaticLocalizationSaver(
- IGuidGenerator guidGenerator,
- IServiceProvider serviceProvider,
- ILanguageRepository languageRepository,
- ITextRepository textRepository,
- IResourceRepository resourceRepository,
- IStringLocalizerFactory stringLocalizerFactory,
- IOptions localizationOptions,
- IOptions localizationPersistenceOptions)
- {
- GuidGenerator = guidGenerator;
- ServiceProvider = serviceProvider;
- LanguageRepository = languageRepository;
- TextRepository = textRepository;
- ResourceRepository = resourceRepository;
- StringLocalizerFactory = stringLocalizerFactory;
- LocalizationOptions = localizationOptions.Value;
- LocalizationPersistenceOptions = localizationPersistenceOptions.Value;
- }
-
- [UnitOfWork]
- public async virtual Task SaveAsync()
- {
- var insertNewTexts = new List();
-
- foreach (var language in LocalizationOptions.Languages)
- {
- if (await LanguageRepository.FindByCultureNameAsync(language.CultureName) == null)
- {
- await LanguageRepository.InsertAsync(
- new Language(
- GuidGenerator.Create(),
- language.CultureName,
- language.UiCultureName,
- language.DisplayName,
- language.FlagIcon));
- }
-
- foreach (var resource in LocalizationPersistenceOptions.SaveToPersistenceResources)
- {
- using (CultureHelper.Use(language.CultureName, language.UiCultureName))
- {
- var localizationResource = LocalizationOptions.Resources.GetOrDefault(resource);
- if (localizationResource == null)
- {
- continue;
- }
-
- if (await ResourceRepository.FindByNameAsync(localizationResource.ResourceName) == null)
- {
- await ResourceRepository.InsertAsync(
- new Resource(
- GuidGenerator.Create(),
- localizationResource.ResourceName,
- localizationResource.ResourceName,
- localizationResource.ResourceName,
- localizationResource.DefaultCultureName));
- }
-
- var context = new LocalizationResourceInitializationContext(localizationResource, ServiceProvider);
- foreach (var contributor in localizationResource.Contributors)
- {
- if (contributor.IsDynamic)
- {
- continue;
- }
-
- contributor.Initialize(context);
- var fillTexts = new Dictionary();
-
- await contributor.FillAsync(language.CultureName, fillTexts);
-
- var existsKeys = await TextRepository.GetExistsKeysAsync(
- localizationResource.ResourceName,
- language.CultureName,
- fillTexts.Values.Select(x => x.Name));
-
- var notExistsKeys = fillTexts.Values.Where(x => !existsKeys.Contains(x.Name));
-
- foreach (var notExistsKey in notExistsKeys)
- {
- if (!insertNewTexts.Any(x => x.CultureName == language.CultureName && x.Key == notExistsKey.Name))
- {
- insertNewTexts.Add(
- new Text(
- localizationResource.ResourceName,
- language.CultureName,
- notExistsKey.Name,
- notExistsKey.Value));
- }
- }
- }
- }
- }
- }
-
- if (insertNewTexts.Any())
- {
- await TextRepository.InsertManyAsync(insertNewTexts);
- }
- }
-}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj
new file mode 100644
index 000000000..9d4293ad2
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationContractsModule.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationContractsModule.cs
new file mode 100644
index 000000000..d22a2e4ad
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationContractsModule.cs
@@ -0,0 +1,33 @@
+using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
+using Volo.Abp.Modularity;
+using Volo.Abp.PermissionManagement.Localization;
+using Volo.Abp.VirtualFileSystem;
+using VoloAbpPermissionManagementApplicationContractsModule = Volo.Abp.PermissionManagement.AbpPermissionManagementApplicationContractsModule;
+
+namespace LINGYUN.Abp.PermissionManagement;
+
+[DependsOn(
+ typeof(VoloAbpPermissionManagementApplicationContractsModule))]
+public class AbpPermissionManagementApplicationContractsModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Get()
+ .AddVirtualJson("/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts");
+ });
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace(PermissionManagementErrorCodes.Namespace, typeof(AbpPermissionManagementResource));
+ });
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateDto.cs
new file mode 100644
index 000000000..c581bce2b
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateDto.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public class PermissionDefinitionCreateDto : PermissionDefinitionCreateOrUpdateDto
+{
+ [Required]
+ [DynamicStringLength(typeof(PermissionDefinitionRecordConsts), nameof(PermissionDefinitionRecordConsts.MaxNameLength))]
+ public string Name { get; set; }
+
+ [Required]
+ [DynamicStringLength(typeof(PermissionGroupDefinitionRecordConsts), nameof(PermissionGroupDefinitionRecordConsts.MaxNameLength))]
+ public string GroupName { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateOrUpdateDto.cs
new file mode 100644
index 000000000..49ae50e3b
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateOrUpdateDto.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Data;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public abstract class PermissionDefinitionCreateOrUpdateDto : IHasExtraProperties
+{
+ [Required]
+ [DynamicStringLength(typeof(PermissionDefinitionRecordConsts), nameof(PermissionDefinitionRecordConsts.MaxDisplayNameLength))]
+ public string DisplayName { get; set; }
+
+ [DynamicStringLength(typeof(PermissionDefinitionRecordConsts), nameof(PermissionDefinitionRecordConsts.MaxNameLength))]
+ public string ParentName { get; set; }
+
+ public bool IsEnabled { get; set; }
+
+ public MultiTenancySides? MultiTenancySide { get; set; }
+
+ public List Providers { get; set; } = new List();
+
+ public List StateCheckers { get; set; } = new List();
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary();
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionDto.cs
new file mode 100644
index 000000000..867ac90f6
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionDto.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using Volo.Abp.Data;
+using Volo.Abp.MultiTenancy;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public class PermissionDefinitionDto : IHasExtraProperties
+{
+ public string Name { get; set; }
+
+ public string ParentName { get; set; }
+
+ public string DisplayName { get; set; }
+
+ public string FormatedDisplayName { get; set; }
+
+ public string GroupName { get; set; }
+
+ public bool IsEnabled { get; set; }
+
+ public MultiTenancySides? MultiTenancySide { get; set; }
+
+ public List Providers { get; set; } = new List();
+
+ public List StateCheckers { get; set; } = new List();
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionGetListInput.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionGetListInput.cs
new file mode 100644
index 000000000..834f37091
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionGetListInput.cs
@@ -0,0 +1,9 @@
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+public class PermissionDefinitionGetListInput : PagedAndSortedResultRequestDto
+{
+ public string Filter { get; set; }
+
+ public string GroupName { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionUpdateDto.cs
new file mode 100644
index 000000000..07d4044cf
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionUpdateDto.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Domain.Entities;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+public class PermissionDefinitionUpdateDto : PermissionDefinitionCreateOrUpdateDto, IHasConcurrencyStamp
+{
+ [StringLength(40)]
+ public string ConcurrencyStamp { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateDto.cs
new file mode 100644
index 000000000..4d93939d3
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateDto.cs
@@ -0,0 +1,11 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+public class PermissionGroupDefinitionCreateDto : PermissionGroupDefinitionCreateOrUpdateDto
+{
+ [Required]
+ [DynamicStringLength(typeof(PermissionGroupDefinitionRecordConsts), nameof(PermissionGroupDefinitionRecordConsts.MaxNameLength))]
+ public string Name { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateOrUpdateDto.cs
new file mode 100644
index 000000000..b9c3eb78c
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateOrUpdateDto.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Data;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.Validation;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public abstract class PermissionGroupDefinitionCreateOrUpdateDto : IHasExtraProperties
+{
+ [Required]
+ [DynamicStringLength(typeof(PermissionGroupDefinitionRecordConsts), nameof(PermissionGroupDefinitionRecordConsts.MaxDisplayNameLength))]
+ public string DisplayName { get; set; }
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary();
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionDto.cs
new file mode 100644
index 000000000..336df036d
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionDto.cs
@@ -0,0 +1,14 @@
+using Volo.Abp.Data;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public class PermissionGroupDefinitionDto : IHasExtraProperties
+{
+ public string Name { get; set; }
+
+ public string DisplayName { get; set; }
+
+ public string FormatedDisplayName { get; set; }
+
+ public ExtraPropertyDictionary ExtraProperties { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionGetListInput.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionGetListInput.cs
new file mode 100644
index 000000000..9e7265dc5
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionGetListInput.cs
@@ -0,0 +1,7 @@
+using Volo.Abp.Application.Dtos;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+public class PermissionGroupDefinitionGetListInput : PagedAndSortedResultRequestDto
+{
+ public string Filter { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionUpdateDto.cs
new file mode 100644
index 000000000..370fe95e5
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionUpdateDto.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Domain.Entities;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+public class PermissionGroupDefinitionUpdateDto : PermissionGroupDefinitionCreateOrUpdateDto, IHasConcurrencyStamp
+{
+ [StringLength(40)]
+ public string ConcurrencyStamp { get; set; }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionDefinitionAppService.cs
new file mode 100644
index 000000000..7cf6793ab
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionDefinitionAppService.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public interface IPermissionDefinitionAppService : IApplicationService
+{
+ Task GetAsync(string name);
+
+ Task DeleteAsync(string name);
+
+ Task CreateAsync(PermissionDefinitionCreateDto input);
+
+ Task UpdateAsync(string name, PermissionDefinitionUpdateDto input);
+
+ Task> GetListAsync(PermissionDefinitionGetListInput input);
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionGroupDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionGroupDefinitionAppService.cs
new file mode 100644
index 000000000..cd1c8d3f7
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionGroupDefinitionAppService.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+public interface IPermissionGroupDefinitionAppService : IApplicationService
+{
+ Task GetAsync(string name);
+
+ Task DeleteAsync(string name);
+
+ Task CreateAsync(PermissionGroupDefinitionCreateDto input);
+
+ Task UpdateAsync(string name, PermissionGroupDefinitionUpdateDto input);
+
+ Task> GetListAsync(PermissionGroupDefinitionGetListInput input);
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/en.json b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/en.json
new file mode 100644
index 000000000..34517b84d
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/en.json
@@ -0,0 +1,16 @@
+{
+ "culture": "en",
+ "texts": {
+ "Permission:PermissionManagement": "Permission Management",
+ "Permission:GroupDefinitions": "Group Definitions",
+ "Permission:PermissionDefinitions": "Permission Definitions",
+ "Permission:Create": "Create",
+ "Permission:Edit": "Edit",
+ "Permission:Delete": "Delete",
+ "PermissionManagement:001100": "Permission group {Name} already exists!",
+ "PermissionManagement:001404": "Permission group named {Name} not found!",
+ "PermissionManagement:002100": "Permission {Name} already exists!",
+ "PermissionManagement:002101": "The group definition of permission {Name} could not be retrieved!",
+ "PermissionManagement:0021404": "Permission named {Name} not found!"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/zh-Hans.json b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/zh-Hans.json
new file mode 100644
index 000000000..3a036509d
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/zh-Hans.json
@@ -0,0 +1,16 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "Permission:PermissionManagement": "权限管理",
+ "Permission:GroupDefinitions": "分组定义",
+ "Permission:PermissionDefinitions": "权限定义",
+ "Permission:Create": "新增",
+ "Permission:Edit": "修改",
+ "Permission:Delete": "删除",
+ "PermissionManagement:001100": "权限分组 {Name} 已经存在!",
+ "PermissionManagement:001404": "没有找到名为 {Name} 的权限分组!",
+ "PermissionManagement:002100": "权限 {Name} 已经存在!",
+ "PermissionManagement:002101": "未能检索到权限 {Name} 所在分组定义!",
+ "PermissionManagement:0021404": "没有找到名为 {Name} 的权限定义!"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/PermissionManagementErrorCodes.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/PermissionManagementErrorCodes.cs
new file mode 100644
index 000000000..b6c519ae0
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/PermissionManagementErrorCodes.cs
@@ -0,0 +1,25 @@
+namespace LINGYUN.Abp.PermissionManagement;
+public static class PermissionManagementErrorCodes
+{
+ public const string Namespace = "PermissionManagement";
+
+ public static class GroupDefinition
+ {
+ private const string Prefix = Namespace + ":001";
+
+ public const string AlreayNameExists = Prefix + "100";
+
+ public const string NameNotFount = Prefix + "404";
+ }
+
+ public static class Definition
+ {
+ private const string Prefix = Namespace + ":002";
+
+ public const string AlreayNameExists = Prefix + "100";
+
+ public const string FailedGetGroup = Prefix + "101";
+
+ public const string NameNotFount = Prefix + "404";
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionDefinitionProvider.cs
new file mode 100644
index 000000000..4c90e9848
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionDefinitionProvider.cs
@@ -0,0 +1,55 @@
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Localization;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.PermissionManagement.Localization;
+
+namespace LINGYUN.Abp.PermissionManagement.Permissions;
+
+public class PermissionManagementPermissionDefinitionProvider : PermissionDefinitionProvider
+{
+ public override void Define(IPermissionDefinitionContext context)
+ {
+ var permissionGroup = context.AddGroup(
+ PermissionManagementPermissionNames.GroupName,
+ L("Permission:PermissionManagement"));
+
+ var groupDefinition = permissionGroup.AddPermission(
+ PermissionManagementPermissionNames.GroupDefinition.Default,
+ L("Permission:GroupDefinitions"),
+ MultiTenancySides.Host);
+ groupDefinition.AddChild(
+ PermissionManagementPermissionNames.GroupDefinition.Create,
+ L("Permission:Create"),
+ MultiTenancySides.Host);
+ groupDefinition.AddChild(
+ PermissionManagementPermissionNames.GroupDefinition.Update,
+ L("Permission:Edit"),
+ MultiTenancySides.Host);
+ groupDefinition.AddChild(
+ PermissionManagementPermissionNames.GroupDefinition.Delete,
+ L("Permission:Delete"),
+ MultiTenancySides.Host);
+
+ var permissionDefinition = permissionGroup.AddPermission(
+ PermissionManagementPermissionNames.Definition.Default,
+ L("Permission:PermissionDefinitions"),
+ MultiTenancySides.Host);
+ permissionDefinition.AddChild(
+ PermissionManagementPermissionNames.Definition.Create,
+ L("Permission:Create"),
+ MultiTenancySides.Host);
+ permissionDefinition.AddChild(
+ PermissionManagementPermissionNames.Definition.Update,
+ L("Permission:Edit"),
+ MultiTenancySides.Host);
+ permissionDefinition.AddChild(
+ PermissionManagementPermissionNames.Definition.Delete,
+ L("Permission:Delete"),
+ MultiTenancySides.Host);
+ }
+
+ private static LocalizableString L(string name)
+ {
+ return LocalizableString.Create(name);
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionNames.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionNames.cs
new file mode 100644
index 000000000..7f234b16d
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionNames.cs
@@ -0,0 +1,23 @@
+namespace LINGYUN.Abp.PermissionManagement.Permissions;
+public static class PermissionManagementPermissionNames
+{
+ public const string GroupName = "PermissionManagement";
+
+ public static class GroupDefinition
+ {
+ public const string Default = GroupName + ".GroupDefinitions";
+
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ }
+
+ public static class Definition
+ {
+ public const string Default = GroupName + ".Definitions";
+
+ public const string Create = Default + ".Create";
+ public const string Update = Default + ".Update";
+ public const string Delete = Default + ".Delete";
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xml b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xsd b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN.Abp.PermissionManagement.Application.csproj b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN.Abp.PermissionManagement.Application.csproj
new file mode 100644
index 000000000..81161aa88
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN.Abp.PermissionManagement.Application.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationModule.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationModule.cs
new file mode 100644
index 000000000..6ed24af73
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationModule.cs
@@ -0,0 +1,12 @@
+using Volo.Abp.Modularity;
+using VoloAbpPermissionManagementApplicationModule = Volo.Abp.PermissionManagement.AbpPermissionManagementApplicationModule;
+
+namespace LINGYUN.Abp.PermissionManagement;
+
+[DependsOn(
+ typeof(AbpPermissionManagementApplicationContractsModule),
+ typeof(VoloAbpPermissionManagementApplicationModule))]
+public class AbpPermissionManagementApplicationModule : AbpModule
+{
+
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/DynamicPermissionDefinitionStoreCacheInvalidator.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/DynamicPermissionDefinitionStoreCacheInvalidator.cs
new file mode 100644
index 000000000..7a12b3bc7
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/DynamicPermissionDefinitionStoreCacheInvalidator.cs
@@ -0,0 +1,64 @@
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Caching;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Domain.Entities.Events;
+using Volo.Abp.EventBus;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.Threading;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+public class DynamicPermissionDefinitionStoreCacheInvalidator :
+ ILocalEventHandler>,
+ ILocalEventHandler>,
+ ITransientDependency
+{
+ private readonly IDynamicPermissionDefinitionStoreInMemoryCache _storeCache;
+
+ private readonly IClock _clock;
+ private readonly IDistributedCache _distributedCache;
+ private readonly AbpDistributedCacheOptions _cacheOptions;
+
+ public DynamicPermissionDefinitionStoreCacheInvalidator(
+ IClock clock,
+ IDistributedCache distributedCache,
+ IDynamicPermissionDefinitionStoreInMemoryCache storeCache,
+ IOptions cacheOptions)
+ {
+ _storeCache = storeCache;
+ _clock = clock;
+ _distributedCache = distributedCache;
+ _cacheOptions = cacheOptions.Value;
+ }
+
+ public async virtual Task HandleEventAsync(EntityChangedEventData eventData)
+ {
+ await RemoveStampInDistributedCacheAsync();
+ }
+
+ public async virtual Task HandleEventAsync(EntityChangedEventData eventData)
+ {
+ await RemoveStampInDistributedCacheAsync();
+ }
+
+ protected async virtual Task RemoveStampInDistributedCacheAsync()
+ {
+ using (await _storeCache.SyncSemaphore.LockAsync())
+ {
+ var cacheKey = GetCommonStampCacheKey();
+
+ await _distributedCache.RemoveAsync(cacheKey);
+
+ _storeCache.CacheStamp = Guid.NewGuid().ToString();
+ _storeCache.LastCheckTime = _clock.Now.AddMinutes(-5);
+ }
+ }
+
+ protected virtual string GetCommonStampCacheKey()
+ {
+ return $"{_cacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp";
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionDefinitionAppService.cs
new file mode 100644
index 000000000..a24a09cba
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionDefinitionAppService.cs
@@ -0,0 +1,331 @@
+using LINGYUN.Abp.PermissionManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Data;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.Localization;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.SimpleStateChecking;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+[Authorize(PermissionManagementPermissionNames.Definition.Default)]
+public class PermissionDefinitionAppService : PermissionManagementAppServiceBase, IPermissionDefinitionAppService
+{
+ private readonly ISimpleStateCheckerSerializer _simpleStateCheckerSerializer;
+ private readonly ILocalizableStringSerializer _localizableStringSerializer;
+ private readonly IPermissionDefinitionManager _permissionDefinitionManager;
+
+ private readonly IPermissionDefinitionRecordRepository _definitionRepository;
+ private readonly IRepository _definitionBasicRepository;
+
+ public PermissionDefinitionAppService(
+ ILocalizableStringSerializer localizableStringSerializer,
+ IPermissionDefinitionManager permissionDefinitionManager,
+ ISimpleStateCheckerSerializer simpleStateCheckerSerializer,
+ IPermissionDefinitionRecordRepository definitionRepository,
+ IRepository definitionBasicRepository)
+ {
+ _localizableStringSerializer = localizableStringSerializer;
+ _permissionDefinitionManager = permissionDefinitionManager;
+ _simpleStateCheckerSerializer = simpleStateCheckerSerializer;
+ _definitionRepository = definitionRepository;
+ _definitionBasicRepository = definitionBasicRepository;
+ }
+
+ [Authorize(PermissionManagementPermissionNames.Definition.Create)]
+ public async virtual Task CreateAsync(PermissionDefinitionCreateDto input)
+ {
+ if (await _permissionDefinitionManager.GetOrNullAsync(input.Name) != null)
+ {
+ throw new BusinessException(PermissionManagementErrorCodes.Definition.AlreayNameExists)
+ .WithData(nameof(PermissionDefinitionRecord.Name), input.Name);
+ }
+
+ var groupDefinition = await _permissionDefinitionManager.GetGroupOrNullAsync(input.GroupName);
+ if (groupDefinition == null)
+ {
+ throw new BusinessException(PermissionManagementErrorCodes.GroupDefinition.NameNotFount)
+ .WithData(nameof(PermissionGroupDefinitionRecord.Name), input.GroupName);
+ }
+
+ var definitionRecord = new PermissionDefinitionRecord(
+ GuidGenerator.Create(),
+ groupDefinition.Name,
+ input.Name,
+ input.ParentName,
+ input.DisplayName,
+ input.IsEnabled);
+
+ if (input.MultiTenancySide.HasValue)
+ {
+ definitionRecord.MultiTenancySide = input.MultiTenancySide.Value;
+ }
+
+ if (input.Providers.Any())
+ {
+ definitionRecord.Providers = input.Providers.JoinAsString(",");
+ }
+
+ if (input.StateCheckers.Any())
+ {
+ definitionRecord.StateCheckers = input.StateCheckers.JoinAsString(",");
+ }
+
+ foreach (var property in input.ExtraProperties)
+ {
+ definitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ await _definitionRepository.InsertAsync(definitionRecord);
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await DefinitionRecordToDto(definitionRecord);
+
+ return dto;
+ }
+
+ [Authorize(PermissionManagementPermissionNames.Definition.Delete)]
+ public async virtual Task DeleteAsync(string name)
+ {
+ var definitionRecord = await FindByNameAsync(name);
+
+ if (definitionRecord == null)
+ {
+ return;
+ }
+
+ await _definitionRepository.DeleteAsync(definitionRecord);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ var definition = await _permissionDefinitionManager.GetOrNullAsync(name);
+ if (definition == null)
+ {
+ throw new BusinessException(PermissionManagementErrorCodes.Definition.NameNotFount)
+ .WithData(nameof(PermissionDefinitionRecord.Name), name);
+ }
+
+ var groupDefinition = await GetGroupDefinition(definition);
+
+ var dto = await DefinitionToDto(groupDefinition, definition);
+
+ return dto;
+ }
+
+ public async virtual Task> GetListAsync(PermissionDefinitionGetListInput input)
+ {
+ var permissions = new List();
+
+ IReadOnlyList definitionPermissions;
+
+ if (!input.GroupName.IsNullOrWhiteSpace())
+ {
+ var group = await _permissionDefinitionManager.GetGroupOrNullAsync(input.GroupName);
+ if (group == null)
+ {
+ return new PagedResultDto(0, permissions);
+ }
+
+ definitionPermissions = group.GetPermissionsWithChildren();
+ }
+ else
+ {
+ definitionPermissions = await _permissionDefinitionManager.GetPermissionsAsync();
+ }
+
+ var definitionFilter = definitionPermissions.AsQueryable()
+ .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter) ||
+ (x.Parent != null && x.Parent.Name.Contains(input.Filter)));
+
+ var sorting = input.Sorting;
+ if (sorting.IsNullOrWhiteSpace())
+ {
+ sorting = nameof(PermissionDefinitionRecord.Name);
+ }
+
+ var filterDefinitionCount = definitionFilter.Count();
+ var filterDefinitions = definitionFilter
+ .OrderBy(sorting)
+ .PageBy(input.SkipCount, input.MaxResultCount);
+
+ foreach (var definition in filterDefinitions)
+ {
+ var groupDefinition = await GetGroupDefinition(definition);
+ var Dto = await DefinitionToDto(groupDefinition, definition);
+
+ permissions.Add(Dto);
+ }
+
+ return new PagedResultDto(filterDefinitionCount, permissions);
+ }
+
+ [Authorize(PermissionManagementPermissionNames.Definition.Update)]
+ public async virtual Task UpdateAsync(string name, PermissionDefinitionUpdateDto input)
+ {
+ var definition = await _permissionDefinitionManager.GetOrNullAsync(name);
+ var definitionRecord = await FindByNameAsync(name);
+
+ if (definitionRecord == null)
+ {
+ var groupDefinition = await GetGroupDefinition(definition);
+ definitionRecord = new PermissionDefinitionRecord(
+ GuidGenerator.Create(),
+ groupDefinition.Name,
+ name,
+ input.ParentName,
+ input.DisplayName,
+ input.IsEnabled);
+
+ if (input.MultiTenancySide.HasValue)
+ {
+ definitionRecord.MultiTenancySide = input.MultiTenancySide.Value;
+ }
+
+ if (input.Providers.Any())
+ {
+ definitionRecord.Providers = input.Providers.JoinAsString(",");
+ }
+
+ if (input.StateCheckers.Any())
+ {
+ definitionRecord.StateCheckers = input.StateCheckers.JoinAsString(",");
+ }
+
+ foreach (var property in input.ExtraProperties)
+ {
+ definitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ definitionRecord = await _definitionBasicRepository.InsertAsync(definitionRecord);
+ }
+ else
+ {
+ definitionRecord.ExtraProperties.Clear();
+ foreach (var property in input.ExtraProperties)
+ {
+ definitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ if (input.MultiTenancySide.HasValue)
+ {
+ definitionRecord.MultiTenancySide = input.MultiTenancySide.Value;
+ }
+
+ if (input.Providers.Any())
+ {
+ definitionRecord.Providers = input.Providers.JoinAsString(",");
+ }
+
+ if (input.StateCheckers.Any())
+ {
+ definitionRecord.StateCheckers = input.StateCheckers.JoinAsString(",");
+ }
+
+ if (!string.Equals(definitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ definitionRecord.DisplayName = input.DisplayName;
+ }
+
+ definitionRecord = await _definitionBasicRepository.UpdateAsync(definitionRecord);
+ }
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await DefinitionRecordToDto(definitionRecord);
+
+ return dto;
+ }
+
+ protected async virtual Task FindByNameAsync(string name)
+ {
+ var DefinitionFilter = await _definitionBasicRepository.GetQueryableAsync();
+
+ var definitionRecord = await AsyncExecuter.FirstOrDefaultAsync(
+ DefinitionFilter.Where(x => x.Name == name));
+
+ return definitionRecord;
+ }
+
+ protected async virtual Task GetGroupDefinition(PermissionDefinition definition)
+ {
+ var groups = await _permissionDefinitionManager.GetGroupsAsync();
+
+ foreach (var group in groups)
+ {
+ if (group.GetPermissionOrNull(definition.Name) != null)
+ {
+ return group;
+ }
+ }
+
+ throw new BusinessException(PermissionManagementErrorCodes.Definition.FailedGetGroup)
+ .WithData(nameof(PermissionDefinitionRecord.Name), definition.Name);
+ }
+
+ protected async virtual Task DefinitionRecordToDto(PermissionDefinitionRecord definitionRecord)
+ {
+ var dto = new PermissionDefinitionDto
+ {
+ Name = definitionRecord.Name,
+ GroupName = definitionRecord.GroupName,
+ ParentName = definitionRecord.ParentName,
+ IsEnabled = definitionRecord.IsEnabled,
+ FormatedDisplayName = definitionRecord.DisplayName,
+ Providers = definitionRecord.Providers.Split(',').ToList(),
+ StateCheckers = definitionRecord.StateCheckers.Split(',').ToList(),
+ MultiTenancySide = definitionRecord.MultiTenancySide,
+ };
+
+ var displayName = _localizableStringSerializer.Deserialize(definitionRecord.DisplayName);
+ dto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory);
+
+ foreach (var property in definitionRecord.ExtraProperties)
+ {
+ dto.SetProperty(property.Key, property.Value);
+ }
+
+ return dto;
+ }
+
+ protected async virtual Task DefinitionToDto(PermissionGroupDefinition groupDefinition, PermissionDefinition definition)
+ {
+ var dto = new PermissionDefinitionDto
+ {
+ Name = definition.Name,
+ GroupName = groupDefinition.Name,
+ ParentName = definition.Parent?.Name,
+ IsEnabled = definition.IsEnabled,
+ Providers = definition.Providers,
+ MultiTenancySide = definition.MultiTenancySide,
+ };
+
+ if (definition.StateCheckers.Any())
+ {
+ var stateCheckers = _simpleStateCheckerSerializer.Serialize(definition.StateCheckers);
+ dto.StateCheckers = stateCheckers.Split(',').ToList();
+ }
+
+ if (definition.DisplayName != null)
+ {
+ dto.DisplayName = await definition.DisplayName.LocalizeAsync(StringLocalizerFactory);
+ dto.FormatedDisplayName = _localizableStringSerializer.Serialize(definition.DisplayName);
+ }
+
+ foreach (var property in definition.Properties)
+ {
+ dto.SetProperty(property.Key, property.Value);
+ }
+
+ return dto;
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionGroupDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionGroupDefinitionAppService.cs
new file mode 100644
index 000000000..e71ea10b3
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionGroupDefinitionAppService.cs
@@ -0,0 +1,216 @@
+using LINGYUN.Abp.PermissionManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Data;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.Localization;
+using Volo.Abp.PermissionManagement;
+
+namespace LINGYUN.Abp.PermissionManagement.Definitions;
+
+[Authorize(PermissionManagementPermissionNames.GroupDefinition.Default)]
+public class PermissionGroupDefinitionAppService : PermissionManagementAppServiceBase, IPermissionGroupDefinitionAppService
+{
+ private readonly ILocalizableStringSerializer _localizableStringSerializer;
+ private readonly IPermissionDefinitionManager _permissionDefinitionManager;
+
+ private readonly IPermissionGroupDefinitionRecordRepository _groupDefinitionRepository;
+ private readonly IRepository _groupDefinitionBasicRepository;
+
+ public PermissionGroupDefinitionAppService(
+ ILocalizableStringSerializer localizableStringSerializer,
+ IPermissionDefinitionManager permissionDefinitionManager,
+ IPermissionGroupDefinitionRecordRepository groupDefinitionRepository,
+ IRepository groupDefinitionBasicRepository)
+ {
+ _localizableStringSerializer = localizableStringSerializer;
+ _permissionDefinitionManager = permissionDefinitionManager;
+ _groupDefinitionRepository = groupDefinitionRepository;
+ _groupDefinitionBasicRepository = groupDefinitionBasicRepository;
+ }
+
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Create)]
+ public async virtual Task CreateAsync(PermissionGroupDefinitionCreateDto input)
+ {
+ if (await _permissionDefinitionManager.GetGroupOrNullAsync(input.Name) != null)
+ {
+ throw new BusinessException(PermissionManagementErrorCodes.GroupDefinition.AlreayNameExists)
+ .WithData(nameof(PermissionGroupDefinitionRecord.Name), input.Name);
+ }
+
+ var groupDefinitionRecord = new PermissionGroupDefinitionRecord(
+ GuidGenerator.Create(),
+ input.Name,
+ input.DisplayName);
+
+ foreach (var property in input.ExtraProperties)
+ {
+ groupDefinitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ await _groupDefinitionRepository.InsertAsync(groupDefinitionRecord);
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord);
+
+ return dto;
+ }
+
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)]
+ public async virtual Task DeleteAsync(string name)
+ {
+ var groupDefinitionRecord = await FindByNameAsync(name);
+
+ if (groupDefinitionRecord == null)
+ {
+ return;
+ }
+
+ await _groupDefinitionRepository.DeleteAsync(groupDefinitionRecord);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ var groupDefinition = await _permissionDefinitionManager.GetGroupOrNullAsync(name);
+ if (groupDefinition == null)
+ {
+ throw new BusinessException(PermissionManagementErrorCodes.GroupDefinition.NameNotFount)
+ .WithData(nameof(PermissionGroupDefinitionRecord.Name), name);
+ }
+
+ var dto = await GroupDefinitionToDto(groupDefinition);
+
+ return dto;
+ }
+
+ public async virtual Task> GetListAsync(PermissionGroupDefinitionGetListInput input)
+ {
+ var groups = new List();
+
+ var groupDefinitions = await _permissionDefinitionManager.GetGroupsAsync();
+
+ var groupDefinitionFilter = groupDefinitions.AsQueryable()
+ .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter));
+
+ var sorting = input.Sorting;
+ if (sorting.IsNullOrWhiteSpace())
+ {
+ sorting = nameof(PermissionDefinitionRecord.Name);
+ }
+
+ var filterGroupDefinitionCount = groupDefinitionFilter.Count();
+ var filterGroupDefinitions = groupDefinitionFilter
+ .OrderBy(sorting)
+ .PageBy(input.SkipCount, input.MaxResultCount);
+
+ foreach (var groupDefinition in filterGroupDefinitions)
+ {
+ var groupDto = await GroupDefinitionToDto(groupDefinition);
+
+ groups.Add(groupDto);
+ }
+
+ return new PagedResultDto(filterGroupDefinitionCount, groups);
+ }
+
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Update)]
+ public async virtual Task UpdateAsync(string name, PermissionGroupDefinitionUpdateDto input)
+ {
+ var groupDefinition = await _permissionDefinitionManager.GetGroupOrNullAsync(name);
+ var groupDefinitionRecord = await FindByNameAsync(name);
+
+ if (groupDefinitionRecord == null)
+ {
+ groupDefinitionRecord = new PermissionGroupDefinitionRecord(
+ GuidGenerator.Create(),
+ name,
+ input.DisplayName);
+
+ foreach (var property in input.ExtraProperties)
+ {
+ groupDefinitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ groupDefinitionRecord = await _groupDefinitionBasicRepository.InsertAsync(groupDefinitionRecord);
+ }
+ else
+ {
+ groupDefinitionRecord.ExtraProperties.Clear();
+ foreach (var property in input.ExtraProperties)
+ {
+ groupDefinitionRecord.SetProperty(property.Key, property.Value);
+ }
+
+ if (!string.Equals(groupDefinitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ groupDefinitionRecord.DisplayName = input.DisplayName;
+ }
+
+ groupDefinitionRecord = await _groupDefinitionBasicRepository.UpdateAsync(groupDefinitionRecord);
+ }
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord);
+
+ return dto;
+ }
+
+ protected async virtual Task FindByNameAsync(string name)
+ {
+ var groupDefinitionFilter = await _groupDefinitionBasicRepository.GetQueryableAsync();
+
+ var groupDefinitionRecord = await AsyncExecuter.FirstOrDefaultAsync(
+ groupDefinitionFilter.Where(x => x.Name == name));
+
+ return groupDefinitionRecord;
+ }
+
+ protected async virtual Task GroupDefinitionRecordToDto(PermissionGroupDefinitionRecord groupDefinitionRecord)
+ {
+ var groupDto = new PermissionGroupDefinitionDto
+ {
+ Name = groupDefinitionRecord.Name,
+ FormatedDisplayName = groupDefinitionRecord.DisplayName,
+ };
+
+ var displayName = _localizableStringSerializer.Deserialize(groupDefinitionRecord.DisplayName);
+ groupDto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory);
+
+ foreach (var property in groupDefinitionRecord.ExtraProperties)
+ {
+ groupDto.SetProperty(property.Key, property.Value);
+ }
+
+ return groupDto;
+ }
+
+ protected async virtual Task GroupDefinitionToDto(PermissionGroupDefinition groupDefinition)
+ {
+ var groupDto = new PermissionGroupDefinitionDto
+ {
+ Name = groupDefinition.Name
+ };
+
+ if (groupDefinition.DisplayName != null)
+ {
+ groupDto.DisplayName = await groupDefinition.DisplayName.LocalizeAsync(StringLocalizerFactory);
+ groupDto.FormatedDisplayName = _localizableStringSerializer.Serialize(groupDefinition.DisplayName);
+ }
+
+ foreach (var property in groupDefinition.Properties)
+ {
+ groupDto.SetProperty(property.Key, property.Value);
+ }
+
+ return groupDto;
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/PermissionManagementAppServiceBase.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/PermissionManagementAppServiceBase.cs
new file mode 100644
index 000000000..edb4c2439
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/PermissionManagementAppServiceBase.cs
@@ -0,0 +1,12 @@
+using Volo.Abp.Application.Services;
+using Volo.Abp.PermissionManagement.Localization;
+
+namespace LINGYUN.Abp.PermissionManagement;
+public abstract class PermissionManagementAppServiceBase : ApplicationService
+{
+ protected PermissionManagementAppServiceBase()
+ {
+ LocalizationResource = typeof(AbpPermissionManagementResource);
+ ObjectMapperContext = typeof(AbpPermissionManagementApplicationModule);
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManagerExtensions.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManagerExtensions.cs
new file mode 100644
index 000000000..132b6e6ea
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManagerExtensions.cs
@@ -0,0 +1,16 @@
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.Authorization.Permissions;
+public static class IPermissionDefinitionManagerExtensions
+{
+ public async static Task GetGroupOrNullAsync(
+ this IPermissionDefinitionManager permissionDefinitionManager,
+ string name
+ )
+ {
+ var groups = await permissionDefinitionManager.GetGroupsAsync();
+
+ return groups.FirstOrDefault(x => x.Name == name);
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xml b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xsd
new file mode 100644
index 000000000..11da52550
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN.Abp.PermissionManagement.HttpApi.csproj b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN.Abp.PermissionManagement.HttpApi.csproj
new file mode 100644
index 000000000..cc612254d
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN.Abp.PermissionManagement.HttpApi.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/AbpPermissionManagementHttpApiModule.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/AbpPermissionManagementHttpApiModule.cs
new file mode 100644
index 000000000..605858340
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/AbpPermissionManagementHttpApiModule.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.AspNetCore.Mvc.Localization;
+using Volo.Abp.Modularity;
+using Volo.Abp.PermissionManagement.Localization;
+using VoloAbpPermissionManagementHttpApiModule = Volo.Abp.PermissionManagement.HttpApi.AbpPermissionManagementHttpApiModule;
+
+namespace LINGYUN.Abp.PermissionManagement.HttpApi;
+
+[DependsOn(
+ typeof(AbpPermissionManagementApplicationContractsModule),
+ typeof(VoloAbpPermissionManagementHttpApiModule))]
+public class AbpPermissionManagementHttpApiModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ PreConfigure(delegate (IMvcBuilder mvcBuilder)
+ {
+ mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpPermissionManagementHttpApiModule)!.Assembly);
+ });
+
+ PreConfigure(options =>
+ {
+ options.AddAssemblyResource(
+ typeof(AbpPermissionManagementResource),
+ typeof(AbpPermissionManagementApplicationContractsModule).Assembly);
+ });
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionDefinitionController.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionDefinitionController.cs
new file mode 100644
index 000000000..b9905869f
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionDefinitionController.cs
@@ -0,0 +1,62 @@
+using LINGYUN.Abp.PermissionManagement.Definitions;
+using LINGYUN.Abp.PermissionManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.PermissionManagement;
+
+namespace LINGYUN.Abp.PermissionManagement.HttpApi.Definitions;
+
+[Controller]
+[Authorize(PermissionManagementPermissionNames.Definition.Default)]
+[RemoteService(Name = PermissionManagementRemoteServiceConsts.RemoteServiceName)]
+[Area(PermissionManagementRemoteServiceConsts.ModuleName)]
+[Route("api/permission-management/definitions")]
+public class PermissionDefinitionController : PermissionManagementControllerBase, IPermissionDefinitionAppService
+{
+ private readonly IPermissionDefinitionAppService _service;
+
+ public PermissionDefinitionController(IPermissionDefinitionAppService service)
+ {
+ _service = service;
+ }
+
+ [HttpPost]
+ [Authorize(PermissionManagementPermissionNames.Definition.Create)]
+ public virtual Task CreateAsync(PermissionDefinitionCreateDto input)
+ {
+ return _service.CreateAsync(input);
+ }
+
+ [HttpDelete]
+ [Route("{name}")]
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)]
+ public virtual Task DeleteAsync(string name)
+ {
+ return _service.DeleteAsync(name);
+ }
+
+ [HttpGet]
+ [Route("{name}")]
+ [Authorize(PermissionManagementPermissionNames.Definition.Delete)]
+ public virtual Task GetAsync(string name)
+ {
+ return _service.GetAsync(name);
+ }
+
+ [HttpGet]
+ public virtual Task> GetListAsync(PermissionDefinitionGetListInput input)
+ {
+ return _service.GetListAsync(input);
+ }
+
+ [HttpPut]
+ [Route("{name}")]
+ [Authorize(PermissionManagementPermissionNames.Definition.Update)]
+ public virtual Task UpdateAsync(string name, PermissionDefinitionUpdateDto input)
+ {
+ return _service.UpdateAsync(name, input);
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionGroupDefinitionController.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionGroupDefinitionController.cs
new file mode 100644
index 000000000..92ab1677d
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionGroupDefinitionController.cs
@@ -0,0 +1,62 @@
+using LINGYUN.Abp.PermissionManagement.Definitions;
+using LINGYUN.Abp.PermissionManagement.Permissions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.PermissionManagement;
+
+namespace LINGYUN.Abp.PermissionManagement.HttpApi.Definitions;
+
+[Controller]
+[Authorize(PermissionManagementPermissionNames.GroupDefinition.Default)]
+[RemoteService(Name = PermissionManagementRemoteServiceConsts.RemoteServiceName)]
+[Area(PermissionManagementRemoteServiceConsts.ModuleName)]
+[Route("api/permission-management/definitions/groups")]
+public class PermissionGroupDefinitionController : PermissionManagementControllerBase, IPermissionGroupDefinitionAppService
+{
+ private readonly IPermissionGroupDefinitionAppService _service;
+
+ public PermissionGroupDefinitionController(IPermissionGroupDefinitionAppService service)
+ {
+ _service = service;
+ }
+
+ [HttpPost]
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Create)]
+ public virtual Task CreateAsync(PermissionGroupDefinitionCreateDto input)
+ {
+ return _service.CreateAsync(input);
+ }
+
+ [HttpDelete]
+ [Route("{name}")]
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)]
+ public virtual Task DeleteAsync(string name)
+ {
+ return _service.DeleteAsync(name);
+ }
+
+ [HttpGet]
+ [Route("{name}")]
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)]
+ public virtual Task GetAsync(string name)
+ {
+ return _service.GetAsync(name);
+ }
+
+ [HttpGet]
+ public virtual Task> GetListAsync(PermissionGroupDefinitionGetListInput input)
+ {
+ return _service.GetListAsync(input);
+ }
+
+ [HttpPut]
+ [Route("{name}")]
+ [Authorize(PermissionManagementPermissionNames.GroupDefinition.Update)]
+ public virtual Task UpdateAsync(string name, PermissionGroupDefinitionUpdateDto input)
+ {
+ return _service.UpdateAsync(name, input);
+ }
+}
diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/PermissionManagementControllerBase.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/PermissionManagementControllerBase.cs
new file mode 100644
index 000000000..a2266adda
--- /dev/null
+++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/PermissionManagementControllerBase.cs
@@ -0,0 +1,11 @@
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.PermissionManagement.Localization;
+
+namespace LINGYUN.Abp.PermissionManagement.HttpApi;
+public abstract class PermissionManagementControllerBase : AbpControllerBase
+{
+ protected PermissionManagementControllerBase()
+ {
+ LocalizationResource = typeof(AbpPermissionManagementResource);
+ }
+}
diff --git a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj
index 0c4cc9212..4eaa76c22 100644
--- a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj
+++ b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj
@@ -4,7 +4,7 @@
- netstandard2.0
+ netstandard2.1
diff --git a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj
index 80a85ad29..c664ce204 100644
--- a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj
+++ b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj
@@ -4,7 +4,7 @@
- netstandard2.0
+ netstandard2.1
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/.gitignore b/aspnet-core/services/LY.MicroService.Applications.Single/.gitignore
new file mode 100644
index 000000000..6cdbad2bc
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/.gitignore
@@ -0,0 +1,2 @@
+wwwroot
+package*.json
\ No newline at end of file
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
index 37b961fa8..2437dde64 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
@@ -103,6 +103,8 @@
+
+
@@ -160,7 +162,9 @@
+
+
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
index 26b4d1d2d..ea3bcb9dc 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
@@ -491,6 +491,8 @@ public partial class MicroServiceApplicationsSingleModule
.AddLanguagesMapOrUpdate(
"vben-admin-ui",
new NameValue("zh_CN", "zh-Hans"));
+
+ options.UseAllPersistence();
});
Configure(options =>
@@ -553,7 +555,7 @@ public partial class MicroServiceApplicationsSingleModule
if (isDevelopment)
{
- // services.AddAlwaysAllowAuthorization();
+ services.AddAlwaysAllowAuthorization();
}
if (!isDevelopment)
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
index 7e80bc4ea..fa265d816 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
@@ -27,6 +27,8 @@ using LINGYUN.Abp.Elsa.EntityFrameworkCore;
using LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Emailing;
+using LINGYUN.Abp.FeatureManagement;
+using LINGYUN.Abp.FeatureManagement.HttpApi;
using LINGYUN.Abp.Features.LimitValidation;
using LINGYUN.Abp.Features.LimitValidation.Redis.Client;
using LINGYUN.Abp.Http.Client.Wrapper;
@@ -56,6 +58,8 @@ using LINGYUN.Abp.OpenIddict;
using LINGYUN.Abp.OssManagement;
using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp;
using LINGYUN.Abp.OssManagement.SettingManagement;
+using LINGYUN.Abp.PermissionManagement;
+using LINGYUN.Abp.PermissionManagement.HttpApi;
using LINGYUN.Abp.PermissionManagement.OrganizationUnits;
using LINGYUN.Abp.Saas;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
@@ -94,15 +98,12 @@ using Volo.Abp.Autofac;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.EventBus;
-using Volo.Abp.FeatureManagement;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Modularity;
using Volo.Abp.OpenIddict;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
-using Volo.Abp.PermissionManagement;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
-using Volo.Abp.PermissionManagement.HttpApi;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.PermissionManagement.IdentityServer;
using Volo.Abp.SettingManagement;
@@ -179,7 +180,6 @@ namespace LY.MicroService.Applications.Single;
typeof(WebhooksManagementApplicationModule),
typeof(WebhooksManagementHttpApiModule),
typeof(WebhooksManagementEntityFrameworkCoreModule),
- typeof(AbpFeatureManagementDomainModule),
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpFeatureManagementHttpApiModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
@@ -187,7 +187,6 @@ namespace LY.MicroService.Applications.Single;
typeof(AbpSettingManagementApplicationModule),
typeof(AbpSettingManagementHttpApiModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
- typeof(AbpPermissionManagementDomainModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpPermissionManagementHttpApiModule),
typeof(AbpPermissionManagementDomainIdentityModule),
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json b/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json
index e896a500f..1bf0d8d7f 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json
@@ -14,7 +14,7 @@
"launchBrowser": false,
"applicationUrl": "http://127.0.0.1:30000",
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Production"
+ "ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/gulpfile.js b/aspnet-core/services/LY.MicroService.Applications.Single/gulpfile.js
new file mode 100644
index 000000000..5dcf4c5c6
--- /dev/null
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/gulpfile.js
@@ -0,0 +1,9 @@
+"use strict";
+
+var gulp = require("gulp"),
+ path = require('path'),
+ copyResources = require('./node_modules/@abp/aspnetcore.mvc.ui/gulp/copy-resources.js');
+
+exports.default = function(){
+ return copyResources(path.resolve('./'));
+};
\ No newline at end of file
diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs
index f4750e6e8..e65c75eb3 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs
@@ -5,6 +5,8 @@ using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.OpenIddict.Permissions;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using Medallion.Threading;
+using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
@@ -26,10 +28,12 @@ using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement;
using Volo.Abp.GlobalFeatures;
+using Volo.Abp.Identity.Localization;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
+using Volo.Abp.OpenIddict.Localization;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Threading;
using Volo.Abp.UI.Navigation.Urls;
@@ -178,6 +182,16 @@ public partial class AuthServerHttpApiHostModule
});
}
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
+
private void ConfigureCaching(IConfiguration configuration)
{
Configure(options =>
@@ -268,6 +282,10 @@ public partial class AuthServerHttpApiHostModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+
+ options.UsePersistences(
+ typeof(IdentityResource),
+ typeof(AbpOpenIddictResource));
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs
index 6fd04ba1a..1cde28844 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs
+++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs
@@ -92,6 +92,7 @@ public partial class AuthServerHttpApiHostModule : AbpModule
ConfigureSwagger(context.Services);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj
index 66c71169f..a89f0e3c6 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj
+++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj
@@ -10,6 +10,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json
index 74d17f1f3..f8b69155c 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json
@@ -55,6 +55,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs
index e4b34a115..3f436d880 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs
@@ -2,6 +2,8 @@
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using Medallion.Threading.Redis;
+using Medallion.Threading;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
@@ -194,6 +196,17 @@ public partial class AuthServerModule
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
}
+
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
+
private void ConfigureCaching(IConfiguration configuration)
{
Configure(options =>
@@ -237,6 +250,8 @@ public partial class AuthServerModule
options.Resources
.Get()
.AddVirtualJson("/Localization/Resources");
+
+ options.UsePersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs
index fc632d3e8..1446881f0 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs
+++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs
@@ -9,6 +9,7 @@ using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.Identity.EntityFrameworkCore;
using LINGYUN.Abp.Identity.OrganizaztionUnits;
using LINGYUN.Abp.Localization.CultureMap;
+using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.OpenIddict.LinkUser;
using LINGYUN.Abp.OpenIddict.Sms;
using LINGYUN.Abp.OpenIddict.WeChat;
@@ -60,6 +61,7 @@ namespace LY.MicroService.AuthServer;
typeof(AbpAuthenticationQQModule),
typeof(AbpAuthenticationWeChatModule),
typeof(AbpIdentityOrganizaztionUnitsModule),
+ typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
@@ -106,6 +108,7 @@ public partial class AuthServerModule : AbpModule
ConfigureAuditing(configuration);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment());
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj b/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj
index d852ec065..e181ad8df 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj
+++ b/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj
@@ -15,6 +15,7 @@
+
@@ -56,6 +57,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json b/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json
index e66c45cb3..de3361ed3 100644
--- a/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json
@@ -29,10 +29,11 @@
"Default": "Server=127.0.0.1;Database=AuthServer-v70;User Id=root;Password=123456",
"AbpIdentity": "Server=127.0.0.1;Database=AuthServer-v70;User Id=root;Password=123456",
"OpenIddict": "Server=127.0.0.1;Database=AuthServer-v70;User Id=root;Password=123456",
- "AbpSaas": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456",
- "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456",
- "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456",
- "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456"
+ "AbpSaas": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
+ "AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-V70;User Id=root;Password=123456",
+ "AbpSettingManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
+ "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
+ "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456"
},
"CAP": {
"EventBus": {
@@ -55,6 +56,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs
index 92546e12f..7a115cf17 100644
--- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs
@@ -1,4 +1,5 @@
-using DotNetCore.CAP;
+using Autofac.Core;
+using DotNetCore.CAP;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Localization.CultureMap;
@@ -6,6 +7,8 @@ using LINGYUN.Abp.Saas;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LINGYUN.Abp.TextTemplating;
+using Medallion.Threading.Redis;
+using Medallion.Threading;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
@@ -181,6 +184,16 @@ public partial class BackendAdminHttpApiHostModule
});
}
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
+
private void ConfigureVirtualFileSystem()
{
Configure(options =>
@@ -280,6 +293,8 @@ public partial class BackendAdminHttpApiHostModule
.AddLanguagesMapOrUpdate(
"vben-admin-ui",
new NameValue("zh_CN", "zh-Hans"));
+
+ options.UseAllPersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs
index bcdd76896..851ec6abf 100644
--- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs
+++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs
@@ -1,5 +1,4 @@
-using DotNetCore.CAP;
-using LINGYUN.Abp.AspNetCore.HttpOverrides;
+using LINGYUN.Abp.AspNetCore.HttpOverrides;
using LINGYUN.Abp.AspNetCore.Mvc.Localization;
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper;
using LINGYUN.Abp.Auditing;
@@ -10,11 +9,14 @@ using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.FeatureManagement;
+using LINGYUN.Abp.FeatureManagement.HttpApi;
using LINGYUN.Abp.Http.Client.Wrapper;
using LINGYUN.Abp.Identity.EntityFrameworkCore;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.Logging.Serilog.Elasticsearch;
+using LINGYUN.Abp.PermissionManagement;
+using LINGYUN.Abp.PermissionManagement.HttpApi;
using LINGYUN.Abp.PermissionManagement.OrganizationUnits;
using LINGYUN.Abp.Saas;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
@@ -24,12 +26,12 @@ using LINGYUN.Abp.SettingManagement;
using LINGYUN.Abp.Sms.Aliyun;
using LINGYUN.Abp.TextTemplating;
using LINGYUN.Abp.TextTemplating.EntityFrameworkCore;
+using LINGYUN.Abp.TextTemplating.Scriban;
using LY.MicroService.BackendAdmin.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-using System.Linq;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
@@ -37,13 +39,10 @@ using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.EntityFrameworkCore.MySQL;
-using Volo.Abp.FeatureManagement;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
using Volo.Abp.Modularity;
-using Volo.Abp.PermissionManagement;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
-using Volo.Abp.PermissionManagement.HttpApi;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.PermissionManagement.IdentityServer;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
@@ -97,6 +96,7 @@ namespace LY.MicroService.BackendAdmin;
typeof(AbpLocalizationCultureMapModule),
typeof(AbpHttpClientWrapperModule),
typeof(AbpAspNetCoreMvcWrapperModule),
+ typeof(AbpTextTemplatingScribanModule),
typeof(AbpAutofacModule)
)]
public partial class BackendAdminHttpApiHostModule : AbpModule
@@ -128,6 +128,7 @@ public partial class BackendAdminHttpApiHostModule : AbpModule
ConfigureSwagger(context.Services);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment());
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj
index 0686ca906..7c0a0f5e4 100644
--- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj
+++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj
@@ -14,6 +14,7 @@
+
@@ -55,6 +56,8 @@
+
+
@@ -66,7 +69,9 @@
+
+
@@ -75,5 +80,6 @@
+
diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json
index 80ee99743..47ca95b17 100644
--- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json
@@ -60,6 +60,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj
index 51cce78a3..78d1fa139 100644
--- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj
+++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj
@@ -10,6 +10,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs
index bb491d1c0..9ab597ce3 100644
--- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs
@@ -4,6 +4,8 @@ using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using Medallion.Threading.Redis;
+using Medallion.Threading;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
@@ -28,7 +30,7 @@ using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
-
+using LINGYUN.Abp.LocalizationManagement.Localization;
namespace LY.MicroService.LocalizationManagement;
@@ -144,6 +146,15 @@ public partial class LocalizationManagementHttpApiHostModule
}
});
}
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
private void ConfigureCaching(IConfiguration configuration)
{
@@ -216,6 +227,8 @@ public partial class LocalizationManagementHttpApiHostModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+
+ options.UsePersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs
index 4f58d9727..cfda98277 100644
--- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs
+++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs
@@ -84,6 +84,7 @@ namespace LY.MicroService.LocalizationManagement
ConfigureSwagger(context.Services);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment());
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json
index b25a694b0..6fac88373 100644
--- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json
@@ -50,6 +50,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj
index 65403e9e7..81c069075 100644
--- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj
+++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj
@@ -10,6 +10,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs
index 858aea532..f09f6d410 100644
--- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs
@@ -4,6 +4,9 @@ using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using LINGYUN.Platform.Localization;
+using Medallion.Threading;
+using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
@@ -178,6 +181,16 @@ public partial class PlatformManagementHttpApiHostModule
});
}
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
+
private void ConfigureCaching(IConfiguration configuration)
{
Configure(options =>
@@ -262,6 +275,8 @@ public partial class PlatformManagementHttpApiHostModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+
+ options.UsePersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs
index e55316df9..fa7858839 100644
--- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs
+++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs
@@ -120,6 +120,7 @@ public partial class PlatformManagementHttpApiHostModule : AbpModule
ConfigureSwagger(context.Services);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment());
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json
index 5de881913..b0ec23206 100644
--- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json
@@ -83,6 +83,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj
index af338c52f..199a15653 100644
--- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj
+++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj
@@ -14,6 +14,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs
index 10eb0c53b..f7a322e91 100644
--- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs
@@ -7,6 +7,8 @@ using LINGYUN.Abp.Notifications;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LY.MicroService.RealtimeMessage.BackgroundJobs;
+using Medallion.Threading.Redis;
+using Medallion.Threading;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
@@ -36,6 +38,7 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.Quartz;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
+using LINGYUN.Abp.Notifications.Localization;
namespace LY.MicroService.RealtimeMessage;
@@ -190,6 +193,16 @@ public partial class RealtimeMessageHttpApiHostModule
});
}
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
+
private void ConfigureCaching(IConfiguration configuration)
{
Configure(options =>
@@ -333,6 +346,10 @@ public partial class RealtimeMessageHttpApiHostModule
options.Resources
.Get()
.AddVirtualJson("/Localization/Resources");
+
+ options.UsePersistences(
+ typeof(MessageServiceResource),
+ typeof(NotificationsResource));
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs
index b9327c39d..ed73ad8c0 100644
--- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs
+++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs
@@ -134,6 +134,7 @@ public partial class RealtimeMessageHttpApiHostModule : AbpModule
ConfigureSwagger(context.Services);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment());
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json
index 273ea5c8e..fb38ce161 100644
--- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json
@@ -47,6 +47,12 @@
"AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456",
"AbpTextTemplating": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456"
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"IsEnabled": true,
"Configuration": "127.0.0.1,defaultDatabase=8",
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs
index ad9bdebb1..56602315c 100644
--- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs
@@ -5,6 +5,7 @@ using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using LINGYUN.Abp.TaskManagement.Localization;
using Medallion.Threading;
using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Authentication.JwtBearer;
@@ -126,8 +127,12 @@ public partial class TaskManagementHttpApiHostModule
private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration)
{
- var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
- services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
}
private void ConfigureDbContext()
@@ -275,6 +280,8 @@ public partial class TaskManagementHttpApiHostModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+
+ options.UsePersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json
index c03b0e207..283ac37d2 100644
--- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json
@@ -80,6 +80,7 @@
}
},
"DistributedLock": {
+ "IsEnabled": true,
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=15"
}
diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs
index 31af82d0c..069951ab4 100644
--- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs
@@ -7,6 +7,7 @@ using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LINGYUN.Abp.Webhooks;
using LINGYUN.Abp.Webhooks.BackgroundJobs;
using LINGYUN.Abp.WebhooksManagement;
+using LINGYUN.Abp.WebhooksManagement.Localization;
using LINGYUN.Abp.Wrapper;
using Medallion.Threading;
using Medallion.Threading.Redis;
@@ -342,6 +343,8 @@ public partial class WebhooksManagementHttpApiHostModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+
+ options.UsePersistence();
});
}
diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs
index 9dc187c7f..c6e134fa1 100644
--- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs
@@ -5,6 +5,7 @@ using Elsa.Options;
using Elsa.Rebus.RabbitMq;
using LINGYUN.Abp.BackgroundTasks;
using LINGYUN.Abp.BlobStoring.OssManagement;
+using LINGYUN.Abp.Elsa.Localization;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Localization.CultureMap;
@@ -369,6 +370,8 @@ public partial class WorkflowManagementHttpApiHostModule
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
+
+ options.UsePersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs
index 70dbdf4a9..ec6f496d7 100644
--- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs
@@ -4,6 +4,8 @@ using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
+using Medallion.Threading.Redis;
+using Medallion.Threading;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
@@ -34,6 +36,7 @@ using Volo.Abp.PermissionManagement;
using Volo.Abp.Threading;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;
+using Volo.Abp.IdentityServer.Localization;
namespace LY.MicroService.IdentityServer;
@@ -177,6 +180,15 @@ public partial class IdentityServerHttpApiHostModule
options.Applications["STS"].RootUrl = configuration["App:StsUrl"];
});
}
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
private void ConfigureCaching(IConfiguration configuration)
{
@@ -272,6 +284,10 @@ public partial class IdentityServerHttpApiHostModule
options.Resources
.Get()
.AddVirtualJson("/Localization/Resources");
+
+ options.UsePersistences(
+ typeof(IdentityResource),
+ typeof(AbpIdentityServerResource));
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs
index 65bb3a130..71c228cf7 100644
--- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs
+++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs
@@ -94,6 +94,7 @@ public partial class IdentityServerHttpApiHostModule : AbpModule
ConfigureSwagger(context.Services);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj
index 94c13e1a4..ab1ae994f 100644
--- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj
+++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj
@@ -18,6 +18,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json
index a6b151399..ee970f9d9 100644
--- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json
@@ -55,6 +55,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"
diff --git a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs
index 9db5936b8..2a58c3f12 100644
--- a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs
@@ -4,6 +4,8 @@ using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
using LY.MicroService.IdentityServer.IdentityResources;
+using Medallion.Threading;
+using Medallion.Threading.Redis;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
@@ -144,6 +146,17 @@ public partial class IdentityServerModule
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
}
+
+ private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)
+ {
+ var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];
+ if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled))
+ {
+ var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]);
+ services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase()));
+ }
+ }
+
private void ConfigureCaching(IConfiguration configuration)
{
Configure(options =>
@@ -201,6 +214,8 @@ public partial class IdentityServerModule
options.Resources
.Get()
.AddVirtualJson("/Localization/Resources");
+
+ options.UsePersistence();
});
Configure(options =>
diff --git a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs
index 1482b2007..664a90681 100644
--- a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs
+++ b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs
@@ -13,6 +13,7 @@ using LINGYUN.Abp.Identity.OrganizaztionUnits;
using LINGYUN.Abp.IdentityServer;
using LINGYUN.Abp.IdentityServer.EntityFrameworkCore;
using LINGYUN.Abp.Localization.CultureMap;
+using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
@@ -59,6 +60,7 @@ namespace LY.MicroService.IdentityServer;
typeof(AbpAuthenticationWeChatModule),
typeof(AbpAuthenticationQQModule),
typeof(AbpIdentityOrganizaztionUnitsModule),
+ typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
@@ -108,6 +110,7 @@ public partial class IdentityServerModule : AbpModule
ConfigureUrls(configuration);
ConfigureMultiTenancy(configuration);
ConfigureCors(context.Services, configuration);
+ ConfigureDistributedLocking(context.Services, configuration);
ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment());
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment());
}
diff --git a/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj b/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj
index fd9d7a66f..0fd004f62 100644
--- a/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj
+++ b/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj
@@ -16,6 +16,7 @@
+
@@ -58,6 +59,7 @@
+
diff --git a/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json b/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json
index 8c5e09b4c..f4e522891 100644
--- a/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json
+++ b/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json
@@ -55,6 +55,12 @@
"VirtualHost": "/"
}
},
+ "DistributedLock": {
+ "IsEnabled": true,
+ "Redis": {
+ "Configuration": "127.0.0.1,defaultDatabase=13"
+ }
+ },
"Redis": {
"Configuration": "127.0.0.1,defaultDatabase=10",
"InstanceName": "LINGYUN.Abp.Application"