diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..9805011759
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,137 @@
+# EditorConfig is awesome: https://EditorConfig.org
+# Please feel free to update it (by considering the code style of ABP Team).
+# top-most EditorConfig file
+root = true
+
+[*.cs]
+
+#Namespace settings
+csharp_style_namespace_declarations = file_scoped
+dotnet_diagnostic.IDE0161.severity = warning
+
+#Core editorconfig formatting - indentation
+
+#use tabs for indentation
+indent_style = tabs
+
+#Formatting - indentation options
+
+#indent switch case contents.
+csharp_indent_case_contents = true
+#indent switch labels
+csharp_indent_switch_labels = true
+
+#Formatting - new line options
+
+#place catch statements on a new line
+csharp_new_line_before_catch = true
+#place else statements on a new line
+csharp_new_line_before_else = true
+#require members of object intializers to be on separate lines
+csharp_new_line_before_members_in_object_initializers = true
+#require braces to be on a new line for object_collection_array_initializers, methods, control_blocks, types, and lambdas (also known as "Allman" style)
+csharp_new_line_before_open_brace = object_collection_array_initializers, methods, control_blocks, types, lambdas
+
+#Formatting - organize using options
+
+#sort System.* using directives alphabetically, and place them before other usings
+dotnet_sort_system_directives_first = true
+
+#Formatting - spacing options
+
+#require NO space between a cast and the value
+csharp_space_after_cast = false
+#require a space before the colon for bases or interfaces in a type declaration
+csharp_space_after_colon_in_inheritance_clause = true
+#require a space after a keyword in a control flow statement such as a for loop
+csharp_space_after_keywords_in_control_flow_statements = true
+#require a space before the colon for bases or interfaces in a type declaration
+csharp_space_before_colon_in_inheritance_clause = true
+#remove space within empty argument list parentheses
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+#remove space between method call name and opening parenthesis
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
+csharp_space_between_method_call_parameter_list_parentheses = false
+#remove space within empty parameter list parentheses for a method declaration
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+
+#Formatting - wrapping options
+
+#leave code block on single line
+csharp_preserve_single_line_blocks = true
+
+#Style - Code block preferences
+
+#prefer curly braces even for one line of code
+csharp_prefer_braces = true:suggestion
+
+#Style - expression bodied member options
+
+#prefer block bodies for constructors
+csharp_style_expression_bodied_constructors = false:suggestion
+#prefer block bodies for methods
+csharp_style_expression_bodied_methods = false:suggestion
+#prefer expression-bodied members for properties
+csharp_style_expression_bodied_properties = true:suggestion
+
+#Style - expression level options
+
+#prefer out variables to be declared inline in the argument list of a method call when possible
+csharp_style_inlined_variable_declaration = true:suggestion
+#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+#Style - Expression-level preferences
+
+#prefer default over default(T)
+csharp_prefer_simple_default_expression = true:suggestion
+#prefer objects to be initialized using object initializers when possible
+dotnet_style_object_initializer = true:suggestion
+#prefer inferred tuple element names
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+
+#Style - implicit and explicit types
+
+#prefer var over explicit type in all cases, unless overridden by another code style rule
+csharp_style_var_elsewhere = true:suggestion
+#prefer var is used to declare variables with built-in system types such as int
+csharp_style_var_for_built_in_types = true:suggestion
+#prefer var when the type is already mentioned on the right-hand side of a declaration expression
+csharp_style_var_when_type_is_apparent = true:suggestion
+
+#Style - language keyword and framework type options
+
+#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+
+#Style - Miscellaneous preferences
+
+#prefer local functions over anonymous functions
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+
+#Style - modifier options
+
+#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
+
+#Style - Modifier preferences
+
+#when this rule is set to a list of modifiers, prefer the specified ordering.
+csharp_preferred_modifier_order = public,protected,private,virtual,async,readonly,static,override,abstract:suggestion
+
+#Style - Pattern matching
+
+#prefer pattern matching instead of is expression with type casts
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+
+#Style - qualification options
+
+#prefer fields not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_field = false:suggestion
+#prefer methods not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_method = false:suggestion
+#prefer properties not to be prefaced with this. or Me. in Visual Basic
+dotnet_style_qualification_for_property = false:suggestion
diff --git a/.gitignore b/.gitignore
index d3968773a0..786eba6270 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@
*.user
*.userosscache
*.sln.docstates
-*.editorconfig
+
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json
index 4ea99af7e1..f64b385908 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json
@@ -210,6 +210,10 @@
"Completed": "Completed",
"Failed": "Failed",
"PaymentRequestDeletionWarningMessage": "This payment request will be deleted. Do you confirm that?",
- "Payment": "Payment"
+ "Payment": "Payment",
+ "Permission:SendWelcomeEmail": "Send Welcome Email",
+ "SendWelcomeEmail": "Send Welcome Email",
+ "SendWelcomeEmailWarningMessage": "Are you sure you want to send welcome email to the organization members?",
+ "SendWelcomeEmailSuccessMessage": "Welcome email sent successfully!"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
index 923535cfdd..808c19a094 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
@@ -352,6 +352,10 @@
"Volo.AbpIo.Commercial:030008": "Purchase date can be set only when status is Purchased!",
"Volo.AbpIo.Commercial:030009": "User not found!",
"Volo.AbpIo.Commercial:030010": "To purchase the trial license, first you need to activate your trial license!",
- "Volo.AbpIo.Commercial:030011": "You cannot delete a trial license when it is purchased!"
+ "Volo.AbpIo.Commercial:030011": "You cannot delete a trial license when it is purchased!",
+ "Permission:SendWelcomeEmail": "Send Welcome Email",
+ "SendWelcomeEmail": "Send Welcome Email",
+ "SendWelcomeEmailWarningMessage": "Are you sure you want to send welcome email to the organization members?",
+ "SendWelcomeEmailSuccessMessage": "Welcome email sent successfully!"
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json
index 1bba0bb964..5942fca747 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json
@@ -348,6 +348,10 @@
"Volo.AbpIo.Commercial:030008": "Satın alma tarihi yalnızca durum Satın Alındı olduğunda ayarlanabilir!",
"Volo.AbpIo.Commercial:030009": "Kullanıcı bulunamadı!",
"Volo.AbpIo.Commercial:030010": "Deneme lisansını satın almak için önce deneme lisansınızı etkinleştirmeniz gerekir!",
- "Volo.AbpIo.Commercial:030011": "Satın alındığında bir deneme lisansını silemezsiniz!"
+ "Volo.AbpIo.Commercial:030011": "Satın alındığında bir deneme lisansını silemezsiniz!",
+ "Permission:SendWelcomeEmail": "Hoşgeldin Emaili Gönder",
+ "SendWelcomeEmail": "Hoşgeldin Emaili Gönder",
+ "SendWelcomeEmailWarningMessage": "Organizasyon üyelerine hoşgeldin emaili göndermek istediğinden emin misin?",
+ "SendWelcomeEmailSuccessMessage": "Hoşgeldin emaili başarıyla gönderilmiştir!"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
index f4a8153ec1..cc31f83529 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
@@ -178,7 +178,7 @@
"ChangingLicenseType": "Can I upgrade my license type later?",
"ChangingLicenseTypeExplanation": "You can upgrade to a higher license by paying the difference within your active license period. When you upgrade to a higher license plan, you get the benefits of the new plan, but the license upgrade does not change the license expiry date. Besides, you can also add new developer seats to your existing license, see \"How many developers can work on the ABP Commercial?\"",
"LicenseExtendUpgradeDiff": "What is the difference between license extend and upgrade?",
- "LicenseExtendUpgradeDiffExplanation": "Extending: By extending/renewing your license, you will continue to get premium support and get major updates for the modules and themes. Besides, you will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development.
Upgrading: By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the license comparison table to check the differences between the license plans.On the other hand, when you upgrade, your license expiry date will not change!To extend your license end date, you need to extend your license.",
+ "LicenseExtendUpgradeDiffExplanation": "Extending: By extending/renewing your license, you will continue to get premium support and get major updates for the modules and themes. Besides, you will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development. When you extend your license, 1 year is added to your license expiry date. Upgrading: By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the license comparison table to check the differences between the license plans.On the other hand, when you upgrade, your license expiry date will not change!To extend your license end date, you need to extend your license.",
"LicenseRenewalCost": "What is the license renewal cost after 1 year?",
"LicenseRenewalCostExplanation": "The renewal (extend) rate of all ABP Commercial perpetual licenses is {0} of the license list price. The renewal price of the standard Team License is ${1}, standard Business License is ${2} and standard Enterprise License is ${3}. If you are already a customer, log into your account to review the available renewal pricing.",
"HowDoIRenewMyLicense": "How do I renew my license?",
@@ -390,6 +390,10 @@
"TrialLicenseExpireMessage": "You are using the trial license and your trial license will expire on {0}.",
"TryForFree": "Try For Free",
"TrialLicenseExpiredInfo": "Your trial license period has expired!",
- "CommercialNewsletterConfirmationMessage": "I agree to the Terms & Conditions and Privacy Policy."
- }
+ "CommercialNewsletterConfirmationMessage": "I agree to the Terms & Conditions and Privacy Policy.",
+ "DowngradeLicensePlan": "Can I downgrade to a lower license plan in the future?",
+ "DowngradeLicensePlanExplanation": "You cannot downgrade your existing license plan. But you can purchase a new lower license plan and continue to your development on the new license. After you purchase a lower license, you just need to login to your new license plan via ABP CLI command: ` abp login -o `.",
+ "LicenseTransfer": "Can a license be transferred from one developer to another?",
+ "LicenseTransferExplanation": "Yes! When you purchase a license, you become the license holder, hence you will have access to the organization management page. An organization has owner and developer roles. Owners can manage the developer seats and assign developers. Each assigned developer will login via ABP CLI command into the system and will have development and support permissions."
+ }
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json
index 44d5d79aac..751b33613e 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "يجب عليك إدخال 3 أحرف على الأقل!",
"Volo.AbpIo.Domain:060001": "عنوان URL المصدر (\"{ArticleUrl}\") ليس عنوان URL لـ Github",
"Volo.AbpIo.Domain:060002": "محتوى المقالة غير متوفر من مورد Github (\"{ArticleUrl}\").",
- "Volo.AbpIo.Domain:060003": "لم يتم العثور على محتوى مقال!"
+ "Volo.AbpIo.Domain:060003": "لم يتم العثور على محتوى مقال!",
+ "SeeMore": "شاهد المزيد"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de-DE.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de-DE.json
index 9dc7da3144..f3da536e7e 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de-DE.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de-DE.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Sie müssen mindestens 3 Zeichen eingeben!",
"Volo.AbpIo.Domain:060001": "Quell-URL(\"{ArticleUrl}\") ist keine Github-URL",
"Volo.AbpIo.Domain:060002": "Artikelinhalt ist über die Github(\"{ArticleUrl}\")-Ressource nicht verfügbar.",
- "Volo.AbpIo.Domain:060003": "Kein Artikelinhalt gefunden!"
+ "Volo.AbpIo.Domain:060003": "Kein Artikelinhalt gefunden!",
+ "SeeMore": "Mehr Sehen"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
index 652090d864..5925ffb172 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
@@ -101,6 +101,7 @@
"ArticleRequestMessageTitle": "Open an issue on the GitHub to request an article/tutorial you want to see on this web site.",
"ArticleRequestMessageBody": "Here is the list of the requested articles by the Community. Do you want to write a requested article? Please click on the request and join the discussion.",
"Language": "Language",
- "CreateArticleLanguageInfo": "The language in which the article is written"
+ "CreateArticleLanguageInfo": "Language of the article",
+ "SeeMore": "See More"
}
-}
\ No newline at end of file
+}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
index 2da4a62481..16a86cac37 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "You must enter at least 3 characters!",
"Volo.AbpIo.Domain:060001": "Source URL(\"{ArticleUrl}\") is not Github URL",
"Volo.AbpIo.Domain:060002": "Article Content is not available from Github(\"{ArticleUrl}\") resource.",
- "Volo.AbpIo.Domain:060003": "No article content found!"
+ "Volo.AbpIo.Domain:060003": "No article content found!",
+ "SeeMore": "See More"
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json
index 7b34e043a7..3066263e8b 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "¡Debes ingresar al menos 3 caracteres!",
"Volo.AbpIo.Domain:060001": "La URL de origen (\"{ArticleUrl}\") no es la URL de Github",
"Volo.AbpIo.Domain:060002": "El contenido del artículo no está disponible en el recurso de Github (\"{ArticleUrl}\").",
- "Volo.AbpIo.Domain:060003": "¡No se encontró contenido del artículo!"
+ "Volo.AbpIo.Domain:060003": "¡No se encontró contenido del artículo!",
+ "SeeMore": "Ver Más"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json
index 2c09984774..435ac1ef92 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Sinun on annettava vähintään 3 merkkiä!",
"Volo.AbpIo.Domain:060001": "Lähteen URL-osoite (\"{ArticleUrl}\") ei ole Githubin URL-osoite",
"Volo.AbpIo.Domain:060002": "Artikkelin sisältö ei ole saatavilla Githubin (\"{ArticleUrl}\") -resurssista.",
- "Volo.AbpIo.Domain:060003": "Artikkelin sisältöä ei löytynyt!"
+ "Volo.AbpIo.Domain:060003": "Artikkelin sisältöä ei löytynyt!",
+ "SeeMore": "Katso Lisää"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json
index 42f239f987..cbeb8ae084 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Vous devez saisir au moins 3 caractères!",
"Volo.AbpIo.Domain:060001": "L'URL source (\"{ArticleUrl}\") n'est pas une URL Github",
"Volo.AbpIo.Domain:060002": "Le contenu de l'article n'est pas disponible à partir de la ressource Github(\"{ArticleUrl}\").",
- "Volo.AbpIo.Domain:060003": "Aucun contenu d'article trouvé !"
+ "Volo.AbpIo.Domain:060003": "Aucun contenu d'article trouvé !",
+ "SeeMore": "Voir Plus"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json
index aa351262ca..1e8d5a9e9f 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "आपको कम से कम 3 वर्ण दर्ज करने होंगे!",
"Volo.AbpIo.Domain:060001": "स्रोत URL (\"{ArticleUrl}\") जीथब URL नहीं है",
"Volo.AbpIo.Domain:060002": "लेख सामग्री Github (\"{ArticleUrl}\") संसाधन से उपलब्ध नहीं है।",
- "Volo.AbpIo.Domain:060003": "कोई लेख सामग्री नहीं मिली!"
+ "Volo.AbpIo.Domain:060003": "कोई लेख सामग्री नहीं मिली!",
+ "SeeMore": "और देखें"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json
index fd128eb596..7c8f3f2fba 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Þú verður að slá inn að minnsta kosti 3 stafi!",
"Volo.AbpIo.Domain:060001": "Upprunaslóð (\"{ArticleUrl} \") er ekki Github slóð",
"Volo.AbpIo.Domain:060002": "Innihald greinar er ekki fáanlegt frá Github (\"{ArticleUrl} \") resoursum.",
- "Volo.AbpIo.Domain:060003": "Innihald greinar fannst ekki!"
+ "Volo.AbpIo.Domain:060003": "Innihald greinar fannst ekki!",
+ "SeeMore": "Sjá Meira"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json
index f104045682..1b305d9b4a 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Devi inserire almeno 3 caratteri!",
"Volo.AbpIo.Domain:060001": "Source URL(\"{ArticleUrl}\") non è un URL di GitHub",
"Volo.AbpIo.Domain:060002": "Il contenuto dell'articolo non è disponibile dalla risorsa Github(\"{ArticleUrl}\").",
- "Volo.AbpIo.Domain:060003": "Nessun contenuto dell'articolo trovato!"
+ "Volo.AbpIo.Domain:060003": "Nessun contenuto dell'articolo trovato!",
+ "SeeMore": "Vedi Altro"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
index 4c78f15d99..a15a1bc102 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Trebuie să introduceţi cel putin 3 caractere!",
"Volo.AbpIo.Domain:060001": "Sursa URL(\"{ArticleUrl}\") nu este URL GitHub",
"Volo.AbpIo.Domain:060002": "Conţinutul articolului nu este disponibil din resursa de pe GitHub(\"{ArticleUrl}\").",
- "Volo.AbpIo.Domain:060003": "Nu a fost găsit conţinutul articolului!"
+ "Volo.AbpIo.Domain:060003": "Nu a fost găsit conţinutul articolului!",
+ "SeeMore": "Vezi mai mult"
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json
index e01e201969..3a2b2e5f1d 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "Musíte zadať aspoň 3 znaky!",
"Volo.AbpIo.Domain:060001": "Zdrojová URL(\"{ArticleUrl}\") nie je URL Githubu",
"Volo.AbpIo.Domain:060002": "Obsah článku nie je dostupný v Github zdroji(\"{ArticleUrl}\").",
- "Volo.AbpIo.Domain:060003": "Nenašiel sa žiadny obsah článku!"
+ "Volo.AbpIo.Domain:060003": "Nenašiel sa žiadny obsah článku!",
+ "SeeMore": "Vidět Víc"
}
}
\ No newline at end of file
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
index f504842e70..15dd748d6e 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
@@ -142,6 +142,7 @@
"MinimumSearchContent": "您必须输入至少 3 个字符!",
"Volo.AbpIo.Domain:060001": "源 URL(\"{ArticleUrl}\") 不是 Github URL",
"Volo.AbpIo.Domain:060002": "文章内容无法从 Github(\"{ArticleUrl}\") 资源中获得。",
- "Volo.AbpIo.Domain:060003": "没有找到文章内容!"
+ "Volo.AbpIo.Domain:060003": "没有找到文章内容!",
+ "SeeMore": "查看更多"
}
}
\ No newline at end of file
diff --git a/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/POST.md b/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/POST.md
index e1bc93e23a..32ab4684f2 100644
--- a/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/POST.md
+++ b/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/POST.md
@@ -127,13 +127,7 @@ First of all, you need to have EF Core or MongoDB installed into your solution.
#### Install the packages
-Install the new [Volo.Abp.EventBus.Boxes](https://www.nuget.org/packages/Volo.Abp.EventBus.Boxes) NuGet package to your database layer (to `EntityFrameworkCore` or `MongoDB` project) or to the host application. Open a command-line terminal at the root directory of your database (or host) project and execute the following command:
-
-````csharp
-abp add-package Volo.Abp.EventBus.Boxes
-````
-
-This will install the package and setup the ABP module dependency. This package depends on [DistributedLock.Core](https://www.nuget.org/packages/DistributedLock.Core) library which provides a distributed locking system for concurrency control in a distributed environment. There are [many distributed lock providers](https://github.com/madelson/DistributedLock#implementations), including Redis, SqlServer and ZooKeeper. You can use the one you like. Here, I will show the Redis provider.
+For the outbox & inbox functionality, ABP depends on [DistributedLock.Core](https://www.nuget.org/packages/DistributedLock.Core) library which provides a distributed locking system for concurrency control in a distributed environment. There are [many distributed lock providers](https://github.com/madelson/DistributedLock#implementations), including Redis, SqlServer and ZooKeeper. You can use the one you like. Here, I will show the Redis provider.
Add [DistributedLock.Redis](https://www.nuget.org/packages/DistributedLock.Redis) NuGet package to your project, then add the following code into the ConfigureService method of your ABP module class:
@@ -285,6 +279,16 @@ This can be a breaking change in rare cases (for example, if you create host sid
## Community News
+### ABP Community Talks 2021.12
+
+
+
+As the core ABP development team, we've decided to organize monthly live meetings with the ABP community. The first live meeting will be at **December 16, 2021, 17:00 (UTC)** on YouTube. ABP core team members will present some of the new features coming with ABP 5.0.
+
+**Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-4afca9c9**
+
+You can also [subscribe to the Volosoft channel](https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ) for reminders for further ABP events and videos.
+
### ABP was on ASP.NET Community Startup!
It was great for us to be invited to Microsoft's [ASP.NET Community Weekly Standup](https://dotnet.microsoft.com/live/community-standup) show, at September 28. There was a very high attention and that made us very happy. Thanks to the ABP Community and all the watchers :) If you've missed the talk, [you can watch it here](https://www.youtube.com/watch?v=vMWM-_ihjwM).
diff --git a/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/community-talks.png b/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/community-talks.png
new file mode 100644
index 0000000000..4056d1afb8
Binary files /dev/null and b/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/community-talks.png differ
diff --git a/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/cover-50.png b/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/cover-50.png
new file mode 100644
index 0000000000..bd343e70b0
Binary files /dev/null and b/docs/en/Blog-Posts/2021-11-18 v5_0_Preview/cover-50.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md
new file mode 100644
index 0000000000..6abf984298
--- /dev/null
+++ b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md
@@ -0,0 +1,1671 @@
+# Many to Many Relationship with ABP and EF Core
+
+## Introduction
+
+In this article, we'll create a **BookStore** application like in [the ABP tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF) and add an extra `Category` feature to demonstrate how we can manage the many-to-many relationship with ABP-based applications (by following DDD rules).
+
+You can see the ER Diagram of our application below. This diagram will be helpful for us to demonstrate the relations between our entities.
+
+
+
+When we've examined the ER Diagram, we can see the one-to-many relationship between the **Author** and the **Book** tables. Also, the many-to-many relationship (**BookCategory** table) between the **Book** and the **Category** tables. (There can be more than one category on each book and vice-versa in our scenario).
+
+### Source Code
+
+You can find the source code of the application at https://github.com/EngincanV/ABP-Many-to-Many-Relationship-Demo .
+
+### Demo of the Final Application
+
+At the end of this article, we will have created an application same as in the gif below.
+
+
+
+## Creating the Solution
+
+In this article, we will create a new startup template with EF Core as a database provider and MVC for UI framework.
+
+* We can create a new startup template by using the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI):
+
+```bash
+abp new BookStore -t app --version 5.0.0-beta.2
+```
+
+* Our project boilerplate will be ready after the download is finished. Then, we can open the solution and start developing.
+
+## Starting the Development
+
+Let's start with creating our Domain Entities.
+
+### Step 1 - (Creating the Domain Entities)
+
+We can create a folder-structure under the `BookStore.Domain` project like in the image below.
+
+
+
+Open the entity classes and add the following codes to each of these classes.
+
+* **Author.cs**
+
+```csharp
+using System;
+using JetBrains.Annotations;
+using Volo.Abp;
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace BookStore.Authors
+{
+ public class Author : FullAuditedAggregateRoot
+ {
+ public string Name { get; private set; }
+
+ public DateTime BirthDate { get; set; }
+
+ public string ShortBio { get; set; }
+
+ /* This constructor is for deserialization / ORM purpose */
+ private Author()
+ {
+ }
+
+ public Author(Guid id, [NotNull] string name, DateTime birthDate, [CanBeNull] string shortBio = null)
+ : base(id)
+ {
+ SetName(name);
+ BirthDate = birthDate;
+ ShortBio = shortBio;
+ }
+
+ public void SetName([NotNull] string name)
+ {
+ Name = Check.NotNullOrWhiteSpace(
+ name,
+ nameof(name),
+ maxLength: AuthorConsts.MaxNameLength
+ );
+ }
+ }
+}
+```
+
+> We'll create the `AuthorConsts` class later in this step.
+
+* **Book.cs**
+
+```csharp
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Volo.Abp;
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace BookStore.Books
+{
+ public class Book : FullAuditedAggregateRoot
+ {
+ public Guid AuthorId { get; set; }
+
+ public string Name { get; private set; }
+
+ public DateTime PublishDate { get; set; }
+
+ public float Price { get; set; }
+
+ public ICollection Categories { get; private set; }
+
+ private Book()
+ {
+ }
+
+ public Book(Guid id, Guid authorId, string name, DateTime publishDate, float price)
+ : base(id)
+ {
+ AuthorId = authorId;
+ SetName(name);
+ PublishDate = publishDate;
+ Price = price;
+
+ Categories = new Collection();
+ }
+
+ public void SetName(string name)
+ {
+ Name = Check.NotNullOrWhiteSpace(name, nameof(name), BookConsts.MaxNameLength);
+ }
+
+ public void AddCategory(Guid categoryId)
+ {
+ Check.NotNull(categoryId, nameof(categoryId));
+
+ if (IsInCategory(categoryId))
+ {
+ return;
+ }
+
+ Categories.Add(new BookCategory(bookId: Id, categoryId));
+ }
+
+ public void RemoveCategory(Guid categoryId)
+ {
+ Check.NotNull(categoryId, nameof(categoryId));
+
+ if (!IsInCategory(categoryId))
+ {
+ return;
+ }
+
+ Categories.RemoveAll(x => x.CategoryId == categoryId);
+ }
+
+ public void RemoveAllCategoriesExceptGivenIds(List categoryIds)
+ {
+ Check.NotNullOrEmpty(categoryIds, nameof(categoryIds));
+
+ Categories.RemoveAll(x => !categoryIds.Contains(x.CategoryId));
+ }
+
+ public void RemoveAllCategories()
+ {
+ Categories.RemoveAll(x => x.BookId == Id);
+ }
+
+ private bool IsInCategory(Guid categoryId)
+ {
+ return Categories.Any(x => x.CategoryId == categoryId);
+ }
+ }
+}
+```
+
+* In our scenario, a book can have more than one category and a category can have more than one book so we need to create a many-to-many relationship between them.
+
+* For achieving this, we will create a **join entity** named `BookCategory`, and this class will simply have variables named `BookId` and `CategoryId`.
+
+* To manage this **join entity**, we can add it as a sub-collection to the **Book** entity, as we do above. We add this sub-collection
+to **Book** class instead of **Category** class, because a book can have tens (or mostly hundreds) of categories but on the other perspective a category can have more than a hundred (or even way much) books inside of it.
+
+* It is a significant performance problem to load thousands of items whenever you query a category. Therefore it makes much more sense to add that sub-collection to the `Book` entity.
+
+> Don't forget: **Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit.** (See the full [description](https://martinfowler.com/bliki/DDD_Aggregate.html))
+
+* Notice that, `BookCategory` is not an **Aggregate Root** so we are not violating one of the base rules about Aggregate Root (Rule: **"Reference Other Aggregates Only by ID"**).
+
+* If we examine the methods in the `Book` class (such as **RemoveAllCategories**, **RemoveAllCategoriesExceptGivenIds** and **AddCategory**) we will manage our sub-collection `Categories` (**BookCategory** - join table/entity) through them. (Adds or removes categories for books)
+
+> We'll create the `BookCategory` and `BookConsts` classes later in this step.
+
+* **BookCategory.cs**
+
+```csharp
+using System;
+using Volo.Abp.Domain.Entities;
+
+namespace BookStore.Books
+{
+ public class BookCategory : Entity
+ {
+ public Guid BookId { get; protected set; }
+
+ public Guid CategoryId { get; protected set; }
+
+ /* This constructor is for deserialization / ORM purpose */
+ private BookCategory()
+ {
+ }
+
+ public BookCategory(Guid bookId, Guid categoryId)
+ {
+ BookId = bookId;
+ CategoryId = categoryId;
+ }
+
+ public override object[] GetKeys()
+ {
+ return new object[] {BookId, CategoryId};
+ }
+ }
+}
+```
+
+* Here, as you can notice, we've defined the `BookCategory` as the **Join Table/Entity** for our many-to-many relationship and ensured the required properties (BookId and CategoryId) were set in the constructor method of this class to create this object.
+
+* And also we've derived this class from the `Entity` class and therefore we've had to override the **GetKeys** method of this class to define the **Composite Key**.
+
+> The composite key is composed of `BookId` and `CategoryId` in our case. And they are unique together.
+
+> For more information about **Entities with Composite Keys**, you can read the relevant section from [Entities documentation](https://docs.abp.io/en/abp/latest/Entities#entities-with-composite-keys).
+
+* **BookManager.cs**
+
+```csharp
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using BookStore.Categories;
+using JetBrains.Annotations;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.Domain.Services;
+
+namespace BookStore.Books
+{
+ public class BookManager : DomainService
+ {
+ private readonly IBookRepository _bookRepository;
+ private readonly IRepository _categoryRepository;
+
+ public BookManager(IBookRepository bookRepository, IRepository categoryRepository)
+ {
+ _bookRepository = bookRepository;
+ _categoryRepository = categoryRepository;
+ }
+
+ public async Task CreateAsync(Guid authorId, string name, DateTime publishDate, float price, [CanBeNull]string[] categoryNames)
+ {
+ var book = new Book(GuidGenerator.Create(), authorId, name, publishDate, price);
+
+ await SetCategoriesAsync(book, categoryNames);
+
+ await _bookRepository.InsertAsync(book);
+ }
+
+ public async Task UpdateAsync(
+ Book book,
+ Guid authorId,
+ string name,
+ DateTime publishDate,
+ float price,
+ [CanBeNull] string[] categoryNames
+ )
+ {
+ book.AuthorId = authorId;
+ book.SetName(name);
+ book.PublishDate = publishDate;
+ book.Price = price;
+
+ await SetCategoriesAsync(book, categoryNames);
+
+ await _bookRepository.UpdateAsync(book);
+ }
+
+ private async Task SetCategoriesAsync(Book book, [CanBeNull] string[] categoryNames)
+ {
+ if (categoryNames == null || !categoryNames.Any())
+ {
+ book.RemoveAllCategories();
+ return;
+ }
+
+ var query = (await _categoryRepository.GetQueryableAsync())
+ .Where(x => categoryNames.Contains(x.Name))
+ .Select(x => x.Id)
+ .Distinct();
+
+ var categoryIds = await AsyncExecuter.ToListAsync(query);
+ if (!categoryIds.Any())
+ {
+ return;
+ }
+
+ book.RemoveAllCategoriesExceptGivenIds(categoryIds);
+
+ foreach (var categoryId in categoryIds)
+ {
+ book.AddCategory(categoryId);
+ }
+ }
+ }
+}
+```
+
+* If we examine the codes in the `BookManager` class, we can see that we've managed the `BookCategory` class (our join table/entity) by using some methods that we've defined in the `Book` class such as **RemoveAllCategories**, **RemoveAllCategoriesExceptGivenIds** and **AddCategory**.
+
+* These methods basically add or remove categories related to the book by conditions.
+
+* In the `CreateAsync` method, if the category names are specified, we'll retrieve their ids from the database and by using the **AddCategory** method that we've defined in the `Book` class, we'll add them.
+
+* In the `UpdateAsync` method, the same logic is also valid. But in this case, the user might want to remove some categories from books, so if the user sends us an empty **categoryNames** array, we remove all categories from the book he wants to update. If the user sends us some category names, we remove the excluded ones and add the new ones according to the **categoryNames** array.
+
+* **BookWithDetails.cs**
+
+```csharp
+using System;
+using Volo.Abp.Auditing;
+
+namespace BookStore.Books
+{
+ public class BookWithDetails : IHasCreationTime
+ {
+ public Guid Id { get; set; }
+
+ public string Name { get; set; }
+
+ public DateTime PublishDate { get; set; }
+
+ public float Price { get; set; }
+
+ public string AuthorName { get; set; }
+
+ public string[] CategoryNames { get; set; }
+
+ public DateTime CreationTime { get; set; }
+ }
+}
+```
+
+We will use this class to retrieve books with their sub-categories and author names.
+
+* **IBookRepository.cs**
+
+```csharp
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Domain.Repositories;
+
+namespace BookStore.Books
+{
+ public interface IBookRepository : IRepository
+ {
+ Task> GetListAsync(
+ string sorting,
+ int skipCount,
+ int maxResultCount,
+ CancellationToken cancellationToken = default
+ );
+
+ Task GetAsync(Guid id, CancellationToken cancellationToken = default);
+ }
+}
+```
+
+We need to create two methods named **GetListAsync** and **GetAsync** and specify their return type as `BookWithDetails`. So by implementing these methods, we will return the book/books by their details (author name and categories).
+
+* **Category.cs**
+
+```csharp
+using System;
+using Volo.Abp;
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace BookStore.Categories
+{
+ public class Category : AuditedAggregateRoot
+ {
+ public string Name { get; private set; }
+
+ /* This constructor is for deserialization / ORM purpose */
+ private Category()
+ {
+ }
+
+ public Category(Guid id, string name) : base(id)
+ {
+ SetName(name);
+ }
+
+ public Category SetName(string name)
+ {
+ Name = Check.NotNullOrWhiteSpace(name, nameof(name), CategoryConsts.MaxNameLength);
+ return this;
+ }
+ }
+}
+```
+
+After defining our entities we can seed initial data to our database by using the [Data Seeding](https://docs.abp.io/en/abp/5.0/Data-Seeding#data-seeding) system of the ABP framework. We will create initial data for both the `Category` and `Author` entities because we will not create CRUD pages for these entities.
+
+> We will create only CRUD pages for the Book entity therefore we don't need to add initial data for the Book entity. We can create a new book by using the create modal of the Book page. (We will create it in the sixth step.)
+
+Create a class named `BookStoreDataSeederContributor` in your `*.Domain` project and update with the following code:
+
+* **BookStoreDataSeederContributor.cs**
+
+```csharp
+using System;
+using System.Threading.Tasks;
+using BookStore.Authors;
+using BookStore.Categories;
+using Volo.Abp.Data;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Domain.Repositories;
+using Volo.Abp.Guids;
+
+namespace BookStore
+{
+ public class BookStoreDataSeederContributor : IDataSeedContributor, ITransientDependency
+ {
+ private readonly IGuidGenerator _guidGenerator;
+ private readonly IRepository _categoryRepository;
+ private readonly IRepository _authorRepository;
+
+ public BookStoreDataSeederContributor(
+ IGuidGenerator guidGenerator,
+ IRepository categoryRepository,
+ IRepository authorRepository
+ )
+ {
+ _guidGenerator = guidGenerator;
+ _categoryRepository = categoryRepository;
+ _authorRepository = authorRepository;
+ }
+
+ public async Task SeedAsync(DataSeedContext context)
+ {
+ await SeedCategoriesAsync();
+ await SeedAuthorsAsync();
+ }
+
+ private async Task SeedCategoriesAsync()
+ {
+ if (await _categoryRepository.GetCountAsync() <= 0)
+ {
+ await _categoryRepository.InsertAsync(
+ new Category(_guidGenerator.Create(), "History")
+ );
+
+ await _categoryRepository.InsertAsync(
+ new Category(_guidGenerator.Create(), "Unknown")
+ );
+
+ await _categoryRepository.InsertAsync(
+ new Category(_guidGenerator.Create(), "Adventure")
+ );
+
+ await _categoryRepository.InsertAsync(
+ new Category(_guidGenerator.Create(), "Action")
+ );
+
+ await _categoryRepository.InsertAsync(
+ new Category(_guidGenerator.Create(), "Crime")
+ );
+
+ await _categoryRepository.InsertAsync(
+ new Category(_guidGenerator.Create(), "Dystopia")
+ );
+ }
+ }
+
+ private async Task SeedAuthorsAsync()
+ {
+ if (await _authorRepository.GetCountAsync() <= 0)
+ {
+ await _authorRepository.InsertAsync(
+ new Author(
+ _guidGenerator.Create(),
+ "George Orwell",
+ new DateTime(1903, 06, 25),
+ "Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)."
+ )
+ );
+
+ await _authorRepository.InsertAsync(
+ new Author(
+ _guidGenerator.Create(),
+ "Dan Brown",
+ new DateTime(1964, 06, 22),
+ "Daniel Gerhard Brown (born June 22, 1964) is an American author best known for his thriller novels"
+ )
+ );
+ }
+ }
+ }
+}
+```
+
+### Step 2 - (Define Consts)
+
+We can create a folder-structure under the `BookStore.Domain.Shared` project like in the image below.
+
+
+
+* **AuthorConsts.cs**
+
+```csharp
+namespace BookStore.Authors
+{
+ public class AuthorConsts
+ {
+ public const int MaxNameLength = 128;
+
+ public const int MaxShortBioLength = 256;
+ }
+}
+```
+
+* **BookConsts.cs**
+
+```csharp
+namespace BookStore.Books
+{
+ public class BookConsts
+ {
+ public const int MaxNameLength = 128;
+ }
+}
+```
+
+* **CategoryConsts.cs**
+
+```csharp
+namespace BookStore.Categories
+{
+ public class CategoryConsts
+ {
+ public const int MaxNameLength = 64;
+ }
+}
+```
+
+In these classes, we've defined max text length for our entity properties that we will use in the **Database Integration** section to specify limits for our properties. (E.g. varchar(128) for BookName)
+
+### Step 3 - (Database Integration)
+
+After defining our entities, we can configure them for the database integration.
+Open the `BookStoreDbContext` class in the `BookStore.EntityFrameworkCore` project and update the following code blocks.
+
+```csharp
+namespace BookStore.EntityFrameworkCore
+{
+ [ReplaceDbContext(typeof(IIdentityDbContext))]
+ [ReplaceDbContext(typeof(ITenantManagementDbContext))]
+ [ConnectionStringName("Default")]
+ public class BookStoreDbContext :
+ AbpDbContext,
+ IIdentityDbContext,
+ ITenantManagementDbContext
+ {
+ //...
+
+ //DbSet properties for our Aggregate Roots
+ public DbSet Authors { get; set; }
+ public DbSet Books { get; set; }
+ public DbSet Categories { get; set; }
+
+ //NOTE: We don't need to add DbSet, because we will be query it via using the Book entity
+ // public DbSet BookCategories { get; set; }
+
+ //...
+
+ protected override void OnModelCreating(ModelBuilder builder)
+ {
+ //...
+
+ /* Configure your own tables/entities inside here */
+ builder.Entity(b =>
+ {
+ b.ToTable(BookStoreConsts.DbTablePrefix + "Authors" + BookStoreConsts.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.Name)
+ .HasMaxLength(AuthorConsts.MaxNameLength)
+ .IsRequired();
+
+ b.Property(x => x.ShortBio)
+ .HasMaxLength(AuthorConsts.MaxShortBioLength)
+ .IsRequired();
+ });
+
+ builder.Entity(b =>
+ {
+ b.ToTable(BookStoreConsts.DbTablePrefix + "Books" + BookStoreConsts.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.Name)
+ .HasMaxLength(BookConsts.MaxNameLength)
+ .IsRequired();
+
+ //one-to-many relationship with Author table
+ b.HasOne().WithMany().HasForeignKey(x => x.AuthorId).IsRequired();
+
+ //many-to-many relationship with Category table => BookCategories
+ b.HasMany(x => x.Categories).WithOne().HasForeignKey(x => x.BookId).IsRequired();
+ });
+
+ builder.Entity(b =>
+ {
+ b.ToTable(BookStoreConsts.DbTablePrefix + "Categories" + BookStoreConsts.DbSchema);
+ b.ConfigureByConvention();
+
+ b.Property(x => x.Name)
+ .HasMaxLength(CategoryConsts.MaxNameLength)
+ .IsRequired();
+ });
+
+ builder.Entity(b =>
+ {
+ b.ToTable(BookStoreConsts.DbTablePrefix + "BookCategories" + BookStoreConsts.DbSchema);
+ b.ConfigureByConvention();
+
+ //define composite key
+ b.HasKey(x => new { x.BookId, x.CategoryId });
+
+ //many-to-many configuration
+ b.HasOne().WithMany(x => x.Categories).HasForeignKey(x => x.BookId).IsRequired();
+ b.HasOne().WithMany().HasForeignKey(x => x.CategoryId).IsRequired();
+
+ b.HasIndex(x => new { x.BookId, x.CategoryId });
+ });
+ }
+ }
+}
+```
+
+* In this class, we've defined the **DbSet** properties for our **Aggregate Roots** (**Book**, **Author** and **Category**). Notice, we didn't define the **DbSet** for the `BookCategory` class (our join table/entity). Because, the `Book` aggregate is responsible for managing it via sub-collection.
+
+* After that, we can use the **FluentAPI** to configure our tables in the `OnModelCreating` method of this class.
+
+```csharp
+builder.Entity(b =>
+{
+ //...
+
+ //one-to-many relationship with Author table
+ b.HasOne().WithMany().HasForeignKey(x => x.AuthorId).IsRequired();
+
+ //many-to-many relationship with Category table => BookCategories
+ b.HasMany(x => x.Categories).WithOne().HasForeignKey(x => x.BookId).IsRequired();
+});
+```
+
+Here, we have provided the one-to-many relationship between the **Book** and the **Author** in the above code-block.
+
+```csharp
+builder.Entity(b =>
+{
+ //...
+
+ //define composite key
+ b.HasKey(x => new { x.BookId, x.CategoryId });
+
+ //many-to-many configuration
+ b.HasOne().WithMany(x => x.Categories).HasForeignKey(x => x.BookId).IsRequired();
+ b.HasOne().WithMany().HasForeignKey(x => x.CategoryId).IsRequired();
+
+ b.HasIndex(x => new { x.BookId, x.CategoryId });
+});
+```
+
+Here, firstly we've defined the composite key for our `BookCategory` entity. `BookId` and `CategoryId` are together as composite keys for the `BookCategory` table. Then we've configured the many-to-many relationship between the `Book` and the `Category` tables like in the above code-block.
+
+#### Implementing the `IBookRepository` Interface
+
+After making the relevant configurations for the database integration, we can now implement the `IBookRepository` interface. To do this, create a folder named `Books` in the `BookStore.EntityFrameworkCore` project and inside of this folder, create a class named `EfCoreBookRepository` and update this class with the following code:
+
+```csharp
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading;
+using System.Threading.Tasks;
+using BookStore.Authors;
+using BookStore.Categories;
+using BookStore.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+
+namespace BookStore.Books
+{
+ public class EfCoreBookRepository : EfCoreRepository, IBookRepository
+ {
+ public EfCoreBookRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider)
+ {
+ }
+
+ public async Task> GetListAsync(
+ string sorting,
+ int skipCount,
+ int maxResultCount,
+ CancellationToken cancellationToken = default
+ )
+ {
+ var query = await ApplyFilterAsync();
+
+ return await query
+ .OrderBy(!string.IsNullOrWhiteSpace(sorting) ? sorting : nameof(Book.Name))
+ .PageBy(skipCount, maxResultCount)
+ .ToListAsync(GetCancellationToken(cancellationToken));
+ }
+
+ public async Task GetAsync(Guid id, CancellationToken cancellationToken = default)
+ {
+ var query = await ApplyFilterAsync();
+
+ return await query
+ .Where(x => x.Id == id)
+ .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
+ }
+
+ private async Task> ApplyFilterAsync()
+ {
+ var dbContext = await GetDbContextAsync();
+
+ return (await GetDbSetAsync())
+ .Include(x => x.Categories)
+ .Join(dbContext.Set(), book => book.AuthorId, author => author.Id,
+ (book, author) => new {book, author})
+ .Select(x => new BookWithDetails
+ {
+ Id = x.book.Id,
+ Name = x.book.Name,
+ Price = x.book.Price,
+ PublishDate = x.book.PublishDate,
+ CreationTime = x.book.CreationTime,
+ AuthorName = x.author.Name,
+ CategoryNames = (from bookCategories in x.book.Categories
+ join category in dbContext.Set() on bookCategories.CategoryId equals category.Id
+ select category.Name).ToArray()
+ });
+ }
+
+ public override Task> WithDetailsAsync()
+ {
+ return base.WithDetailsAsync(x => x.Categories);
+ }
+ }
+}
+```
+
+* Here, we've implemented our custom repository methods and returned the book with details (author name and categories).
+
+### Step 4 - (Database Migration)
+
+* We've integrated our entities with the database in the previous step, now we can create a new database migration and apply it to the database. So let's do that.
+
+* Open the `BookStore.EntityFrameworkCore` project in the terminal. And create a new database migration by using the following command:
+
+```bash
+dotnet ef migrations add
+```
+
+* Then, run the `BookStore.DbMigrator` application to create the database.
+
+### Step 5 - (Create Application Services)
+
+* Let's start with defining our DTOs and application service interfaces in the `BookStore.Application.Contracts` layer. We can create a folder-structure like in the image below:
+
+
+
+* We can use the [`CrudAppService`](https://docs.abp.io/en/abp/latest/Application-Services#crud-application-services) base class of the ABP Framework to create application services to **Get**, **Create**, **Update** and **Delete** authors and categories.
+
+* **AuthorDto.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace BookStore.Authors
+{
+ public class AuthorDto : EntityDto
+ {
+ public string Name { get; set; }
+
+ public DateTime BirthDate { get; set; }
+
+ public string ShortBio { get; set; }
+ }
+}
+```
+
+* **AuthorLookupDto.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace BookStore.Authors
+{
+ public class AuthorLookupDto : EntityDto
+ {
+ public string Name { get; set; }
+ }
+}
+```
+
+We will use this DTO class as output DTO to get all the authors and list them in a select box in the book creation model. (Like in the image below.)
+
+
+
+* **CreateUpdateAuthorDto.cs**
+
+```csharp
+using System;
+
+namespace BookStore.Authors
+{
+ public class CreateUpdateAuthorDto
+ {
+ public string Name { get; set; }
+
+ public DateTime BirthDate { get; set; }
+
+ public string ShortBio { get; set; }
+ }
+}
+```
+
+* **IAuthorAppService.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace BookStore.Authors
+{
+ public interface IAuthorAppService :
+ ICrudAppService
+ {
+ }
+}
+```
+
+* **BookDto.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace BookStore.Books
+{
+ public class BookDto : EntityDto
+ {
+ public string AuthorName { get; set; }
+
+ public string Name { get; set; }
+
+ public DateTime PublishDate { get; set; }
+
+ public float Price { get; set; }
+
+ public string[] CategoryNames { get; set; }
+ }
+}
+```
+
+When listing the Book/Books we will retrieve them with all their details (author name and category names).
+
+* **BookGetListInput.cs**
+
+```csharp
+using Volo.Abp.Application.Dtos;
+
+namespace BookStore.Books
+{
+ public class BookGetListInput : PagedAndSortedResultRequestDto
+ {
+ }
+}
+```
+
+* **CreateUpdateBookDto.cs**
+
+```csharp
+using System;
+
+namespace BookStore.Books
+{
+ public class CreateUpdateBookDto
+ {
+ public Guid AuthorId { get; set; }
+
+ public string Name { get; set; }
+
+ public DateTime PublishDate { get; set; }
+
+ public float Price { get; set; }
+
+ public string[] CategoryNames { get; set; }
+ }
+}
+```
+
+To create or update a book we will use this input DTO.
+
+* **IBookAppService.cs**
+
+```csharp
+using System;
+using System.Threading.Tasks;
+using BookStore.Authors;
+using BookStore.Categories;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace BookStore.Books
+{
+ public interface IBookAppService : IApplicationService
+ {
+ Task> GetListAsync(BookGetListInput input);
+
+ Task GetAsync(Guid id);
+
+ Task CreateAsync(CreateUpdateBookDto input);
+
+ Task UpdateAsync(Guid id, CreateUpdateBookDto input);
+
+ Task DeleteAsync(Guid id);
+
+ Task> GetAuthorLookupAsync();
+
+ Task> GetCategoryLookupAsync();
+ }
+}
+```
+
+* We will create custom application service method for managing Books instead of using the `CrudAppService`'s methods.
+
+* Also we will create two additional methods and they are `GetAuthorLookupAsync` and `GetCategoryLookupAsync`. We will use these two methods to retrieve all the authors and categories without pagination and list them as a select box item in create/update modals for the Book page.
+(You can see the usage of these two methods in the gif below.)
+
+
+
+* **CategoryDto.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace BookStore.Categories
+{
+ public class CategoryDto : EntityDto
+ {
+ public string Name { get; set; }
+ }
+}
+```
+
+* **CategoryLookupDto.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+
+namespace BookStore.Categories
+{
+ public class CategoryLookupDto : EntityDto
+ {
+ public string Name { get; set; }
+ }
+}
+```
+
+We will use this DTO class as an output DTO to get all categories without pagination and list them in a select box in the book create/update modals.
+
+* **CreateUpdateCategoryDto.cs**
+
+```csharp
+namespace BookStore.Categories
+{
+ public class CreateUpdateCategoryDto
+ {
+ public string Name { get; set; }
+ }
+}
+```
+
+* **ICategoryAppService.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+
+namespace BookStore.Categories
+{
+ public interface ICategoryAppService :
+ ICrudAppService
+ {
+ }
+}
+```
+
+After creating the DTOs and application service interfaces, now we can define the implementation of those interfaces. So, we can create a folder-structure like in the image below for the `BookStore.Application` layer. Open the application service classes and add the following codes to each of these classes.
+
+
+
+* **AuthorAppService.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace BookStore.Authors
+{
+ public class AuthorAppService :
+ CrudAppService,
+ IAuthorAppService
+ {
+ public AuthorAppService(IRepository repository) : base(repository)
+ {
+ }
+ }
+}
+```
+
+* **CategoryAppService.cs**
+
+```csharp
+using System;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Domain.Repositories;
+
+namespace BookStore.Categories
+{
+ public class CategoryAppService :
+ CrudAppService,
+ ICategoryAppService
+ {
+ public CategoryAppService(IRepository repository) : base(repository)
+ {
+ }
+ }
+}
+```
+
+Thanks to the `CrudAppService`, we don't need to manually implement the crud methods for **AuthorAppService** and **CategoryAppService**.
+
+* **BookAppService.cs**
+
+```csharp
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using BookStore.Authors;
+using BookStore.Categories;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Domain.Repositories;
+
+namespace BookStore.Books
+{
+ public class BookAppService : BookStoreAppService, IBookAppService
+ {
+ private readonly IBookRepository _bookRepository;
+ private readonly BookManager _bookManager;
+ private readonly IRepository _authorRepository;
+ private readonly IRepository _categoryRepository;
+
+ public BookAppService(
+ IBookRepository bookRepository,
+ BookManager bookManager,
+ IRepository authorRepository,
+ IRepository categoryRepository
+ )
+ {
+ _bookRepository = bookRepository;
+ _bookManager = bookManager;
+ _authorRepository = authorRepository;
+ _categoryRepository = categoryRepository;
+ }
+
+ public async Task> GetListAsync(BookGetListInput input)
+ {
+ var books = await _bookRepository.GetListAsync(input.Sorting, input.SkipCount, input.MaxResultCount);
+ var totalCount = await _bookRepository.CountAsync();
+
+ return new PagedResultDto(totalCount, ObjectMapper.Map, List>(books));
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var book = await _bookRepository.GetAsync(id);
+
+ return ObjectMapper.Map(book);
+ }
+
+ public async Task CreateAsync(CreateUpdateBookDto input)
+ {
+ await _bookManager.CreateAsync(
+ input.AuthorId,
+ input.Name,
+ input.PublishDate,
+ input.Price,
+ input.CategoryNames
+ );
+ }
+
+ public async Task UpdateAsync(Guid id, CreateUpdateBookDto input)
+ {
+ var book = await _bookRepository.GetAsync(id, includeDetails: true); //return type is: Book (not BookWithDetails) Because, we don't need author name
+
+ await _bookManager.UpdateAsync(
+ book,
+ input.AuthorId,
+ input.Name,
+ input.PublishDate,
+ input.Price,
+ input.CategoryNames
+ );
+ }
+
+ public async Task DeleteAsync(Guid id)
+ {
+ await _bookRepository.DeleteAsync(id);
+ }
+
+ public async Task> GetAuthorLookupAsync()
+ {
+ var authors = await _authorRepository.GetListAsync();
+
+ return new ListResultDto(
+ ObjectMapper.Map, List>(authors)
+ );
+ }
+
+ public async Task> GetCategoryLookupAsync()
+ {
+ var categories = await _categoryRepository.GetListAsync();
+
+ return new ListResultDto(
+ ObjectMapper.Map, List>(categories)
+ );
+ }
+ }
+}
+```
+
+* As you can notice here, we've used our **Domain Service** class named `BookManager` in the **CreateAsync** and **UpdateAsync** methods. (Defined them in step 1)
+
+* As you may remember, in these methods, new categories are added to the book or removed from the sub-collection (**Categories** (`BookCategory`)) according to the relevant category names.
+
+* After implementing the application services, we need to define the mappings for our services to work. So open the `BookStoreApplicationAutoMapperProfile` class and update it with the following code:
+
+```csharp
+using AutoMapper;
+using BookStore.Authors;
+using BookStore.Books;
+using BookStore.Categories;
+
+namespace BookStore
+{
+ public class BookStoreApplicationAutoMapperProfile : Profile
+ {
+ public BookStoreApplicationAutoMapperProfile()
+ {
+ CreateMap();
+ CreateMap();
+ CreateMap();
+
+ CreateMap();
+ CreateMap();
+ CreateMap();
+
+ CreateMap();
+ }
+ }
+}
+
+```
+
+### Step 6 - (UI)
+
+The only thing we need to do is, by using the application service methods that we've defined in the previous step to create the UI.
+
+
+
+> To keep the article shorter, I'll just show you how to create the Book page (with Create/Edit modals). If you want to implement it to other pages, you can access the source code of the application at https://github.com/EngincanV/ABP-Many-to-Many-Relationship-Demo and copy-paste the relevant code-blocks to your application.
+
+#### Book Page
+
+* Create a razor page named **Index.cshtml** under the **Pages/Books** folder of the `BookStore.Web` project and paste the following code to that page.
+
+* **Index.cshtml**
+
+```html
+@page
+@model BookStore.Web.Pages.Books.Index
+
+@section scripts
+{
+
+}
+
+
+
+
+
+ Books
+
+
+
+
+
+
+
+
+
+
+```
+
+In here we've added a **New Book** button and a table with an id named "BooksTable". We'll create an `Index.js` file and by using [datatable.js](https://datatables.net) we will fill the table with our records.
+
+* **Index.js**
+
+```js
+$(function () {
+ var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');
+ var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');
+
+ var bookService = bookStore.books.book;
+
+ var dataTable = $('#BooksTable').DataTable(
+ abp.libs.datatables.normalizeConfiguration({
+ serverSide: true,
+ paging: true,
+ order: [[1, "asc"]],
+ searching: false,
+ scrollX: true,
+ ajax: abp.libs.datatables.createAjax(bookService.getList),
+ columnDefs: [
+ {
+ title: 'Actions',
+ rowAction: {
+ items:
+ [
+ {
+ text: 'Edit',
+ action: function (data) {
+ editModal.open({ id: data.record.id });
+ }
+ },
+ {
+ text: 'Delete',
+ confirmMessage: function (data) {
+ return "Are you sure to delete the book '" + data.record.name +"'?";
+ },
+ action: function (data) {
+ bookService
+ .delete(data.record.id)
+ .then(function() {
+ abp.notify.info("Successfully deleted!");
+ dataTable.ajax.reload();
+ });
+ }
+ }
+ ]
+ }
+ },
+ {
+ title: 'Name',
+ data: "name"
+ },
+ {
+ title: 'Publish Date',
+ data: "publishDate",
+ render: function (data) {
+ return luxon
+ .DateTime
+ .fromISO(data, {
+ locale: abp.localization.currentCulture.name
+ }).toLocaleString();
+ }
+ },
+ {
+ title: 'Author Name',
+ data: "authorName"
+ },
+ {
+ title: 'Price',
+ data: "price"
+ },
+ {
+ title: 'Categories',
+ data: "categoryNames",
+ render: function (data) {
+ return data.join(", ");
+ }
+ }
+ ]
+ })
+ );
+
+ createModal.onResult(function () {
+ dataTable.ajax.reload();
+ });
+
+ editModal.onResult(function () {
+ dataTable.ajax.reload();
+ });
+
+ $('#NewBookButton').click(function (e) {
+ e.preventDefault();
+ createModal.open();
+ });
+});
+
+```
+
+> `abp.libs.datatables.normalizeConfiguration` is a helper function defined by the ABP Framework. It simplifies the Datatables configuration by providing conventional default values for missing options.
+
+* Let's examine what we've done in the `Index.js` file.
+
+* Firstly, we've defined our `createModal` and `editModal` modals by using the [ABP Modals](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Modals). Then, we've created the DataTable and fetched our books by using the dynamic JavaScript proxy function (`bookStore.books.book.getList`) (It sends a request to the **GetListAsync** method that we've defined in the `BookAppService` under the hook) and we've shown them in the table with an id named "BooksTable".
+
+* Now let's run the application and navigate to the **/Books** route to see how our Book page looks.
+
+
+
+We need to see a page similar to the image above. Our app is working properly, we can continue developing.
+
+> If you are stuck in any point, you can examine the [source codes](https://github.com/EngincanV/ABP-Many-to-Many-Relationship-Demo).
+
+#### Model Classes and Mapping Configurations
+
+Create a folder named **Models** and add a class named `CategoryViewModel` inside of it. We will use this view modal class to determine which categories are selected or not in our Create/Edit modals.
+
+* **CategoryViewModel.cs**
+
+```csharp
+using System;
+using System.ComponentModel.DataAnnotations;
+using Microsoft.AspNetCore.Mvc;
+
+namespace BookStore.Web.Models
+{
+ public class CategoryViewModel
+ {
+ [HiddenInput]
+ public Guid Id { get; set; }
+
+ public bool IsSelected { get; set; }
+
+ [Required]
+ [HiddenInput]
+ public string Name { get; set; }
+ }
+}
+```
+
+Then, we can open the `BookStoreWebAutoMapperProfile` class and define the required mappings as follows:
+
+```csharp
+using AutoMapper;
+using BookStore.Authors;
+using BookStore.Books;
+using BookStore.Categories;
+using BookStore.Web.Models;
+using BookStore.Web.Pages.Books;
+using Volo.Abp.AutoMapper;
+
+namespace BookStore.Web
+{
+ public class BookStoreWebAutoMapperProfile : Profile
+ {
+ public BookStoreWebAutoMapperProfile()
+ {
+ CreateMap()
+ .Ignore(x => x.IsSelected);
+
+ CreateMap();
+
+ CreateMap();
+
+ CreateMap();
+ }
+ }
+}
+```
+
+#### Create/Edit Modals
+
+After creating our index page for Books and configuring mappings, let's continue with creating the Create/Edit modals for Books.
+
+Create a razor page named **CreateModal.cshtml** (and **CreateModal.cshtml.cs**).
+
+* **CreateModal.cshtml**
+
+```html
+@page
+@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
+@model BookStore.Web.Pages.Books.CreateModal
+
+@{
+ Layout = null;
+}
+
+
+```
+
+* **CreateModal.cshtml.cs**
+
+```csharp
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using BookStore.Books;
+using BookStore.Categories;
+using BookStore.Web.Models;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+
+namespace BookStore.Web.Pages.Books
+{
+ public class CreateModal : BookStorePageModel
+ {
+ [BindProperty]
+ public CreateUpdateBookDto Book { get; set; }
+
+ [BindProperty]
+ public List Categories { get; set; }
+
+ public List AuthorList { get; set; }
+
+ private readonly IBookAppService _bookAppService;
+
+ public CreateModal(IBookAppService bookAppService)
+ {
+ _bookAppService = bookAppService;
+ }
+
+ public async Task OnGetAsync()
+ {
+ Book = new CreateUpdateBookDto();
+
+ //Get all authors and fill the select list
+ var authorLookup = await _bookAppService.GetAuthorLookupAsync();
+ AuthorList = authorLookup.Items
+ .Select(x => new SelectListItem(x.Name, x.Id.ToString()))
+ .ToList();
+
+ //Get all categories
+ var categoryLookupDto = await _bookAppService.GetCategoryLookupAsync();
+ Categories = ObjectMapper.Map, List>(categoryLookupDto.Items.ToList());
+ }
+
+ public async Task OnPostAsync()
+ {
+ ValidateModel();
+
+ var selectedCategories = Categories.Where(x => x.IsSelected).ToList();
+ if (selectedCategories.Any())
+ {
+ var categoryNames = selectedCategories.Select(x => x.Name).ToArray();
+ Book.CategoryNames = categoryNames;
+ }
+
+ await _bookAppService.CreateAsync(Book);
+ return NoContent();
+ }
+ }
+}
+```
+
+Here, we've got all categories and authors inside of the `OnGetAsync` method. And use them inside of the create modal to list them so the user can choose when creating a new book.
+
+
+
+* When the user submits the form, the `OnPostAsync` method runs. Inside of this method, we get the selected categories and pass them into the **CategoryNames** array of the Book object and call the `IBookAppService.CreateAsync` method to create a new book.
+
+Create a razor page named **EditModal.cshtml** (and **EditModal.cshtml.cs**).
+
+* **EditModal.cshtml**
+
+```html
+@page
+@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
+@model BookStore.Web.Pages.Books.EditModal
+
+@{
+ Layout = null;
+}
+
+
+```
+
+* **EditModal.cshtml.cs**
+
+```csharp
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using BookStore.Books;
+using BookStore.Categories;
+using BookStore.Web.Models;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+
+namespace BookStore.Web.Pages.Books
+{
+ public class EditModal : BookStorePageModel
+ {
+ [HiddenInput]
+ [BindProperty(SupportsGet = true)]
+ public Guid Id { get; set; }
+
+ [BindProperty]
+ public CreateUpdateBookDto EditingBook { get; set; }
+
+ [BindProperty]
+ public List Categories { get; set; }
+
+ public List AuthorList { get; set; }
+
+ private readonly IBookAppService _bookAppService;
+
+ public EditModal(IBookAppService bookAppService)
+ {
+ _bookAppService = bookAppService;
+ }
+
+ public async Task OnGetAsync()
+ {
+ var bookDto = await _bookAppService.GetAsync(Id);
+ EditingBook = ObjectMapper.Map(bookDto);
+
+ //get all authors
+ var authorLookup = await _bookAppService.GetAuthorLookupAsync();
+ AuthorList = authorLookup.Items
+ .Select(x => new SelectListItem(x.Name, x.Id.ToString()))
+ .ToList();
+
+ //get all categories
+ var categoryLookupDto = await _bookAppService.GetCategoryLookupAsync();
+ Categories = ObjectMapper.Map, List>(categoryLookupDto.Items.ToList());
+
+ //mark as Selected for Categories in the book
+ if (EditingBook.CategoryNames != null && EditingBook.CategoryNames.Any())
+ {
+ Categories
+ .Where(x => EditingBook.CategoryNames.Contains(x.Name))
+ .ToList()
+ .ForEach(x => x.IsSelected = true);
+ }
+ }
+
+ public async Task OnPostAsync()
+ {
+ ValidateModel();
+
+ var selectedCategories = Categories.Where(x => x.IsSelected).ToList();
+ if (selectedCategories.Any())
+ {
+ var categoryNames = selectedCategories.Select(x => x.Name).ToArray();
+ EditingBook.CategoryNames = categoryNames;
+ }
+
+ await _bookAppService.UpdateAsync(Id, EditingBook);
+ return NoContent();
+ }
+ }
+}
+```
+
+* As in the `CreateModal.cshtml.cs`, we've got all categories and authors inside of the `OnGetAsync` method. And also we get the book by id and mark the selected categories properties' as `IsSelected = true`.
+
+* When the user updates the inputs and submits the form, the `OnPostAsync` method runs. Inside of this method, we get the selected categories and pass them into the **CategoryNames** array of the Book object and call the `IBookAppService.UpdateAsync` method to update the book.
+
+
+
+### Conclusion
+
+In this article, I've tried to explain how to create a many-to-many relationship by using the ABP framework. (by following DDD principles)
+
+Thanks for reading this article, I hope it was helpful.
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-contracts-folder-structure.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-contracts-folder-structure.png
new file mode 100644
index 0000000000..c0ed574489
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-contracts-folder-structure.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-final-demo.gif b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-final-demo.gif
new file mode 100644
index 0000000000..61289a8ffb
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-final-demo.gif differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-folder-structure.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-folder-structure.png
new file mode 100644
index 0000000000..0d37a552d4
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-folder-structure.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-create.gif b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-create.gif
new file mode 100644
index 0000000000..0e534802f2
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-create.gif differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-creation-modal.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-creation-modal.png
new file mode 100644
index 0000000000..8661e016cd
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-creation-modal.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-update-modal.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-update-modal.png
new file mode 100644
index 0000000000..d9d312399a
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-update-modal.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/demo.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/demo.png
new file mode 100644
index 0000000000..9b954bd7d6
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/demo.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-file-structure.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-file-structure.png
new file mode 100644
index 0000000000..6a5405dafe
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-file-structure.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-shared-file-structure.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-shared-file-structure.png
new file mode 100644
index 0000000000..22a8de6599
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-shared-file-structure.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/er-diagram.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/er-diagram.png
new file mode 100644
index 0000000000..5948366e0e
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/er-diagram.png differ
diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/web-folder-structure.png b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/web-folder-structure.png
new file mode 100644
index 0000000000..ed4a63a06c
Binary files /dev/null and b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/web-folder-structure.png differ
diff --git a/docs/en/Customizing-Application-Modules-Extending-Entities.md b/docs/en/Customizing-Application-Modules-Extending-Entities.md
index c2bcd314d4..e1cb02e849 100644
--- a/docs/en/Customizing-Application-Modules-Extending-Entities.md
+++ b/docs/en/Customizing-Application-Modules-Extending-Entities.md
@@ -63,8 +63,6 @@ You can then use the same extra properties system defined in the previous sectio
Another approach can be **creating your own entity** mapped to **the same database table** (or collection for a MongoDB database).
-`AppUser` entity in the [application startup template](Startup-Templates/Application.md) already implements this approach. [EF Core Migrations document](Entity-Framework-Core-Migrations.md) describes how to implement it and manage **EF Core database migrations** in such a case. It is also possible for MongoDB, while this time you won't deal with the database migration problems.
-
## Creating a New Entity with Its Own Database Table/Collection
Mapping your entity to an **existing table** of a depended module has a few disadvantages;
diff --git a/docs/en/Virtual-File-System.md b/docs/en/Virtual-File-System.md
index 4fa29f0738..4a13bf5740 100644
--- a/docs/en/Virtual-File-System.md
+++ b/docs/en/Virtual-File-System.md
@@ -119,7 +119,7 @@ The Virtual File System is well integrated to ASP.NET Core:
### Static Virtual File Folders
-By default, ASP.NET Core only allows the `wwwroot` folder to contain the static files consumed by the clients. When you use the birtual File System, the following folders also can contain static files:
+By default, ASP.NET Core only allows the `wwwroot` folder to contain the static files consumed by the clients. When you use the virtual File System, the following folders also can contain static files:
* Pages
* Views
diff --git a/docs/zh-Hans/Background-Workers.md b/docs/zh-Hans/Background-Workers.md
index a7563349ab..3f0e7fb369 100644
--- a/docs/zh-Hans/Background-Workers.md
+++ b/docs/zh-Hans/Background-Workers.md
@@ -2,7 +2,6 @@
## 介绍
-背景工人在应用简单独立的线程在后台运行.一般来说,他们定期运行,以执行一些任务.例子;
后台工作者在应用程序后台运行的简单的独立线程,一般来说它们定期运行执行一些任务.例如;
* 后台工作者可以定期**删除过时的日志**.
diff --git a/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/AbpApiVersioningAbstractionsModule.cs b/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/AbpApiVersioningAbstractionsModule.cs
index b4f679c927..70d960c8d5 100644
--- a/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/AbpApiVersioningAbstractionsModule.cs
+++ b/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/AbpApiVersioningAbstractionsModule.cs
@@ -1,13 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
-namespace Volo.Abp.ApiVersioning
+namespace Volo.Abp.ApiVersioning;
+
+public class AbpApiVersioningAbstractionsModule : AbpModule
{
- public class AbpApiVersioningAbstractionsModule : AbpModule
+ public override void ConfigureServices(ServiceConfigurationContext context)
{
- public override void ConfigureServices(ServiceConfigurationContext context)
- {
- context.Services.AddSingleton(NullRequestedApiVersion.Instance);
- }
+ context.Services.AddSingleton(NullRequestedApiVersion.Instance);
}
}
diff --git a/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/IRequestedApiVersion.cs b/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/IRequestedApiVersion.cs
index 3d8a31c694..96c2ef33cd 100644
--- a/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/IRequestedApiVersion.cs
+++ b/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/IRequestedApiVersion.cs
@@ -1,7 +1,6 @@
-namespace Volo.Abp.ApiVersioning
+namespace Volo.Abp.ApiVersioning;
+
+public interface IRequestedApiVersion
{
- public interface IRequestedApiVersion
- {
- string Current { get; }
- }
+ string Current { get; }
}
diff --git a/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/NullRequestedApiVersion.cs b/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/NullRequestedApiVersion.cs
index 721fa91815..0589c662ef 100644
--- a/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/NullRequestedApiVersion.cs
+++ b/framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/NullRequestedApiVersion.cs
@@ -1,14 +1,13 @@
-namespace Volo.Abp.ApiVersioning
+namespace Volo.Abp.ApiVersioning;
+
+public class NullRequestedApiVersion : IRequestedApiVersion
{
- public class NullRequestedApiVersion : IRequestedApiVersion
- {
- public static NullRequestedApiVersion Instance = new NullRequestedApiVersion();
+ public static NullRequestedApiVersion Instance = new NullRequestedApiVersion();
- public string Current => null;
+ public string Current => null;
+
+ private NullRequestedApiVersion()
+ {
- private NullRequestedApiVersion()
- {
-
- }
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
index 4ff54f39bf..8171013854 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
@@ -1,25 +1,24 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
-namespace Microsoft.AspNetCore.Builder
+namespace Microsoft.AspNetCore.Builder;
+
+public static class ApplicationBuilderAbpJwtTokenMiddlewareExtension
{
- public static class ApplicationBuilderAbpJwtTokenMiddlewareExtension
+ public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string schema = JwtBearerDefaults.AuthenticationScheme)
{
- public static IApplicationBuilder UseJwtTokenMiddleware(this IApplicationBuilder app, string schema = JwtBearerDefaults.AuthenticationScheme)
+ return app.Use(async (ctx, next) =>
{
- return app.Use(async (ctx, next) =>
+ if (ctx.User.Identity?.IsAuthenticated != true)
{
- if (ctx.User.Identity?.IsAuthenticated != true)
+ var result = await ctx.AuthenticateAsync(schema);
+ if (result.Succeeded && result.Principal != null)
{
- var result = await ctx.AuthenticateAsync(schema);
- if (result.Succeeded && result.Principal != null)
- {
- ctx.User = result.Principal;
- }
+ ctx.User = result.Principal;
}
+ }
- await next();
- });
- }
+ await next();
+ });
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs
index 8698e2283d..1fa5077a91 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs
@@ -1,11 +1,10 @@
using Volo.Abp.Modularity;
using Volo.Abp.Security;
-namespace Volo.Abp.AspNetCore.Authentication.JwtBearer
+namespace Volo.Abp.AspNetCore.Authentication.JwtBearer;
+
+[DependsOn(typeof(AbpSecurityModule))]
+public class AbpAspNetCoreAuthenticationJwtBearerModule : AbpModule
{
- [DependsOn(typeof(AbpSecurityModule))]
- public class AbpAspNetCoreAuthenticationJwtBearerModule : AbpModule
- {
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs
index 2ad72955af..01dc489c54 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs
@@ -1,57 +1,56 @@
using Volo.Abp.AspNetCore.Authentication.OAuth.Claims;
using Volo.Abp.Security.Claims;
-namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
+namespace Microsoft.AspNetCore.Authentication.OAuth.Claims;
+
+public static class AbpClaimActionCollectionExtensions
{
- public static class AbpClaimActionCollectionExtensions
+ public static void MapAbpClaimTypes(this ClaimActionCollection claimActions)
{
- public static void MapAbpClaimTypes(this ClaimActionCollection claimActions)
+ if (AbpClaimTypes.UserName != "name")
+ {
+ claimActions.MapJsonKey(AbpClaimTypes.UserName, "name");
+ claimActions.DeleteClaim("name");
+ claimActions.RemoveDuplicate(AbpClaimTypes.UserName);
+ }
+
+ if (AbpClaimTypes.Email != "email")
+ {
+ claimActions.MapJsonKey(AbpClaimTypes.Email, "email");
+ claimActions.DeleteClaim("email");
+ claimActions.RemoveDuplicate(AbpClaimTypes.Email);
+ }
+
+ if (AbpClaimTypes.EmailVerified != "email_verified")
+ {
+ claimActions.MapJsonKey(AbpClaimTypes.EmailVerified, "email_verified");
+ }
+
+ if (AbpClaimTypes.PhoneNumber != "phone_number")
{
- if (AbpClaimTypes.UserName != "name")
- {
- claimActions.MapJsonKey(AbpClaimTypes.UserName, "name");
- claimActions.DeleteClaim("name");
- claimActions.RemoveDuplicate(AbpClaimTypes.UserName);
- }
-
- if (AbpClaimTypes.Email != "email")
- {
- claimActions.MapJsonKey(AbpClaimTypes.Email, "email");
- claimActions.DeleteClaim("email");
- claimActions.RemoveDuplicate(AbpClaimTypes.Email);
- }
-
- if (AbpClaimTypes.EmailVerified != "email_verified")
- {
- claimActions.MapJsonKey(AbpClaimTypes.EmailVerified, "email_verified");
- }
-
- if (AbpClaimTypes.PhoneNumber != "phone_number")
- {
- claimActions.MapJsonKey(AbpClaimTypes.PhoneNumber, "phone_number");
- }
-
- if (AbpClaimTypes.PhoneNumberVerified != "phone_number_verified")
- {
- claimActions.MapJsonKey(AbpClaimTypes.PhoneNumberVerified, "phone_number_verified");
- }
-
- if (AbpClaimTypes.Role != "role")
- {
- claimActions.MapJsonKeyMultiple(AbpClaimTypes.Role, "role");
- }
-
- claimActions.RemoveDuplicate(AbpClaimTypes.Name);
+ claimActions.MapJsonKey(AbpClaimTypes.PhoneNumber, "phone_number");
}
- public static void MapJsonKeyMultiple(this ClaimActionCollection claimActions, string claimType, string jsonKey)
+ if (AbpClaimTypes.PhoneNumberVerified != "phone_number_verified")
{
- claimActions.Add(new MultipleClaimAction(claimType, jsonKey));
+ claimActions.MapJsonKey(AbpClaimTypes.PhoneNumberVerified, "phone_number_verified");
}
-
- public static void RemoveDuplicate(this ClaimActionCollection claimActions, string claimType)
+
+ if (AbpClaimTypes.Role != "role")
{
- claimActions.Add(new RemoveDuplicateClaimAction(claimType));
+ claimActions.MapJsonKeyMultiple(AbpClaimTypes.Role, "role");
}
+
+ claimActions.RemoveDuplicate(AbpClaimTypes.Name);
+ }
+
+ public static void MapJsonKeyMultiple(this ClaimActionCollection claimActions, string claimType, string jsonKey)
+ {
+ claimActions.Add(new MultipleClaimAction(claimType, jsonKey));
+ }
+
+ public static void RemoveDuplicate(this ClaimActionCollection claimActions, string claimType)
+ {
+ claimActions.Add(new RemoveDuplicateClaimAction(claimType));
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/AbpAspNetCoreAuthenticationOAuthModule.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/AbpAspNetCoreAuthenticationOAuthModule.cs
index cff3f437b7..b73c78782e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/AbpAspNetCoreAuthenticationOAuthModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/AbpAspNetCoreAuthenticationOAuthModule.cs
@@ -1,11 +1,10 @@
using Volo.Abp.Modularity;
using Volo.Abp.Security;
-namespace Volo.Abp.AspNetCore.Authentication.OAuth
+namespace Volo.Abp.AspNetCore.Authentication.OAuth;
+
+[DependsOn(typeof(AbpSecurityModule))]
+public class AbpAspNetCoreAuthenticationOAuthModule : AbpModule
{
- [DependsOn(typeof(AbpSecurityModule))]
- public class AbpAspNetCoreAuthenticationOAuthModule : AbpModule
- {
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs
index 66ca78026d..1910af63d5 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs
@@ -3,51 +3,50 @@ using System.Security.Claims;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
-namespace Volo.Abp.AspNetCore.Authentication.OAuth.Claims
+namespace Volo.Abp.AspNetCore.Authentication.OAuth.Claims;
+
+public class MultipleClaimAction : ClaimAction
{
- public class MultipleClaimAction : ClaimAction
+ public MultipleClaimAction(string claimType, string jsonKey)
+ : base(claimType, jsonKey)
{
- public MultipleClaimAction(string claimType, string jsonKey)
- : base(claimType, jsonKey)
- {
- }
+ }
- public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
- {
- JsonElement prop;
+ public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
+ {
+ JsonElement prop;
- if (!userData.TryGetProperty(ValueType, out prop))
- return;
-
- if (prop.ValueKind == JsonValueKind.Null)
- {
- return;
- }
+ if (!userData.TryGetProperty(ValueType, out prop))
+ return;
- Claim claim;
- switch (prop.ValueKind)
- {
- case JsonValueKind.String:
- claim = new Claim(ClaimType, prop.GetString(), ValueType, issuer);
+ if (prop.ValueKind == JsonValueKind.Null)
+ {
+ return;
+ }
+
+ Claim claim;
+ switch (prop.ValueKind)
+ {
+ case JsonValueKind.String:
+ claim = new Claim(ClaimType, prop.GetString(), ValueType, issuer);
+ if (!identity.Claims.Any(c => c.Type == claim.Type && c.Value == claim.Value))
+ {
+ identity.AddClaim(claim);
+ }
+ break;
+ case JsonValueKind.Array:
+ foreach (var arramItem in prop.EnumerateArray())
+ {
+ claim = new Claim(ClaimType, arramItem.GetString(), ValueType, issuer);
if (!identity.Claims.Any(c => c.Type == claim.Type && c.Value == claim.Value))
{
identity.AddClaim(claim);
}
- break;
- case JsonValueKind.Array:
- foreach (var arramItem in prop.EnumerateArray())
- {
- claim = new Claim(ClaimType, arramItem.GetString(), ValueType, issuer);
- if (!identity.Claims.Any(c => c.Type == claim.Type && c.Value == claim.Value))
- {
- identity.AddClaim(claim);
- }
- }
- break;
- default:
- throw new AbpException("Unhandled JsonValueKind: " + prop.ValueKind);
- }
+ }
+ break;
+ default:
+ throw new AbpException("Unhandled JsonValueKind: " + prop.ValueKind);
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/RemoveDuplicateClaimAction.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/RemoveDuplicateClaimAction.cs
index ab3e4027c2..80773ed481 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/RemoveDuplicateClaimAction.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/RemoveDuplicateClaimAction.cs
@@ -5,36 +5,35 @@ using System.Security.Claims;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
-namespace Volo.Abp.AspNetCore.Authentication.OAuth.Claims
+namespace Volo.Abp.AspNetCore.Authentication.OAuth.Claims;
+
+public class RemoveDuplicateClaimAction : ClaimAction
{
- public class RemoveDuplicateClaimAction : ClaimAction
+ public RemoveDuplicateClaimAction(string claimType)
+ : base(claimType, ClaimValueTypes.String)
{
- public RemoveDuplicateClaimAction(string claimType)
- : base(claimType, ClaimValueTypes.String)
+ }
+
+ ///
+ public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
+ {
+ var claims = identity.Claims.Where(c => c.Type == ClaimType).ToArray();
+ if (claims.Length < 2)
{
+ return;
}
- ///
- public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
+ var previousValues = new List();
+ foreach (var claim in claims)
{
- var claims = identity.Claims.Where(c => c.Type == ClaimType).ToArray();
- if (claims.Length < 2)
+ if (claim.Value.IsIn(previousValues))
{
- return;
+ identity.RemoveClaim(claim);
}
-
- var previousValues = new List();
- foreach (var claim in claims)
+ else
{
- if (claim.Value.IsIn(previousValues))
- {
- identity.RemoveClaim(claim);
- }
- else
- {
- previousValues.Add(claim.Value);
- }
+ previousValues.Add(claim.Value);
}
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
index acd4233512..02b292a984 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
@@ -7,59 +7,58 @@ using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Volo.Abp.AspNetCore.MultiTenancy;
-namespace Microsoft.Extensions.DependencyInjection
+namespace Microsoft.Extensions.DependencyInjection;
+
+public static class AbpOpenIdConnectExtensions
{
- public static class AbpOpenIdConnectExtensions
- {
- public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder)
- => builder.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, _ => { });
+ public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder)
+ => builder.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, _ => { });
- public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, Action configureOptions)
- => builder.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, configureOptions);
+ public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, Action configureOptions)
+ => builder.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, configureOptions);
- public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions)
- => builder.AddAbpOpenIdConnect(authenticationScheme, OpenIdConnectDefaults.DisplayName, configureOptions);
+ public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, Action configureOptions)
+ => builder.AddAbpOpenIdConnect(authenticationScheme, OpenIdConnectDefaults.DisplayName, configureOptions);
- public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions)
+ public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action configureOptions)
+ {
+ return builder.AddOpenIdConnect(authenticationScheme, displayName, options =>
{
- return builder.AddOpenIdConnect(authenticationScheme, displayName, options =>
- {
- options.ClaimActions.MapAbpClaimTypes();
+ options.ClaimActions.MapAbpClaimTypes();
- configureOptions?.Invoke(options);
+ configureOptions?.Invoke(options);
- options.Events ??= new OpenIdConnectEvents();
- var authorizationCodeReceived = options.Events.OnAuthorizationCodeReceived ?? (_ => Task.CompletedTask);
+ options.Events ??= new OpenIdConnectEvents();
+ var authorizationCodeReceived = options.Events.OnAuthorizationCodeReceived ?? (_ => Task.CompletedTask);
- options.Events.OnAuthorizationCodeReceived = receivedContext =>
- {
- SetAbpTenantId(receivedContext);
- return authorizationCodeReceived.Invoke(receivedContext);
- };
+ options.Events.OnAuthorizationCodeReceived = receivedContext =>
+ {
+ SetAbpTenantId(receivedContext);
+ return authorizationCodeReceived.Invoke(receivedContext);
+ };
- options.Events.OnRemoteFailure = remoteFailureContext =>
+ options.Events.OnRemoteFailure = remoteFailureContext =>
+ {
+ if (remoteFailureContext.Failure is OpenIdConnectProtocolException &&
+ remoteFailureContext.Failure.Message.Contains("access_denied"))
{
- if (remoteFailureContext.Failure is OpenIdConnectProtocolException &&
- remoteFailureContext.Failure.Message.Contains("access_denied"))
- {
- remoteFailureContext.HandleResponse();
- remoteFailureContext.Response.Redirect($"{remoteFailureContext.Request.PathBase}/");
- }
- return Task.CompletedTask;
- };
- });
- }
+ remoteFailureContext.HandleResponse();
+ remoteFailureContext.Response.Redirect($"{remoteFailureContext.Request.PathBase}/");
+ }
+ return Task.CompletedTask;
+ };
+ });
+ }
- private static void SetAbpTenantId(AuthorizationCodeReceivedContext receivedContext)
- {
- var tenantKey = receivedContext.HttpContext.RequestServices
- .GetRequiredService>().Value.TenantKey;
+ private static void SetAbpTenantId(AuthorizationCodeReceivedContext receivedContext)
+ {
+ var tenantKey = receivedContext.HttpContext.RequestServices
+ .GetRequiredService>().Value.TenantKey;
- if (receivedContext.Request.Cookies.ContainsKey(tenantKey))
- {
- receivedContext.TokenEndpointRequest.SetParameter(tenantKey,
- receivedContext.Request.Cookies[tenantKey]);
- }
+ if (receivedContext.Request.Cookies.ContainsKey(tenantKey))
+ {
+ receivedContext.TokenEndpointRequest.SetParameter(tenantKey,
+ receivedContext.Request.Cookies[tenantKey]);
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo/Abp/AspNetCore/Authentication/OpenIdConnect/AbpAspNetCoreAuthenticationOpenIdConnectModule.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo/Abp/AspNetCore/Authentication/OpenIdConnect/AbpAspNetCoreAuthenticationOpenIdConnectModule.cs
index 13a8fd5c04..8670fbea17 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo/Abp/AspNetCore/Authentication/OpenIdConnect/AbpAspNetCoreAuthenticationOpenIdConnectModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo/Abp/AspNetCore/Authentication/OpenIdConnect/AbpAspNetCoreAuthenticationOpenIdConnectModule.cs
@@ -2,13 +2,12 @@
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
-namespace Volo.Abp.AspNetCore.Authentication.OpenIdConnect
+namespace Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
+
+[DependsOn(
+ typeof(AbpMultiTenancyModule),
+ typeof(AbpAspNetCoreAuthenticationOAuthModule))]
+public class AbpAspNetCoreAuthenticationOpenIdConnectModule : AbpModule
{
- [DependsOn(
- typeof(AbpMultiTenancyModule),
- typeof(AbpAspNetCoreAuthenticationOAuthModule))]
- public class AbpAspNetCoreAuthenticationOpenIdConnectModule : AbpModule
- {
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/AbpAspNetCoreComponentsServerThemingModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/AbpAspNetCoreComponentsServerThemingModule.cs
index 72462b97d6..dab511b595 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/AbpAspNetCoreComponentsServerThemingModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/AbpAspNetCoreComponentsServerThemingModule.cs
@@ -4,34 +4,33 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages;
using Volo.Abp.Modularity;
-namespace Volo.Abp.AspNetCore.Components.Server.Theming
+namespace Volo.Abp.AspNetCore.Components.Server.Theming;
+
+[DependsOn(
+ typeof(AbpAspNetCoreComponentsServerModule),
+ typeof(AbpAspNetCoreMvcUiPackagesModule),
+ typeof(AbpAspNetCoreComponentsWebThemingModule),
+ typeof(AbpAspNetCoreMvcUiBundlingModule)
+ )]
+public class AbpAspNetCoreComponentsServerThemingModule : AbpModule
{
- [DependsOn(
- typeof(AbpAspNetCoreComponentsServerModule),
- typeof(AbpAspNetCoreMvcUiPackagesModule),
- typeof(AbpAspNetCoreComponentsWebThemingModule),
- typeof(AbpAspNetCoreMvcUiBundlingModule)
- )]
- public class AbpAspNetCoreComponentsServerThemingModule : AbpModule
+ public override void ConfigureServices(ServiceConfigurationContext context)
{
- public override void ConfigureServices(ServiceConfigurationContext context)
+ Configure(options =>
{
- Configure(options =>
- {
- options
- .StyleBundles
- .Add(BlazorStandardBundles.Styles.Global, bundle =>
- {
- bundle.AddContributors(typeof(BlazorGlobalStyleContributor));
- });
-
- options
- .ScriptBundles
- .Add(BlazorStandardBundles.Scripts.Global, bundle =>
- {
- bundle.AddContributors(typeof(BlazorGlobalScriptContributor));
- });
- });
- }
+ options
+ .StyleBundles
+ .Add(BlazorStandardBundles.Styles.Global, bundle =>
+ {
+ bundle.AddContributors(typeof(BlazorGlobalStyleContributor));
+ });
+
+ options
+ .ScriptBundles
+ .Add(BlazorStandardBundles.Scripts.Global, bundle =>
+ {
+ bundle.AddContributors(typeof(BlazorGlobalScriptContributor));
+ });
+ });
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalBundles.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalBundles.cs
index 7112fd342d..d65efa0c3f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalBundles.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalBundles.cs
@@ -1,15 +1,14 @@
-namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling
+namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling;
+
+public class BlazorStandardBundles
{
- public class BlazorStandardBundles
+ public static class Styles
{
- public static class Styles
- {
- public static string Global = "Blazor.Global";
- }
+ public static string Global = "Blazor.Global";
+ }
- public static class Scripts
- {
- public static string Global = "Blazor.Global";
- }
+ public static class Scripts
+ {
+ public static string Global = "Blazor.Global";
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
index 6a0542f717..8977acc869 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
@@ -1,14 +1,13 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
-namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling
+namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling;
+
+public class BlazorGlobalScriptContributor : BundleContributor
{
- public class BlazorGlobalScriptContributor : BundleContributor
+ public override void ConfigureBundle(BundleConfigurationContext context)
{
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.AddIfNotContains("/_framework/blazor.server.js");
- context.Files.AddIfNotContains("/_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js");
- }
+ context.Files.AddIfNotContains("/_framework/blazor.server.js");
+ context.Files.AddIfNotContains("/_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js");
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalStyleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalStyleContributor.cs
index 9e712ffba7..3223be417c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalStyleContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalStyleContributor.cs
@@ -4,19 +4,18 @@ using Volo.Abp.AspNetCore.Mvc.UI.Packages.Bootstrap;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.FontAwesome;
using Volo.Abp.Modularity;
-namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling
+namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling;
+
+[DependsOn(
+ typeof(BootstrapStyleContributor),
+ typeof(FontAwesomeStyleContributor)
+)]
+public class BlazorGlobalStyleContributor : BundleContributor
{
- [DependsOn(
- typeof(BootstrapStyleContributor),
- typeof(FontAwesomeStyleContributor)
- )]
- public class BlazorGlobalStyleContributor : BundleContributor
+ public override void ConfigureBundle(BundleConfigurationContext context)
{
- public override void ConfigureBundle(BundleConfigurationContext context)
- {
- context.Files.AddIfNotContains("/_content/Blazorise/blazorise.css");
- context.Files.AddIfNotContains("/_content/Blazorise.Bootstrap5/blazorise.bootstrap5.css");
- context.Files.AddIfNotContains("/_content/Blazorise.Snackbar/blazorise.snackbar.css");
- }
+ context.Files.AddIfNotContains("/_content/Blazorise/blazorise.css");
+ context.Files.AddIfNotContains("/_content/Blazorise.Bootstrap5/blazorise.bootstrap5.css");
+ context.Files.AddIfNotContains("/_content/Blazorise.Snackbar/blazorise.snackbar.css");
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
index 91b672b073..dfa515c1b8 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Hosting;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Mvc;
@@ -12,49 +13,54 @@ using Volo.Abp.EventBus;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
-namespace Volo.Abp.AspNetCore.Components.Server
+namespace Volo.Abp.AspNetCore.Components.Server;
+
+[DependsOn(
+ typeof(AbpHttpClientModule),
+ typeof(AbpAspNetCoreComponentsWebModule),
+ typeof(AbpAspNetCoreSignalRModule),
+ typeof(AbpEventBusModule),
+ typeof(AbpAspNetCoreMvcContractsModule)
+ )]
+public class AbpAspNetCoreComponentsServerModule : AbpModule
{
- [DependsOn(
- typeof(AbpHttpClientModule),
- typeof(AbpAspNetCoreComponentsWebModule),
- typeof(AbpAspNetCoreSignalRModule),
- typeof(AbpEventBusModule),
- typeof(AbpAspNetCoreMvcContractsModule)
- )]
- public class AbpAspNetCoreComponentsServerModule : AbpModule
+ public override void ConfigureServices(ServiceConfigurationContext context)
{
- public override void ConfigureServices(ServiceConfigurationContext context)
+ var serverSideBlazorBuilder = context.Services.AddServerSideBlazor(options =>
{
- var serverSideBlazorBuilder = context.Services.AddServerSideBlazor();
- context.Services.ExecutePreConfiguredActions(serverSideBlazorBuilder);
-
- Configure(options =>
+ if (context.Services.GetHostingEnvironment().IsDevelopment())
{
- options.IgnoredUrls.AddIfNotContains("/_blazor");
- });
+ options.DetailedErrors = true;
+ }
+ });
+ context.Services.ExecutePreConfiguredActions(serverSideBlazorBuilder);
- Configure(options =>
- {
- options.IgnoredUrls.AddIfNotContains("/_blazor");
- });
+ Configure(options =>
+ {
+ options.IgnoredUrls.AddIfNotContains("/_blazor");
+ });
- Configure(options =>
+ Configure(options =>
+ {
+ options.IgnoredUrls.AddIfNotContains("/_blazor");
+ });
+
+ Configure(options =>
+ {
+ options.EndpointConfigureActions.Add(endpointContext =>
{
- options.EndpointConfigureActions.Add(endpointContext =>
- {
- endpointContext.Endpoints.MapBlazorHub();
- endpointContext.Endpoints.MapFallbackToPage("/_Host");
- });
+ endpointContext.Endpoints.MapBlazorHub();
+ endpointContext.Endpoints.MapFallbackToPage("/_Host");
});
- }
+ });
+ }
- public override void OnApplicationInitialization(ApplicationInitializationContext context)
- {
- context.GetEnvironment().WebRootFileProvider =
- new CompositeFileProvider(
- new ManifestEmbeddedFileProvider(typeof(IServerSideBlazorBuilder).Assembly),
- context.GetEnvironment().WebRootFileProvider
- );
- }
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ context.GetEnvironment().WebRootFileProvider =
+ new CompositeFileProvider(
+ new ManifestEmbeddedFileProvider(typeof(IServerSideBlazorBuilder).Assembly),
+ context.GetEnvironment().WebRootFileProvider
+ );
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Configuration/BlazorServerCurrentApplicationConfigurationCacheResetService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Configuration/BlazorServerCurrentApplicationConfigurationCacheResetService.cs
index 1e3cd857e5..02de9d8bf7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Configuration/BlazorServerCurrentApplicationConfigurationCacheResetService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Configuration/BlazorServerCurrentApplicationConfigurationCacheResetService.cs
@@ -4,26 +4,25 @@ using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Local;
-namespace Volo.Abp.AspNetCore.Components.Server.Configuration
+namespace Volo.Abp.AspNetCore.Components.Server.Configuration;
+
+[Dependency(ReplaceServices = true)]
+public class BlazorServerCurrentApplicationConfigurationCacheResetService :
+ ICurrentApplicationConfigurationCacheResetService,
+ ITransientDependency
{
- [Dependency(ReplaceServices = true)]
- public class BlazorServerCurrentApplicationConfigurationCacheResetService :
- ICurrentApplicationConfigurationCacheResetService,
- ITransientDependency
- {
- private readonly ILocalEventBus _localEventBus;
+ private readonly ILocalEventBus _localEventBus;
- public BlazorServerCurrentApplicationConfigurationCacheResetService(
- ILocalEventBus localEventBus)
- {
- _localEventBus = localEventBus;
- }
+ public BlazorServerCurrentApplicationConfigurationCacheResetService(
+ ILocalEventBus localEventBus)
+ {
+ _localEventBus = localEventBus;
+ }
- public async Task ResetAsync()
- {
- await _localEventBus.PublishAsync(
- new CurrentApplicationConfigurationCacheResetEventData()
- );
- }
+ public async Task ResetAsync()
+ {
+ await _localEventBus.PublishAsync(
+ new CurrentApplicationConfigurationCacheResetEventData()
+ );
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
index 952a2d6de4..2071e40f0b 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
@@ -13,78 +13,77 @@ using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.MultiTenancy;
-namespace Volo.Abp.AspNetCore.Components.Server.Extensibility
+namespace Volo.Abp.AspNetCore.Components.Server.Extensibility;
+
+public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITransientDependency
{
- public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITransientDependency
+ public IHttpClientFactory HttpClientFactory { get; }
+ public IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
+ public IRemoteServiceConfigurationProvider RemoteServiceConfigurationProvider { get; }
+ public ICurrentTenant CurrentTenant { get; }
+ public IHttpContextAccessor HttpContextAccessor { get; }
+ public NavigationManager NavigationManager { get; }
+
+ public BlazorServerLookupApiRequestService(IHttpClientFactory httpClientFactory,
+ IRemoteServiceHttpClientAuthenticator httpClientAuthenticator,
+ ICurrentTenant currentTenant,
+ IHttpContextAccessor httpContextAccessor,
+ NavigationManager navigationManager,
+ IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider)
{
- public IHttpClientFactory HttpClientFactory { get; }
- public IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
- public IRemoteServiceConfigurationProvider RemoteServiceConfigurationProvider { get; }
- public ICurrentTenant CurrentTenant { get; }
- public IHttpContextAccessor HttpContextAccessor { get; }
- public NavigationManager NavigationManager { get; }
+ HttpClientFactory = httpClientFactory;
+ HttpClientAuthenticator = httpClientAuthenticator;
+ CurrentTenant = currentTenant;
+ HttpContextAccessor = httpContextAccessor;
+ NavigationManager = navigationManager;
+ RemoteServiceConfigurationProvider = remoteServiceConfigurationProvider;
+ }
- public BlazorServerLookupApiRequestService(IHttpClientFactory httpClientFactory,
- IRemoteServiceHttpClientAuthenticator httpClientAuthenticator,
- ICurrentTenant currentTenant,
- IHttpContextAccessor httpContextAccessor,
- NavigationManager navigationManager,
- IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider)
- {
- HttpClientFactory = httpClientFactory;
- HttpClientAuthenticator = httpClientAuthenticator;
- CurrentTenant = currentTenant;
- HttpContextAccessor = httpContextAccessor;
- NavigationManager = navigationManager;
- RemoteServiceConfigurationProvider = remoteServiceConfigurationProvider;
- }
+ public async Task SendAsync(string url)
+ {
+ var client = HttpClientFactory.CreateClient();
+ var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
- public async Task SendAsync(string url)
+ var uri = new Uri(url, UriKind.RelativeOrAbsolute);
+ if (!uri.IsAbsoluteUri)
{
- var client = HttpClientFactory.CreateClient();
- var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
-
- var uri = new Uri(url, UriKind.RelativeOrAbsolute);
- if (!uri.IsAbsoluteUri)
+ var baseUrl = string.Empty;
+ try
{
- var baseUrl = string.Empty;
- try
- {
- //Blazor tiered -- mode
- var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Default");
- baseUrl = remoteServiceConfig.BaseUrl;
- client.BaseAddress = new Uri(baseUrl);
- AddHeaders(requestMessage);
- await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client,
- requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
- }
- catch (AbpException) // Blazor-Server mode.
+ //Blazor tiered -- mode
+ var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Default");
+ baseUrl = remoteServiceConfig.BaseUrl;
+ client.BaseAddress = new Uri(baseUrl);
+ AddHeaders(requestMessage);
+ await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client,
+ requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
+ }
+ catch (AbpException) // Blazor-Server mode.
+ {
+ baseUrl = NavigationManager.BaseUri;
+ client.BaseAddress = new Uri(baseUrl);
+ foreach (var header in HttpContextAccessor.HttpContext.Request.Headers)
{
- baseUrl = NavigationManager.BaseUri;
- client.BaseAddress = new Uri(baseUrl);
- foreach (var header in HttpContextAccessor.HttpContext.Request.Headers)
- {
- requestMessage.Headers.Add(header.Key, header.Value.ToArray());
- }
+ requestMessage.Headers.Add(header.Key, header.Value.ToArray());
}
}
-
- var response = await client.SendAsync(requestMessage);
- return await response.Content.ReadAsStringAsync();
}
- protected virtual void AddHeaders(HttpRequestMessage requestMessage)
+ var response = await client.SendAsync(requestMessage);
+ return await response.Content.ReadAsStringAsync();
+ }
+
+ protected virtual void AddHeaders(HttpRequestMessage requestMessage)
+ {
+ if (CurrentTenant.Id.HasValue)
{
- if (CurrentTenant.Id.HasValue)
- {
- requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
- }
+ requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
+ }
- var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
- if (!currentCulture.IsNullOrEmpty())
- {
- requestMessage.Headers.AcceptLanguage.Add(new(currentCulture));
- }
+ var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
+ if (!currentCulture.IsNullOrEmpty())
+ {
+ requestMessage.Headers.AcceptLanguage.Add(new(currentCulture));
}
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/AbpAspNetCoreComponentsWebThemingModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/AbpAspNetCoreComponentsWebThemingModule.cs
index e5c71c8496..e2a0617b90 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/AbpAspNetCoreComponentsWebThemingModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/AbpAspNetCoreComponentsWebThemingModule.cs
@@ -2,14 +2,13 @@
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming
+namespace Volo.Abp.AspNetCore.Components.Web.Theming;
+
+[DependsOn(
+ typeof(AbpBlazoriseUIModule),
+ typeof(AbpUiNavigationModule)
+ )]
+public class AbpAspNetCoreComponentsWebThemingModule : AbpModule
{
- [DependsOn(
- typeof(AbpBlazoriseUIModule),
- typeof(AbpUiNavigationModule)
- )]
- public class AbpAspNetCoreComponentsWebThemingModule : AbpModule
- {
-
- }
-}
\ No newline at end of file
+
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
index 7806aa4b44..594909cd52 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
@@ -5,69 +5,68 @@ using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
using Volo.Abp.BlazoriseUI;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout;
+
+public partial class PageHeader : ComponentBase
{
- public partial class PageHeader : ComponentBase
- {
- protected List ToolbarItemRenders { get; set; }
-
- public IPageToolbarManager PageToolbarManager { get; set; }
-
- [Parameter]
- public string Title { get; set; }
+ protected List ToolbarItemRenders { get; set; }
- [Parameter]
- public bool BreadcrumbShowHome { get; set; } = true;
+ public IPageToolbarManager PageToolbarManager { get; set; }
- [Parameter]
- public bool BreadcrumbShowCurrent { get; set; } = true;
+ [Parameter]
+ public string Title { get; set; }
- [Parameter]
- public RenderFragment ChildContent { get; set; }
+ [Parameter]
+ public bool BreadcrumbShowHome { get; set; } = true;
- [Parameter]
- public List BreadcrumbItems { get; set; }
-
- [Parameter]
- public PageToolbar Toolbar { get; set; }
+ [Parameter]
+ public bool BreadcrumbShowCurrent { get; set; } = true;
- public PageHeader()
- {
- BreadcrumbItems = new List();
- ToolbarItemRenders = new List();
- }
+ [Parameter]
+ public RenderFragment ChildContent { get; set; }
+
+ [Parameter]
+ public List BreadcrumbItems { get; set; }
+
+ [Parameter]
+ public PageToolbar Toolbar { get; set; }
+
+ public PageHeader()
+ {
+ BreadcrumbItems = new List();
+ ToolbarItemRenders = new List();
+ }
- protected override async Task OnParametersSetAsync()
+ protected override async Task OnParametersSetAsync()
+ {
+ await base.OnParametersSetAsync();
+ if (Toolbar != null)
{
- await base.OnParametersSetAsync();
- if (Toolbar!=null)
- {
- var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar);
- ToolbarItemRenders.Clear();
+ var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar);
+ ToolbarItemRenders.Clear();
- foreach (var item in toolbarItems)
+ foreach (var item in toolbarItems)
+ {
+ var sequence = 0;
+ ToolbarItemRenders.Add(builder =>
{
- var sequence = 0;
- ToolbarItemRenders.Add(builder =>
+ builder.OpenComponent(sequence, item.ComponentType);
+ if (item.Arguments != null)
{
- builder.OpenComponent(sequence, item.ComponentType);
- if (item.Arguments != null)
+ foreach (var argument in item.Arguments)
{
- foreach (var argument in item.Arguments)
- {
- sequence++;
- builder.AddAttribute(sequence, argument.Key, argument.Value);
- }
+ sequence++;
+ builder.AddAttribute(sequence, argument.Key, argument.Value);
}
- builder.CloseComponent();
- });
- }
+ }
+ builder.CloseComponent();
+ });
}
}
+ }
- protected override async Task OnInitializedAsync()
- {
- await base.OnInitializedAsync();
- }
+ protected override async Task OnInitializedAsync()
+ {
+ await base.OnInitializedAsync();
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
index dd04c0a1ff..426fdde4c9 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
@@ -1,9 +1,8 @@
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public interface IPageToolbarContributor
{
- public interface IPageToolbarContributor
- {
- Task ContributeAsync(PageToolbarContributionContext context);
- }
+ Task ContributeAsync(PageToolbarContributionContext context);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
index 507fa8070b..87e256b1ce 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
@@ -1,9 +1,8 @@
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public interface IPageToolbarManager
{
- public interface IPageToolbarManager
- {
- Task GetItemsAsync(PageToolbar toolbar);
- }
+ Task GetItemsAsync(PageToolbar toolbar);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
index 84a9bae7c4..f1fb792996 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
@@ -1,12 +1,11 @@
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbar
{
- public class PageToolbar
- {
- public PageToolbarContributorList Contributors { get; set; }
+ public PageToolbarContributorList Contributors { get; set; }
- public PageToolbar()
- {
- Contributors = new PageToolbarContributorList();
- }
+ public PageToolbar()
+ {
+ Contributors = new PageToolbarContributorList();
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
index 5544510b71..057777cfdf 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
@@ -1,21 +1,20 @@
using JetBrains.Annotations;
using System;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbarContributionContext
{
- public class PageToolbarContributionContext
- {
- [NotNull]
- public IServiceProvider ServiceProvider { get; }
+ [NotNull]
+ public IServiceProvider ServiceProvider { get; }
- [NotNull]
- public PageToolbarItemList Items { get; }
+ [NotNull]
+ public PageToolbarItemList Items { get; }
- public PageToolbarContributionContext(
- [NotNull] IServiceProvider serviceProvider)
- {
- ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider));
- Items = new PageToolbarItemList();
- }
+ public PageToolbarContributionContext(
+ [NotNull] IServiceProvider serviceProvider)
+ {
+ ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider));
+ Items = new PageToolbarItemList();
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
index 3c5196c449..87521c592f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
@@ -1,9 +1,8 @@
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public abstract class PageToolbarContributor : IPageToolbarContributor
{
- public abstract class PageToolbarContributor : IPageToolbarContributor
- {
- public abstract Task ContributeAsync(PageToolbarContributionContext context);
- }
+ public abstract Task ContributeAsync(PageToolbarContributionContext context);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
index 984f4618dc..02ef1bfb00 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
@@ -1,8 +1,7 @@
using System.Collections.Generic;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbarContributorList : List
{
- public class PageToolbarContributorList : List
- {
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
index 2368ab9caf..65c2e8a25d 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
@@ -1,9 +1,8 @@
using System.Collections.Generic;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbarDictionary : Dictionary
{
- public class PageToolbarDictionary : Dictionary
- {
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
index 3879e27e3c..dd2063d0cf 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
@@ -5,67 +5,66 @@ using System.Threading.Tasks;
using Volo.Abp.BlazoriseUI.Components;
using Volo.Abp.Localization;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public static class PageToolbarExtensions
{
- public static class PageToolbarExtensions
+ public static PageToolbar AddComponent(
+ this PageToolbar toolbar,
+ Dictionary arguments = null,
+ int order = 0,
+ string requiredPolicyName = null)
{
- public static PageToolbar AddComponent(
- this PageToolbar toolbar,
- Dictionary arguments = null,
- int order = 0,
- string requiredPolicyName = null)
- {
- return toolbar.AddComponent(
- typeof(TComponent),
+ return toolbar.AddComponent(
+ typeof(TComponent),
+ arguments,
+ order,
+ requiredPolicyName
+ );
+ }
+
+ public static PageToolbar AddComponent(
+ this PageToolbar toolbar,
+ Type componentType,
+ Dictionary arguments = null,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ toolbar.Contributors.Add(
+ new SimplePageToolbarContributor(
+ componentType,
arguments,
order,
requiredPolicyName
- );
- }
-
- public static PageToolbar AddComponent(
- this PageToolbar toolbar,
- Type componentType,
- Dictionary arguments = null,
- int order = 0,
- string requiredPolicyName = null)
- {
- toolbar.Contributors.Add(
- new SimplePageToolbarContributor(
- componentType,
- arguments,
- order,
- requiredPolicyName
- )
- );
+ )
+ );
- return toolbar;
- }
+ return toolbar;
+ }
- public static PageToolbar AddButton(
- this PageToolbar toolbar,
- string text,
- Func clicked,
- object icon = null,
- Color color = Color.Primary,
- bool disabled = false,
- int order = 0,
- string requiredPolicyName = null)
- {
- toolbar.AddComponent(
- new Dictionary
- {
+ public static PageToolbar AddButton(
+ this PageToolbar toolbar,
+ string text,
+ Func clicked,
+ object icon = null,
+ Color color = Color.Primary,
+ bool disabled = false,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ toolbar.AddComponent(
+ new Dictionary
+ {
{ nameof(ToolbarButton.Color), color},
{ nameof(ToolbarButton.Text), text},
{ nameof(ToolbarButton.Disabled), disabled},
{ nameof(ToolbarButton.Icon), icon},
{ nameof(ToolbarButton.Clicked),clicked},
- },
- order,
- requiredPolicyName
- );
+ },
+ order,
+ requiredPolicyName
+ );
- return toolbar;
- }
+ return toolbar;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
index 0e1650a803..f62d770403 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
@@ -2,26 +2,25 @@
using System;
using System.Collections.Generic;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbarItem
{
- public class PageToolbarItem
- {
- [NotNull]
- public Type ComponentType { get; }
+ [NotNull]
+ public Type ComponentType { get; }
- [CanBeNull]
- public Dictionary Arguments { get; set; }
+ [CanBeNull]
+ public Dictionary Arguments { get; set; }
- public int Order { get; set; }
+ public int Order { get; set; }
- public PageToolbarItem(
- [NotNull] Type componentType,
- [CanBeNull] Dictionary arguments = null,
- int order = 0)
- {
- ComponentType = Check.NotNull(componentType, nameof(componentType));
- Arguments = arguments;
- Order = order;
- }
+ public PageToolbarItem(
+ [NotNull] Type componentType,
+ [CanBeNull] Dictionary arguments = null,
+ int order = 0)
+ {
+ ComponentType = Check.NotNull(componentType, nameof(componentType));
+ Arguments = arguments;
+ Order = order;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
index 7042b2ed05..4be5e6fab1 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
@@ -1,9 +1,8 @@
using System.Collections.Generic;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbarItemList : List
{
- public class PageToolbarItemList : List
- {
- }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
index adcd72f25e..05531096d4 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
@@ -5,36 +5,35 @@ using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class PageToolbarManager : IPageToolbarManager, ITransientDependency
{
- public class PageToolbarManager : IPageToolbarManager, ITransientDependency
+ protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
+
+ public PageToolbarManager(
+ IHybridServiceScopeFactory serviceScopeFactory)
{
- protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
+ ServiceScopeFactory = serviceScopeFactory;
+ }
- public PageToolbarManager(
- IHybridServiceScopeFactory serviceScopeFactory)
+ public virtual async Task GetItemsAsync(PageToolbar toolbar)
+ {
+ if (toolbar == null || !toolbar.Contributors.Any())
{
- ServiceScopeFactory = serviceScopeFactory;
+ return Array.Empty();
}
- public virtual async Task GetItemsAsync(PageToolbar toolbar)
+ using (var scope = ServiceScopeFactory.CreateScope())
{
- if (toolbar == null || !toolbar.Contributors.Any())
- {
- return Array.Empty();
- }
+ var context = new PageToolbarContributionContext(scope.ServiceProvider);
- using (var scope = ServiceScopeFactory.CreateScope())
+ foreach (var contributor in toolbar.Contributors)
{
- var context = new PageToolbarContributionContext(scope.ServiceProvider);
-
- foreach (var contributor in toolbar.Contributors)
- {
- await contributor.ContributeAsync(context);
- }
-
- return context.Items.OrderBy(i => i.Order).ToArray();
+ await contributor.ContributeAsync(context);
}
+
+ return context.Items.OrderBy(i => i.Order).ToArray();
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
index 82afe19f7f..d31b12e73c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
@@ -4,50 +4,49 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+
+public class SimplePageToolbarContributor : IPageToolbarContributor
{
- public class SimplePageToolbarContributor : IPageToolbarContributor
- {
- public Type ComponentType { get; }
+ public Type ComponentType { get; }
- public Dictionary Arguments { get; set; }
+ public Dictionary Arguments { get; set; }
- public int Order { get; }
+ public int Order { get; }
- public string RequiredPolicyName { get; }
+ public string RequiredPolicyName { get; }
- public SimplePageToolbarContributor(
- Type componentType,
- Dictionary arguments = null,
- int order = 0,
- string requiredPolicyName = null)
- {
- ComponentType = componentType;
- Arguments = arguments;
- Order = order;
- RequiredPolicyName = requiredPolicyName;
- }
+ public SimplePageToolbarContributor(
+ Type componentType,
+ Dictionary arguments = null,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ ComponentType = componentType;
+ Arguments = arguments;
+ Order = order;
+ RequiredPolicyName = requiredPolicyName;
+ }
- public async Task ContributeAsync(PageToolbarContributionContext context)
+ public async Task ContributeAsync(PageToolbarContributionContext context)
+ {
+ if (await ShouldAddComponentAsync(context))
{
- if (await ShouldAddComponentAsync(context))
- {
- context.Items.Add(new PageToolbarItem(ComponentType, Arguments, Order));
- }
+ context.Items.Add(new PageToolbarItem(ComponentType, Arguments, Order));
}
+ }
- protected virtual async Task ShouldAddComponentAsync(PageToolbarContributionContext context)
+ protected virtual async Task ShouldAddComponentAsync(PageToolbarContributionContext context)
+ {
+ if (RequiredPolicyName != null)
{
- if (RequiredPolicyName != null)
+ var authorizationService = context.ServiceProvider.GetRequiredService();
+ if (!await authorizationService.IsGrantedAsync(RequiredPolicyName))
{
- var authorizationService = context.ServiceProvider.GetRequiredService();
- if (!await authorizationService.IsGrantedAsync(RequiredPolicyName))
- {
- return false;
- }
+ return false;
}
-
- return true;
}
+
+ return true;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
index 9655d41186..ce3b2746e4 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
@@ -1,16 +1,15 @@
using System.Reflection;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Routing
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
+
+public class AbpRouterOptions
{
- public class AbpRouterOptions
- {
- public Assembly AppAssembly { get; set; }
+ public Assembly AppAssembly { get; set; }
- public RouterAssemblyList AdditionalAssemblies { get; }
+ public RouterAssemblyList AdditionalAssemblies { get; }
- public AbpRouterOptions()
- {
- AdditionalAssemblies = new RouterAssemblyList();
- }
+ public AbpRouterOptions()
+ {
+ AdditionalAssemblies = new RouterAssemblyList();
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/RouterAssemblyList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/RouterAssemblyList.cs
index ea1153ff1f..ad9d5ea404 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/RouterAssemblyList.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/RouterAssemblyList.cs
@@ -1,10 +1,9 @@
using System.Collections.Generic;
using System.Reflection;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Routing
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
+
+public class RouterAssemblyList : List
{
- public class RouterAssemblyList : List
- {
-
- }
-}
\ No newline at end of file
+
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/AbpToolbarOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/AbpToolbarOptions.cs
index a2bae7460d..b713386359 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/AbpToolbarOptions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/AbpToolbarOptions.cs
@@ -1,16 +1,15 @@
using System.Collections.Generic;
using JetBrains.Annotations;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public class AbpToolbarOptions
{
- public class AbpToolbarOptions
- {
- [NotNull]
- public List Contributors { get; }
+ [NotNull]
+ public List Contributors { get; }
- public AbpToolbarOptions()
- {
- Contributors = new List();
- }
+ public AbpToolbarOptions()
+ {
+ Contributors = new List();
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarConfigurationContext.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarConfigurationContext.cs
index 8ebe76bcb4..e2bfaf06d0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarConfigurationContext.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarConfigurationContext.cs
@@ -5,25 +5,24 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public interface IToolbarConfigurationContext : IServiceProviderAccessor
{
- public interface IToolbarConfigurationContext : IServiceProviderAccessor
- {
- Toolbar Toolbar { get; }
+ Toolbar Toolbar { get; }
- IAuthorizationService AuthorizationService { get; }
+ IAuthorizationService AuthorizationService { get; }
- IStringLocalizerFactory StringLocalizerFactory { get; }
+ IStringLocalizerFactory StringLocalizerFactory { get; }
- Task IsGrantedAsync(string policyName);
+ Task IsGrantedAsync(string policyName);
- [CanBeNull]
- IStringLocalizer GetDefaultLocalizer();
+ [CanBeNull]
+ IStringLocalizer GetDefaultLocalizer();
- [NotNull]
- public IStringLocalizer GetLocalizer();
+ [NotNull]
+ public IStringLocalizer GetLocalizer();
- [NotNull]
- public IStringLocalizer GetLocalizer(Type resourceType);
- }
+ [NotNull]
+ public IStringLocalizer GetLocalizer(Type resourceType);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarContributor.cs
index 6a5de9c1c9..c56f964265 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarContributor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarContributor.cs
@@ -1,9 +1,8 @@
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public interface IToolbarContributor
{
- public interface IToolbarContributor
- {
- Task ConfigureToolbarAsync(IToolbarConfigurationContext context);
- }
-}
\ No newline at end of file
+ Task ConfigureToolbarAsync(IToolbarConfigurationContext context);
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarManager.cs
index 0550ce75b6..df36b9ca32 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarManager.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarManager.cs
@@ -1,9 +1,8 @@
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public interface IToolbarManager
{
- public interface IToolbarManager
- {
- Task GetAsync(string name);
- }
+ Task GetAsync(string name);
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/StandardToolbars.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/StandardToolbars.cs
index 7cda0d8897..9c84d8165e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/StandardToolbars.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/StandardToolbars.cs
@@ -1,7 +1,6 @@
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public static class StandardToolbars
{
- public static class StandardToolbars
- {
- public const string Main = "Main";
- }
-}
\ No newline at end of file
+ public const string Main = "Main";
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/Toolbar.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/Toolbar.cs
index b25cc608b6..cd02da35c2 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/Toolbar.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/Toolbar.cs
@@ -1,18 +1,17 @@
using System.Collections.Generic;
using JetBrains.Annotations;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public class Toolbar
{
- public class Toolbar
- {
- public string Name { get; }
+ public string Name { get; }
- public List Items { get; }
+ public List Items { get; }
- public Toolbar([NotNull] string name)
- {
- Name = Check.NotNull(name, nameof(name));
- Items = new List();
- }
+ public Toolbar([NotNull] string name)
+ {
+ Name = Check.NotNull(name, nameof(name));
+ Items = new List();
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarConfigurationContext.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarConfigurationContext.cs
index fab4eb8f6c..f773ba14e1 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarConfigurationContext.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarConfigurationContext.cs
@@ -6,48 +6,47 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public class ToolbarConfigurationContext : IToolbarConfigurationContext
{
- public class ToolbarConfigurationContext : IToolbarConfigurationContext
- {
- public IServiceProvider ServiceProvider { get; }
+ public IServiceProvider ServiceProvider { get; }
- private readonly IAbpLazyServiceProvider _lazyServiceProvider;
+ private readonly IAbpLazyServiceProvider _lazyServiceProvider;
- public IAuthorizationService AuthorizationService => _lazyServiceProvider.LazyGetRequiredService();
+ public IAuthorizationService AuthorizationService => _lazyServiceProvider.LazyGetRequiredService();
- public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService();
+ public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService();
- public Toolbar Toolbar { get; }
+ public Toolbar Toolbar { get; }
- public ToolbarConfigurationContext(Toolbar toolbar, IServiceProvider serviceProvider)
- {
- Toolbar = toolbar;
- ServiceProvider = serviceProvider;
- _lazyServiceProvider = ServiceProvider.GetRequiredService();
- }
+ public ToolbarConfigurationContext(Toolbar toolbar, IServiceProvider serviceProvider)
+ {
+ Toolbar = toolbar;
+ ServiceProvider = serviceProvider;
+ _lazyServiceProvider = ServiceProvider.GetRequiredService();
+ }
- public Task IsGrantedAsync(string policyName)
- {
- return AuthorizationService.IsGrantedAsync(policyName);
- }
+ public Task IsGrantedAsync(string policyName)
+ {
+ return AuthorizationService.IsGrantedAsync(policyName);
+ }
- [CanBeNull]
- public IStringLocalizer GetDefaultLocalizer()
- {
- return StringLocalizerFactory.CreateDefaultOrNull();
- }
+ [CanBeNull]
+ public IStringLocalizer GetDefaultLocalizer()
+ {
+ return StringLocalizerFactory.CreateDefaultOrNull();
+ }
- [NotNull]
- public IStringLocalizer GetLocalizer()
- {
- return StringLocalizerFactory.Create();
- }
+ [NotNull]
+ public IStringLocalizer GetLocalizer()
+ {
+ return StringLocalizerFactory.Create();
+ }
- [NotNull]
- public IStringLocalizer GetLocalizer(Type resourceType)
- {
- return StringLocalizerFactory.Create(resourceType);
- }
+ [NotNull]
+ public IStringLocalizer GetLocalizer(Type resourceType)
+ {
+ return StringLocalizerFactory.Create(resourceType);
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarItem.cs
index d6bfcd1fb8..966145a4ee 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarItem.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarItem.cs
@@ -1,23 +1,21 @@
using System;
using JetBrains.Annotations;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public class ToolbarItem
{
- public class ToolbarItem
- {
- public Type ComponentType
- {
- get => _componentType;
- set => _componentType = Check.NotNull(value, nameof(value));
- }
- private Type _componentType;
+ public Type ComponentType {
+ get => _componentType;
+ set => _componentType = Check.NotNull(value, nameof(value));
+ }
+ private Type _componentType;
- public int Order { get; set; }
+ public int Order { get; set; }
- public ToolbarItem([NotNull] Type componentType, int order = 0)
- {
- Order = order;
- ComponentType = Check.NotNull(componentType, nameof(componentType));
- }
+ public ToolbarItem([NotNull] Type componentType, int order = 0)
+ {
+ Order = order;
+ ComponentType = Check.NotNull(componentType, nameof(componentType));
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarManager.cs
index 86bdfc751e..b4746fe85f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarManager.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarManager.cs
@@ -4,36 +4,35 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
+
+public class ToolbarManager : IToolbarManager, ITransientDependency
{
- public class ToolbarManager : IToolbarManager, ITransientDependency
+ protected AbpToolbarOptions Options { get; }
+ protected IServiceProvider ServiceProvider { get; }
+
+ public ToolbarManager(
+ IOptions options,
+ IServiceProvider serviceProvider)
{
- protected AbpToolbarOptions Options { get; }
- protected IServiceProvider ServiceProvider { get; }
+ ServiceProvider = serviceProvider;
+ Options = options.Value;
+ }
- public ToolbarManager(
- IOptions options,
- IServiceProvider serviceProvider)
- {
- ServiceProvider = serviceProvider;
- Options = options.Value;
- }
+ public async Task GetAsync(string name)
+ {
+ var toolbar = new Toolbar(name);
- public async Task GetAsync(string name)
+ using (var scope = ServiceProvider.CreateScope())
{
- var toolbar = new Toolbar(name);
+ var context = new ToolbarConfigurationContext(toolbar, scope.ServiceProvider);
- using (var scope = ServiceProvider.CreateScope())
+ foreach (var contributor in Options.Contributors)
{
- var context = new ToolbarConfigurationContext(toolbar, scope.ServiceProvider);
-
- foreach (var contributor in Options.Contributors)
- {
- await contributor.ConfigureToolbarAsync(context);
- }
+ await contributor.ConfigureToolbarAsync(context);
}
-
- return toolbar;
}
+
+ return toolbar;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreApplicationCreationOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreApplicationCreationOptions.cs
index 4eab62f819..27efa5f998 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreApplicationCreationOptions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreApplicationCreationOptions.cs
@@ -1,13 +1,12 @@
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+public class AbpAspNetCoreApplicationCreationOptions
{
- public class AbpAspNetCoreApplicationCreationOptions
- {
- public AbpApplicationCreationOptions ApplicationCreationOptions { get; }
+ public AbpApplicationCreationOptions ApplicationCreationOptions { get; }
- public AbpAspNetCoreApplicationCreationOptions(
- AbpApplicationCreationOptions applicationCreationOptions)
- {
- ApplicationCreationOptions = applicationCreationOptions;
- }
+ public AbpAspNetCoreApplicationCreationOptions(
+ AbpApplicationCreationOptions applicationCreationOptions)
+ {
+ ApplicationCreationOptions = applicationCreationOptions;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
index ddcd839e3d..28984ce5d0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
@@ -5,22 +5,21 @@ using Volo.Abp.AspNetCore.Components.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.UI;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+[DependsOn(
+ typeof(AbpUiModule),
+ typeof(AbpAspNetCoreComponentsModule)
+ )]
+public class AbpAspNetCoreComponentsWebModule : AbpModule
{
- [DependsOn(
- typeof(AbpUiModule),
- typeof(AbpAspNetCoreComponentsModule)
- )]
- public class AbpAspNetCoreComponentsWebModule : AbpModule
+ public override void PreConfigureServices(ServiceConfigurationContext context)
{
- public override void PreConfigureServices(ServiceConfigurationContext context)
- {
- }
+ }
- public override void ConfigureServices(ServiceConfigurationContext context)
- {
- context.Services.Replace(ServiceDescriptor.Transient());
- }
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ context.Services.Replace(ServiceDescriptor.Transient());
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorClientHttpMessageHandler.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorClientHttpMessageHandler.cs
index 450481a646..eb8bee99bd 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorClientHttpMessageHandler.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorClientHttpMessageHandler.cs
@@ -9,90 +9,89 @@ using Microsoft.JSInterop;
using Volo.Abp.AspNetCore.Components.Progression;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+public class AbpBlazorClientHttpMessageHandler : DelegatingHandler, ITransientDependency
{
- public class AbpBlazorClientHttpMessageHandler : DelegatingHandler, ITransientDependency
- {
- private readonly IJSRuntime _jsRuntime;
+ private readonly IJSRuntime _jsRuntime;
- private readonly ICookieService _cookieService;
+ private readonly ICookieService _cookieService;
- private readonly NavigationManager _navigationManager;
+ private readonly NavigationManager _navigationManager;
- private readonly IUiPageProgressService _uiPageProgressService;
+ private readonly IUiPageProgressService _uiPageProgressService;
- private const string AntiForgeryCookieName = "XSRF-TOKEN";
+ private const string AntiForgeryCookieName = "XSRF-TOKEN";
- private const string AntiForgeryHeaderName = "RequestVerificationToken";
+ private const string AntiForgeryHeaderName = "RequestVerificationToken";
- public AbpBlazorClientHttpMessageHandler(
- IJSRuntime jsRuntime,
- ICookieService cookieService,
- NavigationManager navigationManager,
- IClientScopeServiceProviderAccessor clientScopeServiceProviderAccessor)
- {
- _jsRuntime = jsRuntime;
- _cookieService = cookieService;
- _navigationManager = navigationManager;
- _uiPageProgressService = clientScopeServiceProviderAccessor.ServiceProvider.GetRequiredService();
- }
+ public AbpBlazorClientHttpMessageHandler(
+ IJSRuntime jsRuntime,
+ ICookieService cookieService,
+ NavigationManager navigationManager,
+ IClientScopeServiceProviderAccessor clientScopeServiceProviderAccessor)
+ {
+ _jsRuntime = jsRuntime;
+ _cookieService = cookieService;
+ _navigationManager = navigationManager;
+ _uiPageProgressService = clientScopeServiceProviderAccessor.ServiceProvider.GetRequiredService();
+ }
- protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ try
{
- try
+ await _uiPageProgressService.Go(null, options =>
{
- await _uiPageProgressService.Go(null, options =>
- {
- options.Type = UiPageProgressType.Info;
- });
+ options.Type = UiPageProgressType.Info;
+ });
- await SetLanguageAsync(request, cancellationToken);
- await SetAntiForgeryTokenAsync(request);
+ await SetLanguageAsync(request, cancellationToken);
+ await SetAntiForgeryTokenAsync(request);
- return await base.SendAsync(request, cancellationToken);
- }
- finally
- {
- await _uiPageProgressService.Go(-1);
- }
+ return await base.SendAsync(request, cancellationToken);
}
-
- private async Task SetLanguageAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ finally
{
- var selectedLanguage = await _jsRuntime.InvokeAsync(
- "localStorage.getItem",
- cancellationToken,
- "Abp.SelectedLanguage"
- );
+ await _uiPageProgressService.Go(-1);
+ }
+ }
- if (!selectedLanguage.IsNullOrWhiteSpace())
- {
- request.Headers.AcceptLanguage.Clear();
- request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(selectedLanguage));
- }
+ private async Task SetLanguageAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ var selectedLanguage = await _jsRuntime.InvokeAsync(
+ "localStorage.getItem",
+ cancellationToken,
+ "Abp.SelectedLanguage"
+ );
+
+ if (!selectedLanguage.IsNullOrWhiteSpace())
+ {
+ request.Headers.AcceptLanguage.Clear();
+ request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(selectedLanguage));
}
+ }
- private async Task SetAntiForgeryTokenAsync(HttpRequestMessage request)
+ private async Task SetAntiForgeryTokenAsync(HttpRequestMessage request)
+ {
+ if (request.Method == HttpMethod.Get || request.Method == HttpMethod.Head ||
+ request.Method == HttpMethod.Trace || request.Method == HttpMethod.Options)
{
- if (request.Method == HttpMethod.Get || request.Method == HttpMethod.Head ||
- request.Method == HttpMethod.Trace || request.Method == HttpMethod.Options)
- {
- return;
- }
+ return;
+ }
- var selfUri = new Uri(_navigationManager.Uri);
+ var selfUri = new Uri(_navigationManager.Uri);
- if (request.RequestUri.Host != selfUri.Host || request.RequestUri.Port != selfUri.Port)
- {
- return;
- }
+ if (request.RequestUri.Host != selfUri.Host || request.RequestUri.Port != selfUri.Port)
+ {
+ return;
+ }
- var token = await _cookieService.GetAsync(AntiForgeryCookieName);
+ var token = await _cookieService.GetAsync(AntiForgeryCookieName);
- if (!token.IsNullOrWhiteSpace())
- {
- request.Headers.Add(AntiForgeryHeaderName, token);
- }
+ if (!token.IsNullOrWhiteSpace())
+ {
+ request.Headers.Add(AntiForgeryHeaderName, token);
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs
index 5b5a838e17..52efbc6d11 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs
@@ -3,46 +3,45 @@ using System.Linq;
using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+public class AbpBlazorMessageLocalizerHelper
{
- public class AbpBlazorMessageLocalizerHelper
+ private readonly IStringLocalizer stringLocalizer;
+
+ public AbpBlazorMessageLocalizerHelper(IStringLocalizer stringLocalizer)
{
- private readonly IStringLocalizer stringLocalizer;
+ this.stringLocalizer = stringLocalizer;
+ }
- public AbpBlazorMessageLocalizerHelper(IStringLocalizer stringLocalizer)
+ public string Localize(string message, [CanBeNull] IEnumerable arguments)
+ {
+ try
{
- this.stringLocalizer = stringLocalizer;
+ return arguments?.Count() > 0
+ ? stringLocalizer[message, LocalizeMessageArguments(arguments)?.ToArray()]
+ : stringLocalizer[message];
}
-
- public string Localize(string message, [CanBeNull] IEnumerable arguments)
+ catch
{
- try
- {
- return arguments?.Count() > 0
- ? stringLocalizer[message, LocalizeMessageArguments(arguments)?.ToArray()]
- : stringLocalizer[message];
- }
- catch
- {
- return stringLocalizer[message];
- }
+ return stringLocalizer[message];
}
+ }
- private IEnumerable LocalizeMessageArguments(IEnumerable arguments)
+ private IEnumerable LocalizeMessageArguments(IEnumerable arguments)
+ {
+ foreach (var argument in arguments)
{
- foreach (var argument in arguments)
- {
- // first try to localize with "DisplayName:{Name}"
- var localization = stringLocalizer[$"DisplayName:{argument}"];
+ // first try to localize with "DisplayName:{Name}"
+ var localization = stringLocalizer[$"DisplayName:{argument}"];
- if (localization.ResourceNotFound)
- {
- // then try to localize with just "{Name}"
- localization = stringLocalizer[argument];
- }
-
- yield return localization;
+ if (localization.ResourceNotFound)
+ {
+ // then try to localize with just "{Name}"
+ localization = stringLocalizer[argument];
}
+
+ yield return localization;
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpUtilsService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpUtilsService.cs
index b80e927154..082dd7c32f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpUtilsService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpUtilsService.cs
@@ -2,50 +2,49 @@
using Microsoft.JSInterop;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+public class AbpUtilsService : IAbpUtilsService, ITransientDependency
{
- public class AbpUtilsService : IAbpUtilsService, ITransientDependency
- {
- protected IJSRuntime JsRuntime { get; }
-
- public AbpUtilsService(IJSRuntime jsRuntime)
- {
- JsRuntime = jsRuntime;
- }
-
- public ValueTask AddClassToTagAsync(string tagName, string className)
- {
- return JsRuntime.InvokeVoidAsync("abp.utils.addClassToTag", tagName, className);
- }
-
- public ValueTask RemoveClassFromTagAsync(string tagName, string className)
- {
- return JsRuntime.InvokeVoidAsync("abp.utils.removeClassFromTag", tagName, className);
- }
-
- public ValueTask HasClassOnTagAsync(string tagName, string className)
- {
- return JsRuntime.InvokeAsync("abp.utils.hasClassOnTag", tagName, className);
- }
-
- public ValueTask ReplaceLinkHrefByIdAsync(string linkId, string hrefValue)
- {
- return JsRuntime.InvokeVoidAsync("abp.utils.replaceLinkHrefById", linkId, hrefValue);
- }
-
- public ValueTask ToggleFullscreenAsync()
- {
- return JsRuntime.InvokeVoidAsync("abp.utils.toggleFullscreen");
- }
-
- public ValueTask RequestFullscreenAsync()
- {
- return JsRuntime.InvokeVoidAsync("abp.utils.requestFullscreen");
- }
-
- public ValueTask ExitFullscreenAsync()
- {
- return JsRuntime.InvokeVoidAsync("abp.utils.exitFullscreen");
- }
+ protected IJSRuntime JsRuntime { get; }
+
+ public AbpUtilsService(IJSRuntime jsRuntime)
+ {
+ JsRuntime = jsRuntime;
+ }
+
+ public ValueTask AddClassToTagAsync(string tagName, string className)
+ {
+ return JsRuntime.InvokeVoidAsync("abp.utils.addClassToTag", tagName, className);
+ }
+
+ public ValueTask RemoveClassFromTagAsync(string tagName, string className)
+ {
+ return JsRuntime.InvokeVoidAsync("abp.utils.removeClassFromTag", tagName, className);
+ }
+
+ public ValueTask HasClassOnTagAsync(string tagName, string className)
+ {
+ return JsRuntime.InvokeAsync("abp.utils.hasClassOnTag", tagName, className);
+ }
+
+ public ValueTask ReplaceLinkHrefByIdAsync(string linkId, string hrefValue)
+ {
+ return JsRuntime.InvokeVoidAsync("abp.utils.replaceLinkHrefById", linkId, hrefValue);
+ }
+
+ public ValueTask ToggleFullscreenAsync()
+ {
+ return JsRuntime.InvokeVoidAsync("abp.utils.toggleFullscreen");
+ }
+
+ public ValueTask RequestFullscreenAsync()
+ {
+ return JsRuntime.InvokeVoidAsync("abp.utils.requestFullscreen");
+ }
+
+ public ValueTask ExitFullscreenAsync()
+ {
+ return JsRuntime.InvokeVoidAsync("abp.utils.exitFullscreen");
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Alerts/AlertManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Alerts/AlertManager.cs
index aef46b97dd..218e3cbdea 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Alerts/AlertManager.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Alerts/AlertManager.cs
@@ -1,15 +1,14 @@
using Volo.Abp.AspNetCore.Components.Alerts;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.Alerts
+namespace Volo.Abp.AspNetCore.Components.Web.Alerts;
+
+public class AlertManager : IAlertManager, IScopedDependency
{
- public class AlertManager : IAlertManager, IScopedDependency
- {
- public AlertList Alerts { get; }
+ public AlertList Alerts { get; }
- public AlertManager()
- {
- Alerts = new AlertList();
- }
+ public AlertManager()
+ {
+ Alerts = new AlertList();
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/ICurrentApplicationConfigurationCacheResetService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/ICurrentApplicationConfigurationCacheResetService.cs
index b1da30825d..c3e33a9e41 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/ICurrentApplicationConfigurationCacheResetService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/ICurrentApplicationConfigurationCacheResetService.cs
@@ -1,9 +1,8 @@
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Configuration
+namespace Volo.Abp.AspNetCore.Components.Web.Configuration;
+
+public interface ICurrentApplicationConfigurationCacheResetService
{
- public interface ICurrentApplicationConfigurationCacheResetService
- {
- Task ResetAsync();
- }
-}
\ No newline at end of file
+ Task ResetAsync();
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/NullCurrentApplicationConfigurationCacheResetService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/NullCurrentApplicationConfigurationCacheResetService.cs
index 6eeb0e9471..bb91d70775 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/NullCurrentApplicationConfigurationCacheResetService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/NullCurrentApplicationConfigurationCacheResetService.cs
@@ -1,13 +1,12 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.Configuration
+namespace Volo.Abp.AspNetCore.Components.Web.Configuration;
+
+public class NullCurrentApplicationConfigurationCacheResetService : ICurrentApplicationConfigurationCacheResetService, ISingletonDependency
{
- public class NullCurrentApplicationConfigurationCacheResetService : ICurrentApplicationConfigurationCacheResetService, ISingletonDependency
+ public Task ResetAsync()
{
- public Task ResetAsync()
- {
- return Task.CompletedTask;
- }
+ return Task.CompletedTask;
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieOptions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieOptions.cs
index 2781d9ead3..283f665642 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieOptions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieOptions.cs
@@ -1,11 +1,10 @@
using System;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+public class CookieOptions
{
- public class CookieOptions
- {
- public DateTimeOffset? ExpireDate { get; set; }
- public string Path { get; set; }
- public bool Secure { get; set; }
- }
-}
\ No newline at end of file
+ public DateTimeOffset? ExpireDate { get; set; }
+ public string Path { get; set; }
+ public bool Secure { get; set; }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieService.cs
index ed682261a3..1b61acb459 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/CookieService.cs
@@ -2,31 +2,30 @@
using Microsoft.JSInterop;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+[Dependency(ReplaceServices = true)]
+public class CookieService : ICookieService, ITransientDependency
{
- [Dependency(ReplaceServices = true)]
- public class CookieService : ICookieService, ITransientDependency
- {
- public IJSRuntime JsRuntime { get; }
+ public IJSRuntime JsRuntime { get; }
- public CookieService(IJSRuntime jsRuntime)
- {
- JsRuntime = jsRuntime;
- }
+ public CookieService(IJSRuntime jsRuntime)
+ {
+ JsRuntime = jsRuntime;
+ }
- public async ValueTask SetAsync(string key, string value, CookieOptions options)
- {
- await JsRuntime.InvokeVoidAsync("abp.utils.setCookieValue", key, value, options?.ExpireDate?.ToString("r"), options?.Path, options?.Secure);
- }
+ public async ValueTask SetAsync(string key, string value, CookieOptions options)
+ {
+ await JsRuntime.InvokeVoidAsync("abp.utils.setCookieValue", key, value, options?.ExpireDate?.ToString("r"), options?.Path, options?.Secure);
+ }
- public async ValueTask GetAsync(string key)
- {
- return await JsRuntime.InvokeAsync("abp.utils.getCookieValue", key);
- }
+ public async ValueTask GetAsync(string key)
+ {
+ return await JsRuntime.InvokeAsync("abp.utils.getCookieValue", key);
+ }
- public async ValueTask DeleteAsync(string key, string path = null)
- {
- await JsRuntime.InvokeVoidAsync("abp.utils.deleteCookie", key);
- }
+ public async ValueTask DeleteAsync(string key, string path = null)
+ {
+ await JsRuntime.InvokeVoidAsync("abp.utils.deleteCookie", key);
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DefaultServerUrlProvider.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DefaultServerUrlProvider.cs
index 629a19d9f5..281ee3cd73 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DefaultServerUrlProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DefaultServerUrlProvider.cs
@@ -1,13 +1,12 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web
+namespace Volo.Abp.AspNetCore.Components.Web;
+
+public class DefaultServerUrlProvider : IServerUrlProvider, ISingletonDependency
{
- public class DefaultServerUrlProvider : IServerUrlProvider, ISingletonDependency
+ public Task GetBaseUrlAsync(string remoteServiceName = null)
{
- public Task GetBaseUrlAsync(string remoteServiceName = null)
- {
- return Task.FromResult("/");
- }
+ return Task.FromResult("/");
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DependencyInjection/ComponentsClientScopeServiceProviderAccessor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DependencyInjection/ComponentsClientScopeServiceProviderAccessor.cs
index 5ced9d658e..f5e07865a7 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DependencyInjection/ComponentsClientScopeServiceProviderAccessor.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/DependencyInjection/ComponentsClientScopeServiceProviderAccessor.cs
@@ -1,12 +1,11 @@
using System;
using Volo.Abp.DependencyInjection;
-namespace Volo.Abp.AspNetCore.Components.Web.DependencyInjection
+namespace Volo.Abp.AspNetCore.Components.Web.DependencyInjection;
+
+public class ComponentsClientScopeServiceProviderAccessor :
+ IClientScopeServiceProviderAccessor,
+ ISingletonDependency
{
- public class ComponentsClientScopeServiceProviderAccessor :
- IClientScopeServiceProviderAccessor,
- ISingletonDependency
- {
- public IServiceProvider ServiceProvider { get; set; }
- }
+ public IServiceProvider ServiceProvider { get; set; }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLogger.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLogger.cs
index 755947a481..cf66f107a0 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLogger.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLogger.cs
@@ -3,64 +3,63 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.AspNetCore.Components.ExceptionHandling;
-namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling
+namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling;
+
+public class AbpExceptionHandlingLogger : ILogger
{
- public class AbpExceptionHandlingLogger : ILogger
+ private readonly IServiceCollection _serviceCollection;
+ private IUserExceptionInformer _userExceptionInformer;
+
+ public AbpExceptionHandlingLogger(IServiceCollection serviceCollection)
{
- private readonly IServiceCollection _serviceCollection;
- private IUserExceptionInformer _userExceptionInformer;
+ _serviceCollection = serviceCollection;
+ }
- public AbpExceptionHandlingLogger(IServiceCollection serviceCollection)
+ public virtual void Log(
+ LogLevel logLevel,
+ EventId eventId,
+ TState state,
+ Exception exception,
+ Func formatter)
+ {
+ if (exception == null)
{
- _serviceCollection = serviceCollection;
+ return;
}
- public virtual void Log(
- LogLevel logLevel,
- EventId eventId,
- TState state,
- Exception exception,
- Func formatter)
+ if (logLevel != LogLevel.Critical && logLevel != LogLevel.Error)
{
- if (exception == null)
- {
- return;
- }
-
- if (logLevel != LogLevel.Critical && logLevel != LogLevel.Error)
- {
- return;
- }
-
- TryInitialize();
-
- if (_userExceptionInformer == null)
- {
- return;
- }
-
- _userExceptionInformer.Inform(new UserExceptionInformerContext(exception));
+ return;
}
- protected virtual void TryInitialize()
- {
- var serviceProvider = _serviceCollection.GetServiceProviderOrNull();
- if (serviceProvider == null)
- {
- return;
- }
-
- _userExceptionInformer = serviceProvider.GetRequiredService();
- }
+ TryInitialize();
- public virtual bool IsEnabled(LogLevel logLevel)
+ if (_userExceptionInformer == null)
{
- return logLevel == LogLevel.Critical || logLevel == LogLevel.Error;
+ return;
}
- public virtual IDisposable BeginScope(TState state)
+ _userExceptionInformer.Inform(new UserExceptionInformerContext(exception));
+ }
+
+ protected virtual void TryInitialize()
+ {
+ var serviceProvider = _serviceCollection.GetServiceProviderOrNull();
+ if (serviceProvider == null)
{
- return NullDisposable.Instance;
+ return;
}
+
+ _userExceptionInformer = serviceProvider.GetRequiredService();
+ }
+
+ public virtual bool IsEnabled(LogLevel logLevel)
+ {
+ return logLevel == LogLevel.Critical || logLevel == LogLevel.Error;
+ }
+
+ public virtual IDisposable BeginScope(TState state)
+ {
+ return NullDisposable.Instance;
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLoggerProvider.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLoggerProvider.cs
index 85b16d08ba..3f895502fa 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLoggerProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/AbpExceptionHandlingLoggerProvider.cs
@@ -1,38 +1,37 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling
+namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling;
+
+public class AbpExceptionHandlingLoggerProvider : ILoggerProvider
{
- public class AbpExceptionHandlingLoggerProvider : ILoggerProvider
- {
- private AbpExceptionHandlingLogger _logger;
- private static readonly object SyncObj = new object();
- private readonly IServiceCollection _serviceCollection;
+ private AbpExceptionHandlingLogger _logger;
+ private static readonly object SyncObj = new object();
+ private readonly IServiceCollection _serviceCollection;
- public AbpExceptionHandlingLoggerProvider(IServiceCollection serviceCollection)
- {
- _serviceCollection = serviceCollection;
- }
+ public AbpExceptionHandlingLoggerProvider(IServiceCollection serviceCollection)
+ {
+ _serviceCollection = serviceCollection;
+ }
- public ILogger CreateLogger(string categoryName)
+ public ILogger CreateLogger(string categoryName)
+ {
+ if (_logger == null)
{
- if (_logger == null)
+ lock (SyncObj)
{
- lock (SyncObj)
+ if (_logger == null)
{
- if (_logger == null)
- {
- _logger = new AbpExceptionHandlingLogger(_serviceCollection);
- }
+ _logger = new AbpExceptionHandlingLogger(_serviceCollection);
}
}
-
- return _logger;
}
- public void Dispose()
- {
+ return _logger;
+ }
+
+ public void Dispose()
+ {
- }
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs
index ecbeb16e81..0f0da11bdf 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/ExceptionHandling/UserExceptionInformer.cs
@@ -9,65 +9,64 @@ using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
-namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling
+namespace Volo.Abp.AspNetCore.Components.Web.ExceptionHandling;
+
+[Dependency(ReplaceServices = true)]
+public class UserExceptionInformer : IUserExceptionInformer, IScopedDependency
{
- [Dependency(ReplaceServices = true)]
- public class UserExceptionInformer : IUserExceptionInformer, IScopedDependency
+ public ILogger Logger { get; set; }
+ protected IUiMessageService MessageService { get; }
+ protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
+
+ protected AbpExceptionHandlingOptions Options { get; }
+
+ public UserExceptionInformer(
+ IUiMessageService messageService,
+ IExceptionToErrorInfoConverter exceptionToErrorInfoConverter,
+ IOptions options)
+ {
+ MessageService = messageService;
+ ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
+ Options = options.Value;
+ Logger = NullLogger.Instance;
+ }
+
+ public void Inform(UserExceptionInformerContext context)
{
- public ILogger Logger { get; set; }
- protected IUiMessageService MessageService { get; }
- protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
+ //TODO: Create sync versions of the MessageService APIs.
- protected AbpExceptionHandlingOptions Options { get; }
+ var errorInfo = GetErrorInfo(context);
- public UserExceptionInformer(
- IUiMessageService messageService,
- IExceptionToErrorInfoConverter exceptionToErrorInfoConverter,
- IOptions options)
+ if (errorInfo.Details.IsNullOrEmpty())
{
- MessageService = messageService;
- ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
- Options = options.Value;
- Logger = NullLogger.Instance;
+ MessageService.Error(errorInfo.Message);
}
-
- public void Inform(UserExceptionInformerContext context)
+ else
{
- //TODO: Create sync versions of the MessageService APIs.
+ MessageService.Error(errorInfo.Details, errorInfo.Message);
+ }
+ }
- var errorInfo = GetErrorInfo(context);
+ public async Task InformAsync(UserExceptionInformerContext context)
+ {
+ var errorInfo = GetErrorInfo(context);
- if (errorInfo.Details.IsNullOrEmpty())
- {
- MessageService.Error(errorInfo.Message);
- }
- else
- {
- MessageService.Error(errorInfo.Details, errorInfo.Message);
- }
+ if (errorInfo.Details.IsNullOrEmpty())
+ {
+ await MessageService.Error(errorInfo.Message);
}
-
- public async Task InformAsync(UserExceptionInformerContext context)
+ else
{
- var errorInfo = GetErrorInfo(context);
-
- if (errorInfo.Details.IsNullOrEmpty())
- {
- await MessageService.Error(errorInfo.Message);
- }
- else
- {
- await MessageService.Error(errorInfo.Details, errorInfo.Message);
- }
+ await MessageService.Error(errorInfo.Details, errorInfo.Message);
}
+ }
- protected virtual RemoteServiceErrorInfo GetErrorInfo(UserExceptionInformerContext context)
+ protected virtual RemoteServiceErrorInfo GetErrorInfo(UserExceptionInformerContext context)
+ {
+ return ExceptionToErrorInfoConverter.Convert(context.Exception, options =>
{
- return ExceptionToErrorInfoConverter.Convert(context.Exception, options =>
- {
- options.SendExceptionsDetailsToClients = Options.SendExceptionsDetailsToClients;
- options.SendStackTraceToClients = Options.SendStackTraceToClients;
- });
- }
+ options.SendExceptionsDetailsToClients = Options.SendExceptionsDetailsToClients;
+ options.SendStackTraceToClients = Options.SendStackTraceToClients;
+ });
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs
index 61bea5c27a..2f800c7257 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs
@@ -1,20 +1,19 @@
using System;
using System.Threading.Tasks;
-namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions
+namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
+
+public class EntityAction : IEquatable
{
- public class EntityAction : IEquatable
+ public string Text { get; set; }
+ public Func