Browse Source

Merge branch 'dev' into auto-merge/rel-5-0/729

pull/11007/head
maliming 4 years ago
parent
commit
2ced498334
No known key found for this signature in database GPG Key ID: 96224957E51C89E
  1. 137
      .editorconfig
  2. 2
      .gitignore
  3. 6
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json
  4. 7
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  5. 6
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json
  6. 6
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json
  7. 14
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  8. 6
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
  9. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json
  10. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de-DE.json
  11. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
  12. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  13. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json
  14. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json
  15. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json
  16. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json
  17. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json
  18. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json
  19. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
  20. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json
  21. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
  22. 18
      docs/en/Blog-Posts/2021-11-18 v5_0_Preview/POST.md
  23. BIN
      docs/en/Blog-Posts/2021-11-18 v5_0_Preview/community-talks.png
  24. BIN
      docs/en/Blog-Posts/2021-11-18 v5_0_Preview/cover-50.png
  25. 47
      docs/en/Blog-Posts/2021-12-15 v5_0_Release_Stable/POST.md
  26. BIN
      docs/en/Blog-Posts/2021-12-15 v5_0_Release_Stable/community-talks.png
  27. 17
      docs/en/Community-Articles/2021-06-17-Using-Elsa-Workflow-with-ABP-Framework/POST.md
  28. 1671
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md
  29. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-contracts-folder-structure.png
  30. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-final-demo.gif
  31. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-folder-structure.png
  32. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-create.gif
  33. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-creation-modal.png
  34. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-update-modal.png
  35. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/demo.png
  36. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-file-structure.png
  37. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-shared-file-structure.png
  38. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/er-diagram.png
  39. BIN
      docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/web-folder-structure.png
  40. 2
      docs/en/Customizing-Application-Modules-Extending-Entities.md
  41. 2
      docs/en/Getting-Started-Running-Solution.md
  42. 2
      docs/en/Getting-Started.md
  43. 2
      docs/en/Virtual-File-System.md
  44. 1
      docs/zh-Hans/Background-Workers.md
  45. 98
      docs/zh-Hans/Getting-Started-AspNetCore-Application.md
  46. 73
      docs/zh-Hans/Getting-Started-Create-Solution.md
  47. 199
      docs/zh-Hans/Getting-Started-Running-Solution.md
  48. 53
      docs/zh-Hans/Getting-Started-Setup-Environment.md
  49. 370
      docs/zh-Hans/Getting-Started.md
  50. 18
      docs/zh-Hans/docs-nav.json
  51. 11
      framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/AbpApiVersioningAbstractionsModule.cs
  52. 9
      framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/IRequestedApiVersion.cs
  53. 19
      framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo/Abp/ApiVersioning/NullRequestedApiVersion.cs
  54. 25
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
  55. 9
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs
  56. 85
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Microsoft/AspNetCore/Authentication/OAuth/Claims/AbpClaimActionCollectionExtensions.cs
  57. 9
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/AbpAspNetCoreAuthenticationOAuthModule.cs
  58. 71
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs
  59. 41
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/RemoveDuplicateClaimAction.cs
  60. 81
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
  61. 13
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo/Abp/AspNetCore/Authentication/OpenIdConnect/AbpAspNetCoreAuthenticationOpenIdConnectModule.cs
  62. 53
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/AbpAspNetCoreComponentsServerThemingModule.cs
  63. 21
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalBundles.cs
  64. 13
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalScriptContributor.cs
  65. 25
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorGlobalStyleContributor.cs
  66. 76
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
  67. 37
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Configuration/BlazorServerCurrentApplicationConfigurationCacheResetService.cs
  68. 119
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
  69. 19
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/AbpAspNetCoreComponentsWebThemingModule.cs
  70. 95
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
  71. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
  72. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
  73. 15
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
  74. 25
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
  75. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
  76. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
  77. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
  78. 97
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
  79. 33
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
  80. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
  81. 39
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
  82. 63
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
  83. 17
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
  84. 11
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/RouterAssemblyList.cs
  85. 17
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/AbpToolbarOptions.cs
  86. 27
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarConfigurationContext.cs
  87. 11
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarContributor.cs
  88. 9
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/IToolbarManager.cs
  89. 11
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/StandardToolbars.cs
  90. 19
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/Toolbar.cs
  91. 65
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarConfigurationContext.cs
  92. 30
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarItem.cs
  93. 43
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Toolbars/ToolbarManager.cs
  94. 17
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreApplicationCreationOptions.cs
  95. 25
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
  96. 123
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorClientHttpMessageHandler.cs
  97. 57
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs
  98. 87
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpUtilsService.cs
  99. 17
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Alerts/AlertManager.cs
  100. 11
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Configuration/ICurrentApplicationConfigurationCacheResetService.cs

137
.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

2
.gitignore

@ -6,7 +6,7 @@
*.user
*.userosscache
*.sln.docstates
*.editorconfig
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

6
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!"
}
}

7
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -352,6 +352,11 @@
"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!",
"PaymentRequestId": "Payment Request Id"
}
}

6
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!"
}
}

6
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json

@ -102,6 +102,10 @@
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>.",
"FreeDDDEBook": "Free DDD E-Book",
"CommercialNewsletterConfirmationMessage": "I agree to the <a href=\"https://commercial.abp.io/TermsConditions\">Terms & Conditions</a> and <a href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>."
"CommercialNewsletterConfirmationMessage": "I agree to the <a href=\"https://commercial.abp.io/TermsConditions\">Terms & Conditions</a> and <a href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"RemoveCurrentUserFromOrganizationWarningMessage": "You are removing yourself from your own organization. You will no longer be able to manage this organization, do you confirm?",
"RenewExistingOrganizationOrCreateNewOneMessage": "You can renew the license of your organization(s) by clicking the below \"Extend Now\" button(s) and thus you can extend the license expiry date by 1 year. If you continue to checkout, you will have a new organization. Do you want to continue with a new organization?",
"ExtendNow": "Extend Now",
"ContinueWithNewOrganization": "Continue with a new organization"
}
}

14
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": "<strong>Extending:</strong> 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.<hr/><strong>Upgrading:</strong> By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the <a href=\"/pricing\">license comparison table</a> to check the differences between the license plans.<strong>On the other hand, when you upgrade, your license expiry date will not change!</strong>To extend your license end date, you need to extend your license.",
"LicenseExtendUpgradeDiffExplanation": "<strong>Extending:</strong> 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. <hr/><strong>Upgrading:</strong> By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the <a href=\"/pricing\">license comparison table</a> to check the differences between the license plans.<strong>On the other hand, when you upgrade, your license expiry date will not change!</strong>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, <a href='{4}' target='_blank'>log into your account</a> to review the available renewal pricing.",
"HowDoIRenewMyLicense": "How do I renew my license?",
@ -390,6 +390,16 @@
"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 <a href=\"https://commercial.abp.io/TermsConditions\">Terms & Conditions</a> and <a href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>."
"CommercialNewsletterConfirmationMessage": "I agree to the <a href=\"https://commercial.abp.io/TermsConditions\">Terms & Conditions</a> and <a href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"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 <username> -o <organization> `.",
"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.",
"UserOwnerDescription": "The 'Owner' of the organization is the admin of this account. He/she manages the organization by purchasing licenses, allocating developers. An 'Owner' cannot write code in the ABP Commercial projects, cannot download the ABP sample projects, or cannot ask questions on the support website. If you want to do all these, you have to add yourself as a developer too.",
"UserDeveloperDescription": "The 'Developers' can write code in the ABP Commercial projects, download the ABP sample projects, or ask questions on the support website. On the other hand, the 'Developers' cannot manage this organization.",
"RemoveCurrentUserFromOrganizationWarningMessage": "You are removing yourself from your own organization. You will no longer be able to manage this organization, do you confirm?",
"RenewExistingOrganizationOrCreateNewOneMessage": "You can renew the license of your organization(s) by clicking the below \"Extend Now\" button(s) and thus you can extend the license expiry date by 1 year. If you continue to checkout, you will have a new organization. Do you want to continue with a new organization?",
"ExtendNow": "Extend Now",
"ContinueWithNewOrganization": "Continue with a new organization"
}
}

6
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json

@ -390,6 +390,10 @@
"TrialLicenseExpireMessage": "Deneme lisansını kullanıyorsunuz ve deneme lisansınızın süresi {0} tarihinde sona erecek.",
"TryForFree": "Ücretsiz deneyin",
"TrialLicenseExpiredInfo": "Deneme lisansınızın süresi doldu!",
"CommercialNewsletterConfirmationMessage": "<a href=\"https://commercial.abp.io/TermsConditions\">Şartlar, Koşullar</a> ve <a href=\"https://commercial.abp.io/Privacy\">Gizlilik politikasını</a> kabul ediyorum."
"CommercialNewsletterConfirmationMessage": "<a href=\"https://commercial.abp.io/TermsConditions\">Şartlar, Koşullar</a> ve <a href=\"https://commercial.abp.io/Privacy\">Gizlilik politikasını</a> kabul ediyorum.",
"RemoveCurrentUserFromOrganizationWarningMessage": "Organizasyondan kendinizi kaldırıyorsunuz. Artık bu organizasyonu yönetemeyeceksiniz, onaylıyor musunuz? ",
"RenewExistingOrganizationOrCreateNewOneMessage": "Aşağıdaki \"Şimdi Uzat\" buton(lar)una tıklayarak organizasyon(lar)ınızın lisansını yenileyebilir ve böylece lisans geçerlilik süresini 1 yıl uzatabilirsiniz. Ödemeye devam ederseniz, yeni bir organizasyonunuz olacak. Yeni bir organizasyonla devam etmek istiyor musunuz? ",
"ExtendNow": "Şimdi Uzat",
"ContinueWithNewOrganization": "Yeni bir organizasyon ile devam et"
}
}

3
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": "شاهد المزيد"
}
}

3
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"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json

@ -101,6 +101,7 @@
"ArticleRequestMessageTitle": "<a href=\"https://github.com/abpframework/abp/issues/new\">Open an issue</a> 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"
}
}
}

3
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"
}
}

3
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"
}
}

3
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ää"
}
}

3
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"
}
}

3
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": "और देखें"
}
}

3
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"
}
}

3
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"
}
}

3
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"
}
}

3
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"
}
}

3
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": "查看更多"
}
}

18
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
![community-talks](community-talks.png)
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).

BIN
docs/en/Blog-Posts/2021-11-18 v5_0_Preview/community-talks.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 KiB

BIN
docs/en/Blog-Posts/2021-11-18 v5_0_Preview/cover-50.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

47
docs/en/Blog-Posts/2021-12-15 v5_0_Release_Stable/POST.md

@ -0,0 +1,47 @@
# ABP.IO Platform 5.0 Final Has Been Released!
[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 5.0 versions have been released today.
## What's new with 5.0?
Since all the new features are already explained in details with the [5.0 RC.1 Announcement Post](https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released), I will not repeat all the details again. See the [RC Blog Post](https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released) for all the features and enhancements.
## Getting started with 5.0
### Creating new solutions
You can create a new solution with the ABP Framework version 5.0 by either using the `abp new` command or using the **direct download** tab on the [get started page](https://abp.io/get-started).
Type the following command in a command-line terminal to install the ABP CLI version 5.0:
````bash
dotnet tool install -g Volo.Abp.Cli --version 5.0.0
````
To upgrade your existing ABP CLI installation:
````bash
dotnet tool update -g Volo.Abp.Cli --version 5.0.0
````
Then you can create a new solution using the `abp new` command:
````bash
abp new Acme.BookStore
````
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for details.
### Upgrading existing solutions
Check [the migration guide](https://docs.abp.io/en/abp/latest/Migration-Guides/Abp-5_0) for the applications with the version 4.x upgrading to the version 5.0. Also see [the upgrading guide](https://docs.abp.io/en/abp/latest/Upgrading) to understand how to update existing solutions.
## ABP Community Talks 2021.12
![community-talks](community-talks.png)
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**
See you in the event!

BIN
docs/en/Blog-Posts/2021-12-15 v5_0_Release_Stable/community-talks.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 KiB

17
docs/en/Community-Articles/2021-06-17-Using-Elsa-Workflow-with-ABP-Framework/POST.md

@ -241,8 +241,9 @@ private void ConfigureElsa(ServiceConfigurationContext context, IConfiguration c
.WithExposedHeaders("Content-Disposition"))
);
//register controllers inside elsa
context.Services.AddAssemblyOf<Elsa.Server.Api.Endpoints.WorkflowRegistry.Get>();
//Uncomment the below line if your abp version is lower than v4.4 to register controllers of Elsa .
//See https://github.com/abpframework/abp/pull/9299 (we will no longer need to specify this line of code from v4.4)
// context.Services.AddAssemblyOf<Elsa.Server.Api.Endpoints.WorkflowRegistry.Get>();
//Disable antiforgery validation for elsa
Configure<AbpAntiForgeryOptions>(options =>
@ -269,11 +270,7 @@ public override void OnApplicationInitialization(ApplicationInitializationContex
}
```
* In here we've specified the Elsa Server Api's assembly by using the `AddAssemblyOf<>` extension method to register the required services (controllers). These services required for the dashboard (if we create a workflow by using **Elsa Workflow Designer** it calls some services under the hook, therefore we need to be assured about these services get registered).
* With [v4.4](https://github.com/abpframework/abp/pull/9299), we will no longer need to specify this line of code.
> **Note:** `AddAssemblyOf<>` extension method can help you to register all your services by convention. You can check [here](https://docs.abp.io/en/abp/latest/Dependency-Injection#conventional-registration) for more information about conventional registration.
* These services required for the dashboard.
* We don't need to register our workflows one by one anymore. Because now we use `.AddWorkflowsFrom<Startup>()`, and this registers workflows on our behalf.
@ -371,12 +368,14 @@ namespace ElsaDemo.Permissions
<link rel="icon" type="image/png" sizes="32x32" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/favicon-16x16.png">
<link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/fonts/inter/inter.css">
<link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/styles/tailwind.css">
<link rel="stylesheet" href="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/elsa-workflows-studio.css">
<script src="/_content/Elsa.Designer.Components.Web/monaco-editor/min/vs/loader.js"></script>
<script type="module" src="/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/elsa-workflows-studio.esm.js"></script>
</head>
<body class="h-screen" style="background-size: 30px 30px; background-image: url(/_content/Elsa.Designer.Components.Web/elsa-workflows-studio/assets/images/tile.png); background-color: #FBFBFB;">
<elsa-studio-root server-url="@serverUrl" monaco-lib-path="_content/Elsa.Designer.Components.Web/monaco-editor/min"></elsa-studio-root>
<elsa-studio-root server-url="@serverUrl" monaco-lib-path="_content/Elsa.Designer.Components.Web/monaco-editor/min">
<elsa-studio-dashboard></elsa-studio-dashboard>
</elsa-studio-root>
</body>
</html>
```

1671
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md

File diff suppressed because it is too large

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-contracts-folder-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-final-demo.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/application-folder-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-create.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-creation-modal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/book-update-modal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/demo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-file-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/domain-shared-file-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/er-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/web-folder-structure.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

2
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;

2
docs/en/Getting-Started-Running-Solution.md

@ -139,7 +139,7 @@ Ensure that the `.IdentityServer` project is the startup project. Run the applic
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.
You can login, but you cannot enter to the main application here. This is just the authentication server.
You can login, but you cannot enter to the main application here. This is **just the authentication server**.
Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a Swagger UI:

2
docs/en/Getting-Started.md

@ -15,6 +15,6 @@
This tutorial explains how to **create and run** a new web application using the ABP Framework. Follow the steps below;
1. [Setup your development environment](Getting-Started-Setup-Environment)
1. [Setup your development environment](Getting-Started-Setup-Environment.md)
2. [Creating a new solution](Getting-Started-Create-Solution.md)
3. [Running the solution](Getting-Started-Running-Solution.md)

2
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

1
docs/zh-Hans/Background-Workers.md

@ -2,7 +2,6 @@
## 介绍
背景工人在应用简单独立的线程在后台运行.一般来说,他们定期运行,以执行一些任务.例子;
后台工作者在应用程序后台运行的简单的独立线程,一般来说它们定期运行执行一些任务.例如;
* 后台工作者可以定期**删除过时的日志**.

98
docs/zh-Hans/Getting-Started-AspNetCore-Application.md

@ -1,12 +1,12 @@
# 在AspNet Core MVC Web Application中使用ABP
# 在ASP.NET Core MVC Web 应用程序中使用ABP
本教程将介绍如何开始以最少的依赖关系开始使用ABP开发.
本教程将介绍如何开始以最少的依赖关系开始使用ABP开发.
通常情况下你需要下载一个 **[启动模板](Getting-Started-AspNetCore-MVC-Template.md)**
通常情况下你希望从 **[启动模板](Getting-Started-AspNetCore-MVC-Template.md)** 开始.
## 创建一个新项目
1. 使用Visual Studio 2019 (16.4.0+)创建一个新的AspNet Core Web Application:
1. 使用Visual Studio 2022 (17.0.0+)创建一个新的ASP.NET Core Web应用程序:
![](images/create-new-aspnet-core-application-v2.png)
@ -21,7 +21,7 @@
## 安装 Volo.Abp.AspNetCore.Mvc 包
Volo.Abp.AspNetCore.Mvc是ABP集成AspNet Core MVC的包,请安装它到你项目中:
Volo.Abp.AspNetCore.Mvc是ABP集成ASP.NET Core MVC的包,请安装它到你项目中:
````
Install-Package Volo.Abp.AspNetCore.Mvc
@ -29,7 +29,7 @@ Install-Package Volo.Abp.AspNetCore.Mvc
## 创建ABP模块
ABP是一个模块化框架,它需要一个**启动 (根) 模块**继承自``AbpModule``:
ABP是一个模块化框架,它需要一个**启动(根)模块**继承自 `AbpModule`:
````C#
using Microsoft.AspNetCore.Builder;
@ -43,21 +43,20 @@ namespace BasicAspNetCoreApplication
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(
ApplicationInitializationContext context)
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
// Configure the HTTP request pipeline.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseConfiguredEndpoints();
@ -68,49 +67,44 @@ namespace BasicAspNetCoreApplication
``AppModule`` 是应用程序启动模块的好名称.
ABP的包定义了这个模块类,模块可以依赖其它模块.在上面的代码中 ``AppModule`` 依赖于 ``AbpAspNetCoreMvcModule`` (模块存在于[Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)包中). 安装新的ABP的包后添加``DependsOn``是很常见的做法.
ABP的包定义了模块类,模块可以依赖其它模块.在上面的代码中 ``AppModule`` 依赖于 ``AbpAspNetCoreMvcModule`` (由[Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)包定义). 安装新的ABP的包后添加``DependsOn``特性是很常见的做法.
我们在此模块类中配置ASP.NET Core管道,而不是Startup类中.
### 启动类
接下来修改启动类集成ABP模块系统:
接下来修改启动类集成ABP模块系统:
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using BasicAspNetCoreApplication;
namespace BasicAspNetCoreApplication
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
}
var builder = WebApplication.CreateBuilder(args);
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}
builder.Services.ReplaceConfiguration(builder.Configuration);
builder.Services.AddApplication<AppModule>();
var app = builder.Build();
app.InitializeApplication();
app.Run();
````
``services.AddApplication<AppModule>()``添加了所有``AppModule``模块中定义的全部服务.
``Configure``方法中的``app.InitializeApplication()``完成初始化并启动应用程序.
``services.AddApplication<AppModule>()``添加了从``AppModule``中启动的所有模块中定义的所有服务.
``app.InitializeApplication()`` 初始化并启动应用程序.
## 运行应用程序!
启动该应用它将按预期运行.
启动该应用,它将按预期运行.
## 使用 Autofac 依赖注入框架
虽然AspNet Core的依赖注入(DI)系统适用于基本要求,但[Autofac](https://autofac.org/)提供了属性注入和方法拦截等高级功能,这些功能是ABP执行高级应用程序框架功能所必需的.
虽然ASP.NET Core的依赖注入(DI)系统适用于基本要求,但[Autofac](https://autofac.org/)提供了属性注入和方法拦截等高级功能,这些功能是ABP执行高级应用程序框架功能所必需的.
用Autofac取代AspNet Core的DI系统并集成到ABP非常简单.
用Autofac取代ASP.NET Core的DI系统并集成到ABP非常简单.
1. 安装 [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) 包
@ -132,27 +126,21 @@ public class AppModule : AbpModule
3. 修改``Program.cs``以使用Autofac:
````C#
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using BasicAspNetCoreApplication;
namespace BasicAspNetCoreApplication
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
var builder = WebApplication.CreateBuilder(args);
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac(); // 添加这一行
}
}
builder.Host.UseAutofac(); //Add this line
builder.Services.ReplaceConfiguration(builder.Configuration);
builder.Services.AddApplication<AppModule>();
var app = builder.Build();
app.InitializeApplication();
app.Run();
````
## 源码

73
docs/zh-Hans/Getting-Started-Create-Solution.md

@ -0,0 +1,73 @@
# 入门教程
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
> 本文档假设你更喜欢使用 **{{ UI_Value }}** 作为 UI 框架, 使用 **{{ DB_Value }}** 作为数据库提供程序. 对于其他选项, 请更改本文档顶部的首选项.
## 创建新项目
我们将使用 ABP CLI 创建一个新的 ABP 项目.
> 或者, 你可以使用[ABP Framework 网站](https://abp.io/get-started)页面上的选项轻松的 **创建并下载** 项目.
使用 ABP CLI 的 `new` 命令创建一个新项目:
````shell
abp new Acme.BookStore{{if UI == "NG"}} -u angular{{else if UI == "Blazor"}} -u blazor{{else if UI == "BlazorServer"}} -u blazor-server{{end}}{{if DB == "Mongo"}} -d mongodb{{end}}{{if Tiered == "Yes"}}{{if UI == "MVC" || UI == "BlazorServer"}} --tiered{{else}} --separate-identity-server{{end}}{{end}}
````
*你可以使用不同级别的命名空间, 例如: BookStore、Acme.BookStore或 Acme.Retail.BookStore.*
{{ if Tiered == "Yes" }}
{{ if UI == "MVC" || UI == "BlazorServer" }}
* `--tified` 参数用于创建认证服务器、 UI 和 API 实际分隔的 N-层解决方案.
{{ else }}
* `--separate-identity-server` 参数用于将Identity Server应用程序与API主机应用程序分隔开. 如果未指定, 则服务器上将只有一个端点.
{{ end }}
{{ end }}
> [ABP CLI 文档](./CLI.md) 涵盖了所有可用的命令和选项.
## 移动端开发
如果你想要在你的解决方案中包含 [React Native](https://reactnative.dev/) 项目, 将 `-m react-native` (or `--mobile react-native`) 参数添加到项目创建命令. 这是一个基础的 React Native 启动模板, 用于开发基于你的 ABP 后端的移动应用程序.
请参阅 [React Native 入门](Getting-Started-React-Native.md) 文档, 了解如何配置和运行 React Native 应用程序.
### 解决方案结构
该解决方案具有分层结构 (基于 [域驱动设计](Domain-Driven-Design.md)), 并包含单元 & 集成测试项目. 请参阅 [应用程序模板文档](Startup-Templates/Application.md) 以详细了解解决方案结构.
{{ if DB == "Mongo" }}
#### MongoDB 事务
[启动模板](Startup-templates/Index.md) 默认在`.MongoDB`项目中**禁用**事务. 如果你的MongoDB服务器支持事务, 你可以在*YourProjectMongoDbModule*类中的`ConfigureServices`方法开启它:
```csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto;
});
```
> 或者你可以删除该代码, 因为 `Auto` 已经是默认行为.
{{ end }}
## 下一步
* [运行解决方案](Getting-Started-Running-Solution.md)

199
docs/zh-Hans/Getting-Started-Running-Solution.md

@ -0,0 +1,199 @@
# 入门教程
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
> 本文档假设你更喜欢使用 **{{ UI_Value }}** 作为 UI 框架, 使用 **{{ DB_Value }}** 作为数据库提供程序. 对于其他选项, 请更改本文档顶部的首选项.
## 创建数据库
### 连接字符串
检查在 {{if Tiered == "Yes"}}`.IdentityServer` 和`.HttpApi.Host` 项目{{else}}{{if UI=="MVC"}}`.Web` 项目{{else if UI=="BlazorServer"}}`.Blazor` 项目{{else}}`.HttpApi.Host` 项目{{end}}{{end}} 中 `appsettings.json` 文件里的**连接字符串**.
{{ if DB == "EF" }}
````json
"ConnectionStrings": {
"Default": "Server=(LocalDb)\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True"
}
````
> **关于连接字符串和数据库管理系统**
>
> 解决方案配置为默认使用 **Entity Framework Core****MS SQL Server**. 但是, 如果在执行ABP CLI 的`new`命令时使用了`-dbms`参数来选择其他DBMS (如`-dbms MySQL`), 那么连接字符串可能不同.
>
> EF Core 支持 [多种](https://docs.microsoft.com/en-us/ef/core/providers/) 据库提供程序, 因此你可以使用任何受支持的DBMS. 你可以需要时候参阅[Entity Framework 集成文档](Entity-Framework-Core.md) 来学习如何[切换到另一个DBMS](Entity-Framework-Core-Other-DBMS.md).
### 数据库迁移
该解决方案使用[Entity Framework Core Code First 迁移](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli). 带有 `.DbMigrator` 的控制台程序用于 **应用迁移****初始化种子数据**. 它在**开发**和**生产**环境中都很有用.
> `.dbMigator` 项目有自己的 `appsettings.json`. 因此, 如果你更改了之前的连接字符串, 那么也应该更改这个连接字符串.
### 初次迁移
`.dbMigator` 应用程序在首次运行时自动**创建初始迁移**.
**如果你使用的是 Visual Studio, 你可以跳到 *运行 dbMigrator* 部分.** 但是, 其他 IDE (例如 Rider) 在首次运行时可能会遇到问题, 因为它会添加初始迁移并编译项目. 在这种情况下, 请在 `.dbMigration` 项目的文件夹中打开命令行终端, 然后运行以下命令:
````bash
dotnet run
````
下次, 你可以像往常一样在 IDE 中运行它.
### 运行迁移
右键单击 `.dbMigration` 项目, 然后选择 **设置为启动项目**
![set-as-startup-project](images/set-as-startup-project.png)
按F5(或Ctrl + F5) 运行应用程序. 它将具有如下所示的输出:
![db-migrator-output](images/db-migrator-output.png)
> 初始的[种子数据](Data-Seeding.md)在数据库中创建了 `admin` 用户(密码为`1q2w3E*`) 用于登录应用程序. 所以, 对于新数据库至少使用 `.DbMigrator` 一次.
{{ else if DB == "Mongo" }}
````json
"ConnectionStrings": {
"Default": "mongodb://localhost:27017/BookStore"
}
````
该解决方案配置为在本地计算机中使用 **MongoDB**, 因此你需要启动并运行 MongoDB 服务器实例, 或者将连接字符串更改为另一台 MongoDB 服务器.
### 种子初始数据
该解决方案带有 `.DbMigrator` 的控制台程序用于 **初始化种子数据**. 它在**开发**和**生产**环境中都很有用.
> `.dbMigator` 项目有自己的 `appsettings.json`. 因此, 如果你更改了之前的连接字符串, 那么也应该更改这个连接字符串.
右键单击 `.dbMigration` 项目, 然后选择 **设置为启动项目**
![set-as-startup-project](images/set-as-startup-project.png)
按F5(或Ctrl + F5) 运行应用程序. 它将具有如下所示的输出:
![db-migrator-output](images/db-migrator-output.png)
> 初始的[种子数据](Data-Seeding.md)在数据库中创建了 `admin` 用户(密码为`1q2w3E*`) 用于登录应用程序. 所以, 对于新数据库至少使用 `.DbMigrator` 一次.
{{ end }}
## 运行应用程序
{{ if UI == "MVC" || UI == "BlazorServer" }}
{{ if Tiered == "Yes" }}
> 分层解决方案使用 **Redis** 作为分布式缓存. 确保它已安装并在本地计算机上运行. 如果你使用的是远程 Redis 服务器, 请修改项目的 ` appsettings.json` 文件中的配置.
1. 确保 `.IdentityServer` 项目是启动项目. 运行此应用程序, 它将在浏览器中打开 **登录** 页面.
> 在 Visual Studio 中使用 Ctrl+F5(而不是F5) 在不进行调试的情况下运行应用程序. 如果你没有调试目的, 这会更快.
你可以登录, 但不能在这里进入主应用程序. 这 **只是身份验证服务器**.
2. 确保 `.httpapi.Host` 项目是启动项目, 然后运行应用将在浏览器中打开 **Swagger UI**.
![swagger-ui](images/swagger-ui.png)
这是 Web 应用程序使用的 HTTP API.
3. 最后, 确保 {{if UI=="MVC"}}`.Web`{{else}}`.Blazor`{{end}} 项目是启动项目,然后运行应用程序,它将在浏览器中打开 **欢迎** 页面
![mvc-tiered-app-home](images/bookstore-home.png)
单击 **login** 按钮, 它将重定向到 *身份验证服务器* 以登录到应用程序:
![bookstore-login](images/bookstore-login.png)
{{ else # Tiered != "Yes" }}
确保 {{if UI=="MVC"}}`.Web`{{else}}`.Blazor`{{end}} 项目是启动项目. 运行应用程序将会在浏览器中打开 **login** 页面:
> 在 Visual Studio 中使用 Ctrl+F5(而不是F5) 在不进行调试的情况下运行应用程序. 如果你没有调试目的, 这会更快.
![bookstore-login](images/bookstore-login.png)
{{ end # Tiered }}
{{ else # UI != MVC || BlazorServer }}
### 运行 HTTP API 主机(服务器端)
{{ if Tiered == "Yes" }}
> 分层解决方案使用 Redis 作为分布式缓存. 确保它已安装并在本地计算机上运行. 如果你使用的是远程 Redis 服务器, 请修改项目的 `appsettings.json` 文件中的配置.
确保 `.IdentityServer` 项目是启动项目. 运行此应用程序, 它将在浏览器中打开 **登录** 页面.
> 在 Visual Studio 中使用 Ctrl+F5(而不是F5) 在不进行调试的情况下运行应用程序. 如果你没有调试目的, 这会更快.
你可以登录, 但不能在这里进入主应用程序. 这 **只是身份验证服务器**.
确保 `.HttpApi.Host` 项目是启动项目, 然后运行应用程序将打开 Swagger UI 的:
{{ else # Tiered == "No" }}
确保 `.HttpApi.Host` 项目是启动项目, 然后运行应用程序将打开 Swagger UI 的:
> 在 Visual Studio 中使用 Ctrl+F5(而不是F5) 在不进行调试的情况下运行应用程序. 如果你没有调试目的, 这会更快.
{{ end # Tiered }}
![swagger-ui](images/swagger-ui.png)
你可以在这里查看应用程序的API并测试它们. 获取Swagger UI的[更多信息](https://swagger.io/tools/swagger-ui/).
{{ end # UI }}
{{ if UI == "Blazor" }}
### 运行 Blazor 应用程序 (客户端)
确保 `.Blazor` 项目是启动项目并运行应用程序.
> 在 Visual Studio 中使用 Ctrl+F5(而不是F5) 在不进行调试的情况下运行应用程序. 如果你没有调试目的, 这会更快.
应用程序启动后, 单击页头上的 **Login** 链接, 你将重定向到身份验证服务器以输入用户名和密码:
![bookstore-login](images/bookstore-login.png)
{{ else if UI == "NG" }}
### 运行 Angular 应用程序 (客户端)
转到 `Angular` 文件夹, 打开命令行终端, 键入 `yarn` 命令(我们建议使用 [yarn](https://yarnpkg.com/) 软件包管理器, 而 `npm install` 也可以使用)
```bash
yarn
```
当所有node模块加载完毕后, 执行 `yarn start` (或 `npm start`) 命令:
```bash
yarn start
```
初次构建可能需要更长的时间. 完成后, 它会在默认浏览器中使用 [localhost:4200](http://localhost:4200/) 地址打开 Angular UI.
![bookstore-login](images/bookstore-login.png)
{{ end }}
输入用户名 **admin** 和 密码 **1q2w3E*** 登录应用程序. 应用程序已启动并正在运行. 你可以根据此启动模板开始开发应用程序.
## 另请参见
* [Web 应用程序开发教程](Tutorials/Part-1.md)
* [应用程序启动模板](Startup-Templates/Application.md)

53
docs/zh-Hans/Getting-Started-Setup-Environment.md

@ -0,0 +1,53 @@
# 入门教程
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
> 本文档假设你更喜欢使用 **{{ UI_Value }}** 作为 UI 框架, 使用 **{{ DB_Value }}** 作为数据库提供程序. 对于其他选项, 请更改本文档顶部的首选项.
## 设置你的开发环境
第一件事! 在创建项目之前, 让我们先设置你的开发环境.
### 先决条件
开发计算机上应安装以下工具:
* 一个集成开发环境 (比如: [Visual Studio](https://visualstudio.microsoft.com/vs/)) 它需要支持 [.NET 6.0+](https://dotnet.microsoft.com/download/dotnet) 的开发.
{{ if UI != "Blazor" }}
* [Node v12 或 v14](https://nodejs.org/)
* [Yarn v1.20+ (不是v2)](https://classic.yarnpkg.com/en/docs/install) <sup id="a-yarn">[1](#f-yarn)</sup> 或 npm v6+ (已跟随Node一起安装)
{{ end }}
{{ if Tiered == "Yes" }}
* [Redis](https://redis.io/) (启动解决方案使用 Redis 作为 [分布式缓存](Caching.md)).
{{ end }}
{{ if UI != "Blazor" }}
<sup id="f-yarn"><b>1</b></sup> _Yarn v2 工作方式不同, 不被支持._ <sup>[↩](#a-yarn)</sup>
{{ end }}
### 安装 ABP CLI
[ABP CLI](./CLI.md) 是一个命令行界面, 用于自动执行基于 ABP 的解决方案的一些常见任务. 首先, 你需要使用以下命令安装 ABP CLI:
````shell
dotnet tool install -g Volo.Abp.Cli
````
如果已安装, 则可以使用以下命令对其进行更新:
````shell
dotnet tool update -g Volo.Abp.Cli
````
## 下一步
* [创建新的解决方案](Getting-Started-Create-Solution.md)

370
docs/zh-Hans/Getting-Started.md

@ -1,374 +1,20 @@
## 入门
# 入门教程
````json
//[doc-params]
{
"UI": ["MVC","NG"],
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
本教程介绍了如何创建一个新的{{if UI == "MVC"}} ASP.NET Core MVC web {{else if UI == "NG"}} Angular {{end}}. 配置并运行它.
> 本文档假设你更喜欢使用 **{{ UI_Value }}** 作为 UI 框架, 使用 **{{ DB_Value }}** 作为数据库提供程序. 对于其他选项, 请更改本文档顶部的首选项.
## 设置你的开发环境
## 内容
创建第一个项目之前,需要正确的设置你的开发环境.
本教程介绍如何使用 ABP 框架 **创建和运行** 新的 Web 应用程序. 请按照以下步骤操作;
### 预先要求
你需要安装以下工具:
* [Visual Studio 2019 (v16.4+)](https://visualstudio.microsoft.com/vs/) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).<sup id="a-editor">[1](#f-editor)</sup>
* [.NET Core 3.1+](https://www.microsoft.com/net/download/dotnet-core/)
* [Node v12 或 v14](https://nodejs.org/en/)
* [Yarn v1.19+](https://classic.yarnpkg.com/)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <sup id="a-yarn">[2](#f-yarn)</sup> 或 npm v6+ (与Node一起安装)
{{ if Tiered == "Yes" }}
* [Redis](https://redis.io/): 入门解决方案将Redis用作[分布式缓存](Caching.md). 因此你需要安装并运行Redis.
{{ end }}
<sup id="f-editor"><b>1</b></sup> _只要支持.NET Core和ASP.NET Core,就可以使用其他编辑器代替Visual Studio._ <sup>[↩](#a-editor)</sup>
<sup id="f-yarn"><b>2</b></sup> _Yarn v2 的工作方式不同,不受支持._ <sup>[↩](#a-yarn)</sup>
### 安装ABP CLI
[ABP CLI](./CLI.md)是一个命令行页面,用于自动执行一些基于ABP的应用程序的常见任务.
> ABP CLI是ABP框架一个免费开源的工具.
你需要使用以下命令安排ABP CLI:
````shell
dotnet tool install -g Volo.Abp.Cli
````
如果你已经安装,你可以使用以下命令更新到最新版本:
````shell
dotnet tool update -g Volo.Abp.Cli
````
## 创建新项目
> 本文假设你使用 **{{ UI_Value }}** 做为UI框架 **{{ DB_Value }}** 做为数据库提供程序,对于其它选项,你可以更改文档顶部的首选项.
### 使用ABP CLI创建一个新项目
使用ABP CLI的 `new` 命令创建新项目:
````shell
abp new Acme.BookStore{{if UI == "NG"}} -u angular {{end}}{{if DB == "Mongo"}} -d mongodb{{end}}{{if Tiered == "Yes" && UI != "NG"}} --tiered {{else if Tiered == "Yes" && UI == "NG"}}--separate-identity-server{{end}} --mobile react-native
````
* 此命令还会在解决方案文件夹内创建一个React Native移动应用程序. 如果你不想要它,可以安全地删除它或从`abp new`命令中删除`--mobile react-native`选项, 以使其完全不包含在解决方案中.
{{ if UI == "NG" }}
* `-u` 指定UI框架, 本例中是 `angular`.
{{ if Tiered == "Yes" }}
* `--separate-identity-server` 参数用于将Identity服务器应用程序与API主机应用程序分隔开. 如果未指定,则服务器上将只有一个端点.
{{ end }}
{{ end }}
{{ if DB == "Mongo" }}
* `-d` 指定数据库提供程序, 本例中是 `mongodb`.
{{ end }}
{{ if Tiered == "Yes" && UI != "NG" }}
* `--tiered` 参数用于创建n层解决方案,其中身份验证服务器层,UI层和API层在物理上是分离的.
{{ end }}
> 你可以使用不同级别的命令空间; 例如. BookStore, Acme.BookStore or Acme.Retail.BookStore.
#### ABP CLI 命令 & 选项
[ABP CLI文档](./CLI.md)涵盖了ABP CLI的所有可用命令和选项. 本文档使用[应用程序启动模板](Startup-Templates/Application.md)创建新的Web应用程序. 有关其他模板,请参见[ABP启动模板](Startup-Templates/Index.md)文档.
> 或者,您可以从[ABP Framework网站](https://abp.io/get-started)中选择"直接下载"选项卡创建新的解决方案.
## 解决方案结构
{{ if UI == "MVC" }}
创建项目后你会有以下解决方案目录和文件:
![](images/solution-files-mvc.png)
在Visual Studio中打开 `.sln` 文件时,将看到以下解决方案结构:
{{if DB == "Mongo"}}
![vs-default-app-solution-structure](images/vs-app-solution-structure-mongodb.png)
{{else}}
![vs-default-app-solution-structure](images/vs-app-solution-structure{{if Tiered == "Yes"}}-tiered{{end}}.png)
{{end}}
{{ else if UI == "NG" }}
在创建的解决方案中有三个文件夹:
![](images/solution-files-non-mvc.png)
* `angular` 文件夹包含Angular UI应用程序.
* `aspnet-core` 文件夹包含后端应用程序.
* `react-native` 文件夹包含React Native UI 应用程序.
打开 `aspnet-core` 文件夹下的 `.sln`(`Visual Studio`解决方案)文件:
![vs-angular-app-backend-solution-structure](images/vs-spa-app-backend-structure{{if DB == "Mongo"}}-mongodb{{end}}.png)
{{ end }}
> ###### 关于解决方案中的项目
>
> 根据你的**UI**,**数据库**和其他选项,你的解决方案的结构可能略有不同.
该解决方案具有分层结构(基于[Domain Driven Design](Domain-Driven-Design.md)), 并包含配置好的的单元&集成测试项目.
{{ if DB == "EF" }}
集成测试项目已配置为可与 **EF Core** & **SQLite 内存** database同时使用.
{{ else if DB == "Mongo" }}
集成测试项目已配置为每个测试创建的内存中的**MongoDB**数据库(使用的[Mongo2Go](https://github.com/Mongo2Go/Mongo2Go)库).
{{ end }}
> 请参阅[应用程序模板文档](Startup-Templates/Application.md)详细了解解决方案结构.
{{ if DB == "Mongo" }}
> [启动模板](Startup-templates/Index.md)默认在 `.MongoDB` 项目中**禁用**了工作单元事务. 如果你的MongoDB服务器支持事务,你可以手动启用工作单元的事务:
```csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Enabled;
});
```
{{ end }}
## 创建数据库
### 连接字符串
检查 {{if UI == "MVC"}}{{if Tiered == "Yes"}}`.IdentityServer` 和 `.HttpApi.Host` 项目{{else}}`.Web` 项目{{end}}{{else if UI == "NG" }}`.HttpApi.Host` 项目{{end}}下 `appsettings.json` 文件中的 **链接字符串**:
{{ if DB == "EF" }}
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
````
该解决方案配置为**Entity Framework Core**与**MS SQL Server**一起使用. EF Core支持[各种](https://docs.microsoft.com/en-us/ef/core/providers/)数据库提供程序,因此你可以使用任何受支持的DBMS. 请参阅[Entity Framework集成文档](https://docs.abp.io/en/abp/latest/Entity-Framework-Core)了解如何切换到另一个DBMS.
### 数据库连接字符串
查看`.Web`项目下`appsettings.json`文件中的 **连接字符串**:
````json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
}
````
解决方案使用 **Entity Framework Core****MS SQL Server**. EF Core支持[各种](https://docs.microsoft.com/zh-cn/ef/core/providers/)数据库提供程序,因此你可以根据实际需要使用其他DBMS. 如果需要,请更改连接字符串.
### 应用迁移
该解决方案使用[Entity Framework Core Code First 迁移](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli). 你需要应用迁移来创建数据库,有两种方法迁移数据库.
#### 使用DbMigrator应用程序应用迁移
该解决方案包含一个控制台应用程序(在此示例中名为`Acme.BookStore.DbMigrator`),可以创建数据库,应用迁移和初始化数据. 它对开发和生产环境都很有用.
> `.DbMigrator`项目有自己的`appsettings.json`. 因此,如果你更改了上面的连接字符串,则还应更改此字符串.
右键单击`.DbMigrator`项目并选择 **设置为启动项目**:
![set-as-startup-project](images/set-as-startup-project.png)
按F5(或Ctrl + F5)运行应用程序. 它将具有如下所示的输出:
![set-as-startup-project](images/db-migrator-app.png)
#### 使用EF Core Update-Database命令
Ef Core具有`Update-Database`命令, 可根据需要创建数据库并应用挂起的迁移. 右键单击`.Web`项目并选择**设置为启动项目**:
{{ if UI == "MVC" }}
右键单击{{if Tiered == "Yes"}}`.IdentityServer`{{else}}`.Web`{{end}}项目并选择**设置为启动项目**:
{{ else if UI != "MVC" }}
右键单击`.HttpApi.Host`项目并选择**设置为启动项目**:
{{ end }}
![set-as-startup-project](images/set-as-startup-project.png)
打开**包管理器控制台(Package Manager Console)**, 选择`.EntityFrameworkCore.DbMigrations`项目作为**默认项目**并运行`Update-Database`命令:
![package-manager-console-update-database](images/package-manager-console-update-database.png)
这将基于配置的连接字符串创建新数据库.
> **使用`.DbMigrator`工具是建议的方法**, 因为它能初始化初始数据能够正确运行Web应用程序.
>
> 如果你只是使用 `Update-Database` 命令,你会得到一个空数据库,所以你无法登录到应用程序因为数据库中没有初始管理用户. 不需要种子数据库时,可以在开发期间使用 `Update-Database` 命令. 但是使用 `.DbMigrator` 应用程序会更简单,你始终可以使用它来迁移模式并为数据库添加种子.
{{ else if DB == "Mongo" }}
````json
"ConnectionStrings": {
"Default": "mongodb://localhost:27017/BookStore"
}
````
该解决方案被配置为在你的本地计算机中使用 **MongoDB**,因此你需要启动并运行一个MongoDB服务器实例或者将连接字符串更改为另一个MongoDB服务器.
### 初始化种子数据
该解决方案附带一个 `.DbMigrator` 控制台应用程序,该应用程序为初始数据提供了种子. 它对于开发以及生产环境都很有用.
> `.DbMigrator` 项目有自己的 `appsettings.json`.如果你更改了其他项目的 `appsettings.json`,也应该更改这个.
右键点击 `.DbMigrator` 并选择 **设置为启动项目**.
![set-as-startup-project](images/set-as-startup-project.png)
按F5(或Ctrl+F5)启动应用程序,你会看到以下输出:
![db-migrator-output](images/db-migrator-output.png)
> 数据库创建后会初始化[种子数据](Data-Seeding.md), 其中包含用于登录的 `admin` 用户. 所以你至少使用 `.DbMigrator` 一次.
{{ end }}
### 运行应用程序
{{ if UI == "MVC" }}
{{ if Tiered == "Yes" }}
确保 `.IdentityServer` 是启动项目,运行应用程序后会在你的浏览器打开一个 **login** 页面.
> 在Visual Studio中使用Ctrl+F5(而不是F5)运行应用,如果你不用于调试,这会减少启动时间.
你可以登录,但是不能在这里进入主应用程序,它仅是验证服务器.
确保 `.HttpApi.Host` 是启动项目,运行应用程序后会在你的浏览器打开一个 **Swagger UI** 页面.
![swagger-ui](images/swagger-ui.png)
这里是Web应用程序使用的API应用程序.
最后确保 `.Web` 是启动项目,运行应用程序后会在你的浏览器打开一个 **welcome** 页面.
![mvc-tiered-app-home](images/bookstore-home.png)
点击 **login** 按钮重定向到 `Identity Server` 来登录应用程序.
![bookstore-login](images/bookstore-login.png)
{{ else }}
最后确保 `.Web` 是启动项目,运行应用程序后会在你的浏览器打开一个 **login** 页面.
> 在Visual Studio中使用Ctrl+F5(而不是F5)运行应用,如果你不用于调试,这会减少启动时间.
![bookstore-login](images/bookstore-login.png)
{{ end }}
{{ else if UI != "MVC" }}
#### 运行HTTP API Host (服务器端)
{{ if Tiered == "Yes" }}
确保 `.IdentityServer` 是启动项目,运行应用程序后会在你的浏览器打开一个 **login** 页面.
> 在Visual Studio中使用Ctrl+F5(而不是F5)运行应用,如果你不用于调试,这会减少启动时间.
你可以登录,但是不能在这里进入主应用程序,它仅是验证服务器.
{{ end }}
确保 `.HttpApi.Host` 是启动项目,运行应用程序后会在你的浏览器打开一个 **Swagger UI** 页面.
{{ if Tiered == "No" }}
> 在Visual Studio中使用Ctrl+F5(而不是F5)运行应用,如果你不用于调试,这会减少启动时间.
{{ end }}
![swagger-ui](images/swagger-ui.png)
你可以看到应用程序的API并进行测试. 更多信息,请参阅[Swagger UI](https://swagger.io/tools/swagger-ui/).
> ##### Swagger UI 授权
>
> 大多数的HTTP API都需要身份验证和授权. 如果你要测试授权API, 请手动进入 `/Account/Login` 页面, 输入用户名: `admin` 和密码: `1q2w3E*` 登录到应用程序. 然后你可以访问授权API.
{{ end }}
{{ if UI == "NG" }}
#### 运行 Angular 应用程序 (客户端)
`angular` 下打开命令行终端, 输入 `yarn` 命令(我们推荐使用[yarn](https://yarnpkg.com/)包管理, `npm install` 在大多数情况下也可以工作).
```bash
yarn
```
等到所有node模块加载成功, 执行 `yarn start` (或 `npm start`) 命令:
```bash
yarn start
```
等待 `Angular CLI` 使用 `BrowserSync` 启动 `Webpack` dev-server.
它会负责编译你的 `TypeScript`代码, 并自动重新加载浏览器.
完成后 `Angular Live Development Server` 会监听 localhost:4200.
打开你的浏览器并导航到[localhost:4200](http://localhost:4200/).
![bookstore-login](images/bookstore-login.png)
{{ end }}
输入用户名 **admin**,密码 **1q2w3E*** 登录到应用程序,应用程序已经启动并执行,你可以基于此启动模板开始开发应用程序.
#### 移动开发
当你创建一个新的应用程序时. 可以添加`-m react-native`选项以在解决方案中包含 `react-native`项目. 这是一个基础的[React Native](https://reactnative.dev/)启动模板,用于开发与基于ABP的后端集成的移动应用程序.
请参阅"[React Native入门](Getting-Started-React-Native.md)"文档了解如何配置和运行React Native应用程序.
## 下一步是什么?
[Web应用程序开发教程](Tutorials/Part-1.md)
1. [设置你的开发环境](Getting-Started-Setup-Environment.md)
2. [创建新的解决方案](Getting-Started-Create-Solution.md)
3. [运行解决方案](Getting-Started-Running-Solution.md)

18
docs/zh-Hans/docs-nav.json

@ -5,11 +5,25 @@
"path": "Tutorials/Todo/Index.md"
},
{
"text": "入门",
"text": "入门教程",
"items": [
{
"text": "Web应用程序",
"path": "Getting-Started.md"
"path": "Getting-Started.md",
"items": [
{
"text": "1: 设置你的开发环境",
"path": "Getting-Started-Setup-Environment.md"
},
{
"text": "2: 创建新的解决方案",
"path": "Getting-Started-Create-Solution.md"
},
{
"text": "3: 运行解决方案",
"path": "Getting-Started-Running-Solution.md"
}
]
},
{
"text": "控制台应用程序",

11
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<IRequestedApiVersion>(NullRequestedApiVersion.Instance);
}
context.Services.AddSingleton<IRequestedApiVersion>(NullRequestedApiVersion.Instance);
}
}

9
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; }
}

19
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()
{
}
}
}
}

25
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();
});
}
}

9
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
{
}
}

85
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));
}
}

9
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
{
}
}

71
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);
}
}
}
}

41
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)
}
/// <inheritdoc />
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;
}
/// <inheritdoc />
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
var previousValues = new List<string>();
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<string>();
foreach (var claim in claims)
else
{
if (claim.Value.IsIn(previousValues))
{
identity.RemoveClaim(claim);
}
else
{
previousValues.Add(claim.Value);
}
previousValues.Add(claim.Value);
}
}
}
}
}

81
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<OpenIdConnectOptions> configureOptions)
=> builder.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, configureOptions);
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, Action<OpenIdConnectOptions> configureOptions)
=> builder.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, configureOptions);
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, Action<OpenIdConnectOptions> configureOptions)
=> builder.AddAbpOpenIdConnect(authenticationScheme, OpenIdConnectDefaults.DisplayName, configureOptions);
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, Action<OpenIdConnectOptions> configureOptions)
=> builder.AddAbpOpenIdConnect(authenticationScheme, OpenIdConnectDefaults.DisplayName, configureOptions);
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<OpenIdConnectOptions> configureOptions)
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<OpenIdConnectOptions> 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<IOptions<AbpAspNetCoreMultiTenancyOptions>>().Value.TenantKey;
private static void SetAbpTenantId(AuthorizationCodeReceivedContext receivedContext)
{
var tenantKey = receivedContext.HttpContext.RequestServices
.GetRequiredService<IOptions<AbpAspNetCoreMultiTenancyOptions>>().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]);
}
}
}

13
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
{
}
}

53
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<AbpBundlingOptions>(options =>
{
Configure<AbpBundlingOptions>(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));
});
});
}
}
}

21
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";
}
}
}

13
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");
}
}

25
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");
}
}
}

76
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<AbpAspNetCoreUnitOfWorkOptions>(options =>
if (context.Services.GetHostingEnvironment().IsDevelopment())
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
options.DetailedErrors = true;
}
});
context.Services.ExecutePreConfiguredActions(serverSideBlazorBuilder);
Configure<AbpAspNetCoreAuditingOptions>(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
Configure<AbpAspNetCoreUnitOfWorkOptions>(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
Configure<AbpEndpointRouterOptions>(options =>
Configure<AbpAspNetCoreAuditingOptions>(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
Configure<AbpEndpointRouterOptions>(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
);
}
}

37
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()
);
}
}
}

119
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<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
public async Task<string> 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));
}
}
}
}

19
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
{
}
}
}

95
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<RenderFragment> ToolbarItemRenders { get; set; }
public IPageToolbarManager PageToolbarManager { get; set; }
[Parameter]
public string Title { get; set; }
protected List<RenderFragment> 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<BreadcrumbItem> BreadcrumbItems { get; set; }
[Parameter]
public PageToolbar Toolbar { get; set; }
[Parameter]
public bool BreadcrumbShowCurrent { get; set; } = true;
public PageHeader()
{
BreadcrumbItems = new List<BreadcrumbItem>();
ToolbarItemRenders = new List<RenderFragment>();
}
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public List<BreadcrumbItem> BreadcrumbItems { get; set; }
[Parameter]
public PageToolbar Toolbar { get; set; }
public PageHeader()
{
BreadcrumbItems = new List<BreadcrumbItem>();
ToolbarItemRenders = new List<RenderFragment>();
}
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();
}
}

9
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);
}

9
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<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar);
}
Task<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar);
}

15
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();
}
}

25
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();
}
}

9
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);
}

7
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<IPageToolbarContributor>
{
public class PageToolbarContributorList : List<IPageToolbarContributor>
{
}
}

7
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<string, PageToolbar>
{
public class PageToolbarDictionary : Dictionary<string, PageToolbar>
{
}
}

97
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<TComponent>(
this PageToolbar toolbar,
Dictionary<string, object> arguments = null,
int order = 0,
string requiredPolicyName = null)
{
public static PageToolbar AddComponent<TComponent>(
this PageToolbar toolbar,
Dictionary<string, object> 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<string, object> 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<string, object> 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<Task> clicked,
object icon = null,
Color color = Color.Primary,
bool disabled = false,
int order = 0,
string requiredPolicyName = null)
{
toolbar.AddComponent<ToolbarButton>(
new Dictionary<string, object>
{
public static PageToolbar AddButton(
this PageToolbar toolbar,
string text,
Func<Task> clicked,
object icon = null,
Color color = Color.Primary,
bool disabled = false,
int order = 0,
string requiredPolicyName = null)
{
toolbar.AddComponent<ToolbarButton>(
new Dictionary<string, object>
{
{ 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;
}
}

33
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<string, object> Arguments { get; set; }
[CanBeNull]
public Dictionary<string, object> Arguments { get; set; }
public int Order { get; set; }
public int Order { get; set; }
public PageToolbarItem(
[NotNull] Type componentType,
[CanBeNull] Dictionary<string, object> arguments = null,
int order = 0)
{
ComponentType = Check.NotNull(componentType, nameof(componentType));
Arguments = arguments;
Order = order;
}
public PageToolbarItem(
[NotNull] Type componentType,
[CanBeNull] Dictionary<string, object> arguments = null,
int order = 0)
{
ComponentType = Check.NotNull(componentType, nameof(componentType));
Arguments = arguments;
Order = order;
}
}

7
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<PageToolbarItem>
{
public class PageToolbarItemList : List<PageToolbarItem>
{
}
}

39
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<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar)
{
if (toolbar == null || !toolbar.Contributors.Any())
{
ServiceScopeFactory = serviceScopeFactory;
return Array.Empty<PageToolbarItem>();
}
public virtual async Task<PageToolbarItem[]> GetItemsAsync(PageToolbar toolbar)
using (var scope = ServiceScopeFactory.CreateScope())
{
if (toolbar == null || !toolbar.Contributors.Any())
{
return Array.Empty<PageToolbarItem>();
}
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();
}
}
}

63
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<string, object> Arguments { get; set; }
public Dictionary<string, object> Arguments { get; set; }
public int Order { get; }
public int Order { get; }
public string RequiredPolicyName { get; }
public string RequiredPolicyName { get; }
public SimplePageToolbarContributor(
Type componentType,
Dictionary<string, object> arguments = null,
int order = 0,
string requiredPolicyName = null)
{
ComponentType = componentType;
Arguments = arguments;
Order = order;
RequiredPolicyName = requiredPolicyName;
}
public SimplePageToolbarContributor(
Type componentType,
Dictionary<string, object> 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<bool> ShouldAddComponentAsync(PageToolbarContributionContext context)
protected virtual async Task<bool> ShouldAddComponentAsync(PageToolbarContributionContext context)
{
if (RequiredPolicyName != null)
{
if (RequiredPolicyName != null)
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
if (!await authorizationService.IsGrantedAsync(RequiredPolicyName))
{
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
if (!await authorizationService.IsGrantedAsync(RequiredPolicyName))
{
return false;
}
return false;
}
return true;
}
return true;
}
}

17
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();
}
}

11
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<Assembly>
{
public class RouterAssemblyList : List<Assembly>
{
}
}
}

17
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<IToolbarContributor> Contributors { get; }
[NotNull]
public List<IToolbarContributor> Contributors { get; }
public AbpToolbarOptions()
{
Contributors = new List<IToolbarContributor>();
}
public AbpToolbarOptions()
{
Contributors = new List<IToolbarContributor>();
}
}

27
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<bool> IsGrantedAsync(string policyName);
Task<bool> IsGrantedAsync(string policyName);
[CanBeNull]
IStringLocalizer GetDefaultLocalizer();
[CanBeNull]
IStringLocalizer GetDefaultLocalizer();
[NotNull]
public IStringLocalizer GetLocalizer<T>();
[NotNull]
public IStringLocalizer GetLocalizer<T>();
[NotNull]
public IStringLocalizer GetLocalizer(Type resourceType);
}
[NotNull]
public IStringLocalizer GetLocalizer(Type resourceType);
}

11
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);
}
}
Task ConfigureToolbarAsync(IToolbarConfigurationContext context);
}

9
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<Toolbar> GetAsync(string name);
}
Task<Toolbar> GetAsync(string name);
}

11
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";
}
}
public const string Main = "Main";
}

19
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<ToolbarItem> Items { get; }
public List<ToolbarItem> Items { get; }
public Toolbar([NotNull] string name)
{
Name = Check.NotNull(name, nameof(name));
Items = new List<ToolbarItem>();
}
public Toolbar([NotNull] string name)
{
Name = Check.NotNull(name, nameof(name));
Items = new List<ToolbarItem>();
}
}

65
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<IAuthorizationService>();
public IAuthorizationService AuthorizationService => _lazyServiceProvider.LazyGetRequiredService<IAuthorizationService>();
public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>();
public IStringLocalizerFactory StringLocalizerFactory => _lazyServiceProvider.LazyGetRequiredService<IStringLocalizerFactory>();
public Toolbar Toolbar { get; }
public Toolbar Toolbar { get; }
public ToolbarConfigurationContext(Toolbar toolbar, IServiceProvider serviceProvider)
{
Toolbar = toolbar;
ServiceProvider = serviceProvider;
_lazyServiceProvider = ServiceProvider.GetRequiredService<IAbpLazyServiceProvider>();
}
public ToolbarConfigurationContext(Toolbar toolbar, IServiceProvider serviceProvider)
{
Toolbar = toolbar;
ServiceProvider = serviceProvider;
_lazyServiceProvider = ServiceProvider.GetRequiredService<IAbpLazyServiceProvider>();
}
public Task<bool> IsGrantedAsync(string policyName)
{
return AuthorizationService.IsGrantedAsync(policyName);
}
public Task<bool> 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<T>()
{
return StringLocalizerFactory.Create<T>();
}
[NotNull]
public IStringLocalizer GetLocalizer<T>()
{
return StringLocalizerFactory.Create<T>();
}
[NotNull]
public IStringLocalizer GetLocalizer(Type resourceType)
{
return StringLocalizerFactory.Create(resourceType);
}
[NotNull]
public IStringLocalizer GetLocalizer(Type resourceType)
{
return StringLocalizerFactory.Create(resourceType);
}
}

30
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));
}
}
}

43
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<AbpToolbarOptions> options,
IServiceProvider serviceProvider)
{
protected AbpToolbarOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
ServiceProvider = serviceProvider;
Options = options.Value;
}
public ToolbarManager(
IOptions<AbpToolbarOptions> options,
IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
Options = options.Value;
}
public async Task<Toolbar> GetAsync(string name)
{
var toolbar = new Toolbar(name);
public async Task<Toolbar> 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;
}
}

17
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;
}
}

25
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<IComponentActivator, ServiceProviderComponentActivator>());
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(ServiceDescriptor.Transient<IComponentActivator, ServiceProviderComponentActivator>());
}
}

123
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<IUiPageProgressService>();
}
public AbpBlazorClientHttpMessageHandler(
IJSRuntime jsRuntime,
ICookieService cookieService,
NavigationManager navigationManager,
IClientScopeServiceProviderAccessor clientScopeServiceProviderAccessor)
{
_jsRuntime = jsRuntime;
_cookieService = cookieService;
_navigationManager = navigationManager;
_uiPageProgressService = clientScopeServiceProviderAccessor.ServiceProvider.GetRequiredService<IUiPageProgressService>();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
protected override async Task<HttpResponseMessage> 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<string>(
"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<string>(
"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);
}
}
}

57
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<T>
{
public class AbpBlazorMessageLocalizerHelper<T>
private readonly IStringLocalizer<T> stringLocalizer;
public AbpBlazorMessageLocalizerHelper(IStringLocalizer<T> stringLocalizer)
{
private readonly IStringLocalizer<T> stringLocalizer;
this.stringLocalizer = stringLocalizer;
}
public AbpBlazorMessageLocalizerHelper(IStringLocalizer<T> stringLocalizer)
public string Localize(string message, [CanBeNull] IEnumerable<string> arguments)
{
try
{
this.stringLocalizer = stringLocalizer;
return arguments?.Count() > 0
? stringLocalizer[message, LocalizeMessageArguments(arguments)?.ToArray()]
: stringLocalizer[message];
}
public string Localize(string message, [CanBeNull] IEnumerable<string> arguments)
catch
{
try
{
return arguments?.Count() > 0
? stringLocalizer[message, LocalizeMessageArguments(arguments)?.ToArray()]
: stringLocalizer[message];
}
catch
{
return stringLocalizer[message];
}
return stringLocalizer[message];
}
}
private IEnumerable<string> LocalizeMessageArguments(IEnumerable<string> arguments)
private IEnumerable<string> LocalizeMessageArguments(IEnumerable<string> 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;
}
}
}

87
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<bool> HasClassOnTagAsync(string tagName, string className)
{
return JsRuntime.InvokeAsync<bool>("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<bool> HasClassOnTagAsync(string tagName, string className)
{
return JsRuntime.InvokeAsync<bool>("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");
}
}

17
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();
}
}
}

11
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();
}
}
Task ResetAsync();
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save