Browse Source

Merge branch 'dev' into NormalizedName

pull/18426/head
maliming 3 years ago
parent
commit
9328ad7e36
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 4
      Directory.Packages.props
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json
  3. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  4. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json
  5. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/hu.json
  6. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json
  7. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json
  8. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json
  9. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json
  10. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json
  11. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json
  12. 8
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  13. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json
  14. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
  15. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
  16. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
  17. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json
  18. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json
  19. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json
  20. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
  21. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json
  22. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json
  23. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json
  24. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json
  25. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json
  26. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
  27. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json
  28. 12
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
  29. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json
  30. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  31. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
  32. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  33. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json
  34. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/cs.json
  35. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/de.json
  36. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en-GB.json
  37. 26
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  38. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/es.json
  39. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fi.json
  40. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fr.json
  41. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hr.json
  42. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hu.json
  43. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/is.json
  44. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/it.json
  45. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/nl.json
  46. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pl-PL.json
  47. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json
  48. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json
  49. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ru.json
  50. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sk.json
  51. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sl.json
  52. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json
  53. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/vi.json
  54. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  55. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json
  56. 84
      docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/POST.md
  57. BIN
      docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/abp-china-team.jpeg
  58. BIN
      docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/awards.jpeg
  59. BIN
      docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/cover-image.png
  60. 18
      docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md
  61. 10
      docs/en/Entity-Cache.md
  62. 72
      docs/en/Entity-Framework-Core-Oracle-Devart.md
  63. 70
      docs/en/Entity-Framework-Core-Oracle-Official.md
  64. 2
      docs/en/Tutorials/Part-1.md
  65. 14
      docs/en/Tutorials/Part-10.md
  66. 55
      docs/en/Tutorials/Part-4.md
  67. 16
      docs/en/Tutorials/Part-6.md
  68. 52
      docs/en/Tutorials/Part-8.md
  69. 8
      docs/en/Tutorials/Part-9.md
  70. 130
      docs/en/UI/Angular/Authorization.md
  71. 134
      docs/en/UI/Angular/Component-Replacement.md
  72. 2
      docs/en/UI/Common/Utils/Linked-List.md
  73. 2
      docs/zh-Hans/UI/Common/Utils/Linked-List.md
  74. 7
      framework/Volo.Abp.sln
  75. 22
      framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpApiVersioningExtensions.cs
  76. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  77. 5
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  78. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpConventionalApiControllerSpecification.cs
  79. 13
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs
  80. 46
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs
  81. 69
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs
  82. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs
  83. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs
  84. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs
  85. 33
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RemoveUnnecessaryPortsStep.cs
  86. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/Angular/AngularServiceProxyGenerator.cs
  87. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/CSharp/CSharpServiceProxyGenerator.cs
  88. 49
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/CliVersionService.cs
  89. 9
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/IMultiTenantUrlProvider.cs
  90. 78
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantUrlProvider.cs
  91. 1
      framework/src/Volo.Abp.RemoteServices/Volo.Abp.RemoteServices.csproj
  92. 8
      framework/src/Volo.Abp.RemoteServices/Volo/Abp/Http/Client/RemoteServiceConfiguration.cs
  93. 39
      framework/src/Volo.Abp.RemoteServices/Volo/Abp/Http/Client/RemoteServiceConfigurationProvider.cs
  94. 2
      framework/src/Volo.Abp.RemoteServices/Volo/Abp/RemoteServices/AbpRemoteServicesModule.cs
  95. 7
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs
  96. 63
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs
  97. 6
      framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/AbpAspNetCoreMvcVersioningTestModule.cs
  98. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/HelloController.cs
  99. 57
      framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantUrlProivder_Tests.cs
  100. 17
      framework/test/Volo.Abp.RemoteServices.Tests/Volo.Abp.RemoteServices.Tests.csproj

4
Directory.Packages.props

@ -6,11 +6,12 @@
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.24" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
<PackageVersion Include="AsyncKeyedLock" Version="6.2.2" />
<PackageVersion Include="AsyncKeyedLock" Version="6.2.4" />
<PackageVersion Include="Autofac" Version="7.1.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
<PackageVersion Include="AutoMapper" Version="12.0.1" />
<PackageVersion Include="Asp.Versioning.Mvc" Version="7.1.0" />
<PackageVersion Include="AWSSDK.S3" Version="3.7.300.2" />
<PackageVersion Include="AWSSDK.SecurityToken" Version="3.7.300.2" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.17.0" />
@ -60,7 +61,6 @@
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.25" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.0" />

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json

@ -91,7 +91,7 @@
"JoinOurMarketingNewsletter": "انضم إلى النشرة الإخبارية التسويقية",
"CommunityPrivacyPolicyConfirmation": "أوافق على الشروط والأحكام و <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">سياسة الخصوصية</a>.",
"WouldLikeToReceiveNotification": "أرغب في تلقي آخر الأخبار من مواقع abp.io.",
"CommercialNewsletterConfirmationMessage": "أنا أوافق على <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/TermsConditions\">البنود و الظروف</a> و <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">سياسة الخصوصية</a>.",
"CommercialNewsletterConfirmationMessage": "أنا أوافق على <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/TermsConditions\">البنود و الظروف</a> و <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/Privacy\">سياسة الخصوصية</a>.",
"FreeDDDEBook": "كتاب تصميم مقاد بالنطاق DDD إلكتروني مجاني",
"AdditionalServices": "خدمات إضافية",
"Learn": "تعلم",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json

@ -91,7 +91,7 @@
"JoinOurMarketingNewsletter": "Join our marketing newsletter",
"CommunityPrivacyPolicyConfirmation": "I agree to the Terms & Conditions and <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"WouldLikeToReceiveNotification": "I would like to receive the latest news from abp.io websites.",
"CommercialNewsletterConfirmationMessage": "I agree to the <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/TermsConditions\">Terms & Conditions</a> and <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"CommercialNewsletterConfirmationMessage": "I agree to the <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/TermsConditions\">Terms & Conditions</a> and <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"FreeDDDEBook": "Free DDD E-Book",
"AdditionalServices": "Additional Services",
"Learn": "Learn",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json

@ -91,7 +91,7 @@
"JoinOurMarketingNewsletter": "Liity markkinointiuutiskirjeeseemme",
"CommunityPrivacyPolicyConfirmation": "Hyväksyn käyttöehdot ja <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">tietosuojakäytännön</a> .",
"WouldLikeToReceiveNotification": "Haluan saada viimeisimmät uutiset abp.io-sivustoilta.",
"CommercialNewsletterConfirmationMessage": "Hyväksyn <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/TermsConditions\">käyttöehdot</a> ja <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">tietosuojakäytännön</a>.",
"CommercialNewsletterConfirmationMessage": "Hyväksyn <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/TermsConditions\">käyttöehdot</a> ja <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/Privacy\">tietosuojakäytännön</a>.",
"FreeDDDEBook": "Ilmainen DDD e-kirja",
"AdditionalServices": "Lisäpalvelut",
"Learn": "Opi",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/hu.json

@ -91,7 +91,7 @@
"JoinOurMarketingNewsletter": "Csatlakozzon marketing hírlevelünkhöz",
"CommunityPrivacyPolicyConfirmation": "Elfogadom az Általános Szerződési Feltételeket és az <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">Adatvédelmi szabályzatot</a>.",
"WouldLikeToReceiveNotification": "Szeretném megkapni a legfrissebb híreket az abp.io webhelyekről.",
"CommercialNewsletterConfirmationMessage": "Elfogadom az <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/TermsConditions\">Általános Szerződési Feltételeket</a> és az <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">Adatvédelmi szabályzatot</a> .",
"CommercialNewsletterConfirmationMessage": "Elfogadom az <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/TermsConditions\">Általános Szerződési Feltételeket</a> és az <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/Privacy\">Adatvédelmi szabályzatot</a> .",
"FreeDDDEBook": "Ingyenes DDD e-könyv",
"AdditionalServices": "További szolgáltatások",
"Learn": "Tanulás",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json

@ -83,7 +83,7 @@
"JoinOurMarketingNewsletter": "Pazarlama bültenimize katılın",
"CommunityPrivacyPolicyConfirmation": "Şartları, Koşulları ve <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">Gizlilik Politikasını</a> kabul ediyorum.",
"WouldLikeToReceiveNotification": "abp.io web sitelerinden en son haberleri almak istiyorum.",
"CommercialNewsletterConfirmationMessage": "<a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/TermsConditions\">Şartlar ve Koşulları</a> ve <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">Gizlilik Politikasını</a> kabul ediyorum.",
"CommercialNewsletterConfirmationMessage": "<a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/TermsConditions\">Şartlar ve Koşulları</a> ve <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/Privacy\">Gizlilik Politikasını</a> kabul ediyorum.",
"FreeDDDEBook": "Ücretsiz DDD E-Kitabı",
"AdditionalServices": "Ek Hizmetler",
"Learn": "Öğren",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json

@ -91,7 +91,7 @@
"JoinOurMarketingNewsletter": "加入我们市场推广时事通讯",
"CommunityPrivacyPolicyConfirmation": "我同意条款 & 条件和<a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">隐私政策 </a>。",
"WouldLikeToReceiveNotification": "我想从 abp.io 网站接收最新消息。",
"CommercialNewsletterConfirmationMessage": "我同意<a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/TermsConditions\">条款 & 条件</a > 和 <a class=\"text-white fw-6 text-decoration-underline opacity-50\" href=\"https://commercial.abp.io/Privacy\">隐私政策</a>。",
"CommercialNewsletterConfirmationMessage": "我同意<a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/TermsConditions\">条款 & 条件</a > 和 <a class=\"text-white fw-bolder text-decoration-underline\" href=\"https://commercial.abp.io/Privacy\">隐私政策</a>。",
"FreeDDDEBook": "免费 DDD 电子书",
"AdditionalServices": "额外服务",
"Learn": "学习",

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json

@ -792,6 +792,8 @@
"TermsConditionsPageTitle": "الأحكام والشروط",
"TrainingsPageTitle": "حزم تدريب ABP",
"ModulesPageTitle": "وحدات تطبيق ABP سابقة البناء",
"MultipleOrganizationInfo": "شاهد جميع مؤسساتك"
"MultipleOrganizationInfo": "شاهد جميع مؤسساتك",
"PaymentFailedInfo": "عذرا، فشل الدفع! ",
"UsedPayment": "لقد تم استخدام هذه الدفعة بالفعل"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json

@ -406,6 +406,8 @@
"WhatHappensWhenLicenseEndsExplanation7": "Pokud chcete i nadále využívat tyto výhody, můžete svou licenci prodloužit (obnovit). Pokud prodloužíte licenci do <strong>{3} dní</strong> po vypršení platnosti licence, budou uplatněny následující slevy: Týmová licence {0}; Obchodní licence {1}; Enterprise Licence {2}.",
"BlazoriseLicense": "Musíme si koupit licenci Blazorise?",
"BlazoriseLicenseExplanation": "Máme dohodu mezi společnostmi Volosoft a Megabit, na základě této dohody je licence Blazorise přibalena k produktům ABP Commercial, proto si naši zákazníci nemusí kupovat další licenci Blazorise.",
"MultipleOrganizationInfo": "Podívejte se na všechny vaše organizace"
"MultipleOrganizationInfo": "Podívejte se na všechny vaše organizace",
"PaymentFailedInfo": "Omlouváme se, platba se nezdařila! ",
"UsedPayment": "Tato platba již byla použita"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json

@ -387,6 +387,8 @@
"RenewLicenseEarly": "Erhalte ich das ganze Jahr, wenn ich meine Lizenz vorzeitig erneuere?",
"RenewLicenseEarylExplanation": "Wenn Sie Ihre Lizenz vor dem Ablaufdatum Ihrer Lizenz erneuern, wird Ihr Lizenzablaufdatum um 1 Jahr verlängert. Wenn Ihre Lizenz beispielsweise am {0}-06-06 abläuft und Sie sie am {0}-01-01 erneuern, ist das neue Ablaufdatum der Lizenz der {1}-06-06.",
"BlackFridayDiscount": "Black Friday Rabatt",
"MultipleOrganizationInfo": "Alle Ihre Organisationen anzeigen"
"MultipleOrganizationInfo": "Alle Ihre Organisationen anzeigen",
"PaymentFailedInfo": "Entschuldigung, die Zahlung ist fehlgeschlagen! ",
"UsedPayment": "Diese Zahlung wurde bereits verwendet"
}
}

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

@ -111,6 +111,8 @@
"RenewLicenseEarylExplanation": "When you renew your license before your license expiry date, 1 year will be added to your license expiry date. For example, if your license expires on {0}-06-06 and you renew it on {0}-01-01, your new license expiry date will be {1}-06-06.",
"LicenseTypeNotCorrect": "The license type is not correct!",
"BlackFridayDiscount": "Black Friday Discount",
"MultipleOrganizationInfo": "See All Your Organizations"
"MultipleOrganizationInfo": "See All Your Organizations",
"PaymentFailedInfo": "Sorry, payment failed! This could be due to insufficient funds, invalid credit card numbers or invalid pin",
"UsedPayment": "This payment has been already used"
}
}

8
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -50,7 +50,7 @@
"AbpCommercialShortDescription": "ABP Commercial provides pre-built application modules, rapid application development tooling, professional UI themes, premium support and more.",
"LiveDemo": "Live Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> using your ABP account, <a href=\"{2}\">{3}</a> to abp.io <br/> or fill the form below to create a live demo now",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "There is already an account with the given email address: <b>{0}</b><br/> You can login with your account to proceed.",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "There is already an account with the given email address: <b>{0}</b><br/> You should login with your account to proceed.",
"GetLicence": "Get a License",
"Application": "Application",
"StartupTemplates": "Startup Templates",
@ -849,7 +849,7 @@
"BlazoriseSupportExplanation5": "You can post your questions on the support website and generate a product token for your application.",
"AbpLiveTrainingPackages": "ABP Live Training Packages",
"Releases": "Releases",
"ReleasesDescription": "Release logs of ABP Commercial.",
"ReleasesDescription": "This page contains detailed information about each release. You can see all the closed pull requests for a specific release. For overall milestone developments, you can check out the <a href=\"https://docs.abp.io/en/commercial/latest/release-notes\">brief release notes page</a>.",
"ReleaseDate": "Release Date",
"Labels": "Labels",
"PreRelease": "Pre-release",
@ -1089,6 +1089,8 @@
"MultipleOrganizationInfo": "See All Your Organizations",
"AbpStudioBetaAccessInfoTitle": "ABP Studio Beta Access",
"AbpStudioBetaAccessInfoText": "We're thrilled to share with you the <span class=\"text-highlight-white\">beta</span> version of <span class=\"text-highlight-white\">ABP Studio</span>! This release marks a significant milestone in our development journey, and we're eager to gather your feedback to make the application even better.",
"YouAreNotAuthorizedToDownloadStudio": "You are not authorized to download ABP Studio."
"YouAreNotAuthorizedToDownloadStudio": "You are not authorized to download ABP Studio.",
"PaymentFailedInfo": "Sorry, payment failed! This could be due to insufficient funds, invalid credit card numbers or invalid pin",
"UsedPayment": "This payment has been already used"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json

@ -387,6 +387,8 @@
"RenewLicenseEarly": "Si renuevo mi licencia antes, ¿obtendré el año completo?",
"RenewLicenseEarylExplanation": "Cuando renueve su licencia antes de la fecha de vencimiento de su licencia, se agregará 1 año a la fecha de vencimiento de su licencia. Por ejemplo, si su licencia vence el {0} -06-06 y la renueva el {0} -01-01, la fecha de vencimiento de su nueva licencia será {1} -06-06.",
"BlackFridayDiscount": "Descuento de viernes negro",
"MultipleOrganizationInfo": "Vea todas sus organizaciones"
"MultipleOrganizationInfo": "Vea todas sus organizaciones",
"PaymentFailedInfo": "Lo sentimos, ¡el pago falló! ",
"UsedPayment": "Este pago ya ha sido utilizado."
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json

@ -828,6 +828,8 @@
"SpringCampaignDiscount": "Kevään kampanja-alennus",
"WhyUseAbpIoPlatform": "Miksi minun pitäisi käyttää ABP.IO-alustaa sen sijaan, että luon uuden ratkaisun tyhjästä?",
"WhyUseAbpIoPlatformFaqExplanation": "Katso <a href=\"https://docs.abp.io/en/commercial/latest/why-abp-io-platform \"> kyseisestä asiakirjasta </a> yksityiskohtainen selitys siitä, miksi ABP.IO Platformin käyttäminen on huomattavasti edullisempaa kuin kaiken tekeminen itse.",
"MultipleOrganizationInfo": "Katso kaikki organisaatiosi"
"MultipleOrganizationInfo": "Katso kaikki organisaatiosi",
"PaymentFailedInfo": "Anteeksi, maksu epäonnistui! ",
"UsedPayment": "Tämä maksu on jo käytetty"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json

@ -406,6 +406,8 @@
"WhatHappensWhenLicenseEndsExplanation7": "Vous pouvez prolonger (renouveler) votre licence si vous souhaitez continuer à bénéficier de ces avantages. Si vous prolongez votre licence dans <strong>{3} jours</strong> après l'expiration de votre licence, les remises suivantes seront appliquées : Licence d'équipe {0} ; Licence commerciale {1} ; Licence Entreprise {2}.",
"BlazoriseLicense": "Faut-il acheter une licence Blazorise ?",
"BlazoriseLicenseExplanation": "Nous avons conclu un accord entre Volosoft et Megabit, dans le cadre duquel la licence Blazorise est intégrée aux produits ABP Commercial, de sorte que nos clients n'ont pas besoin d'acheter une licence Blazorise supplémentaire.",
"MultipleOrganizationInfo": "Voir toutes vos organisations"
"MultipleOrganizationInfo": "Voir toutes vos organisations",
"PaymentFailedInfo": "Désolé, le paiement a échoué! ",
"UsedPayment": "Ce paiement a déjà été utilisé"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json

@ -405,6 +405,8 @@
"WhatHappensWhenLicenseEndsExplanation7": "यदि आप इन लाभों को प्राप्त करना जारी रखना चाहते हैं तो आप अपने लाइसेंस का विस्तार (नवीनीकरण) कर सकते हैं। यदि आप अपना लाइसेंस समाप्त होने के बाद <strong>{3} दिन</strong> के भीतर अपना लाइसेंस बढ़ाते हैं, तो निम्नलिखित छूट लागू होंगी: टीम लाइसेंस {0}; व्यवसाय लाइसेंस {1}; उद्यम लाइसेंस {2}।",
"BlazoriseLicense": "क्या हमें ब्लेज़ोराइज़ लाइसेंस खरीदने की ज़रूरत है?",
"BlazoriseLicenseExplanation": "हमारे पास Volosoft और Megabit के बीच एक समझौता है, इस समझौते के साथ Blazorise लाइसेंस को ABP वाणिज्यिक उत्पादों के साथ बंडल किया गया है, इसलिए हमारे ग्राहकों को एक अतिरिक्त Blazorise लाइसेंस खरीदने की आवश्यकता नहीं है।",
"MultipleOrganizationInfo": "अपने सभी संगठन देखें"
"MultipleOrganizationInfo": "अपने सभी संगठन देखें",
"PaymentFailedInfo": "क्षमा करें, भुगतान विफल रहा! ",
"UsedPayment": "इस भुगतान का उपयोग पहले ही किया जा चुका है"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json

@ -1084,6 +1084,8 @@
"MultipleYearDiscount": "Višegodišnji popust",
"CampaignDiscountText": "Crni petak popust",
"CampaignDiscountName": "Crni petak",
"CampaignName:BlackFriday": "Crni petak"
"CampaignName:BlackFriday": "Crni petak",
"PaymentFailedInfo": "Nažalost, plaćanje nije uspjelo! ",
"UsedPayment": "Ovo plaćanje je već iskorišteno"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json

@ -754,6 +754,8 @@
"ExtendPaymentInfoSection_DiscountRate": "Kedvezmény: {0}%",
"TotalNetPrice": "Total Net Price",
"BlackFridayDiscount": "Black Friday Kedvezmény",
"MultipleOrganizationInfo": "Tekintse meg az összes szervezetét"
"MultipleOrganizationInfo": "Tekintse meg az összes szervezetét",
"PaymentFailedInfo": "Sajnos a fizetés sikertelen! ",
"UsedPayment": "Ezt a fizetést már felhasználták"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json

@ -384,6 +384,8 @@
"TrialLicenseExpiredInfo": "Prófunartímabil þitt er útrunnið!",
"CommercialNewsletterConfirmationMessage": "Ég samþykki <a href=\"https://commercial.abp.io/TermsConditions\">skilmálana</a> og <a href=\"https://commercial.abp.io/Privacy\">persónuverndarstefnuna </a>.",
"BlackFridayDiscount": "Black Friday afsláttur",
"MultipleOrganizationInfo": "Sjá öll samtök þín"
"MultipleOrganizationInfo": "Sjá öll samtök þín",
"PaymentFailedInfo": "Því miður, greiðsla mistókst! ",
"UsedPayment": "Þessi greiðsla hefur þegar verið notuð"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json

@ -405,6 +405,8 @@
"WhatHappensWhenLicenseEndsExplanation7": "Puoi estendere (rinnovare) la tua licenza se desideri continuare a ottenere questi vantaggi. Se estendi la licenza entro <strong>{3} giorni</strong> dalla scadenza della licenza, verranno applicati i seguenti sconti: Licenza Team {0}; Licenza commerciale {1}; Licenza aziendale {2}.",
"BlazoriseLicense": "Dobbiamo acquistare la licenza di Blazorise?",
"BlazoriseLicenseExplanation": "Abbiamo un accordo tra Volosoft e Megabit, con il quale la licenza di Blazorise viene fornita in bundle con i prodotti commerciali ABP, pertanto i nostri clienti non hanno bisogno di acquistare una licenza Blazorise aggiuntiva.",
"MultipleOrganizationInfo": "Visualizza tutte le tue organizzazioni"
"MultipleOrganizationInfo": "Visualizza tutte le tue organizzazioni",
"PaymentFailedInfo": "Siamo spiacenti, pagamento non riuscito! ",
"UsedPayment": "Questo pagamento è già stato utilizzato"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json

@ -384,6 +384,8 @@
"TrialLicenseExpiredInfo": "Uw proeflicentieperiode is verlopen!",
"CommercialNewsletterConfirmationMessage": "Ik ga akkoord met de <a href=\"https://commercial.abp.io/TermsConditions\">Algemene voorwaarden</a> en het <a href=\"https://commercial.abp.io/Privacy\">Privacybeleid </a>.",
"BlackFridayDiscount": "Black Friday korting",
"MultipleOrganizationInfo": "Bekijk al uw organisaties"
"MultipleOrganizationInfo": "Bekijk al uw organisaties",
"PaymentFailedInfo": "Excuses, betaling mislukt! ",
"UsedPayment": "Deze betaling is al gebruikt"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json

@ -384,6 +384,8 @@
"TrialLicenseExpiredInfo": "Twoja licencja próbna wygasła!",
"CommercialNewsletterConfirmationMessage": "Wyrażam zgodę na <a href=\"https://commercial.abp.io/TermsConditions\">Warunki</a> i <a href=\"https://commercial.abp.io/Privacy\">Politykę prywatności </a>.",
"BlackFridayDiscount": "Zniżka Black Friday",
"MultipleOrganizationInfo": "Zobacz wszystkie swoje organizacje"
"MultipleOrganizationInfo": "Zobacz wszystkie swoje organizacje",
"PaymentFailedInfo": "Przepraszamy, płatność nie powiodła się! ",
"UsedPayment": "Ta płatność została już wykorzystana"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json

@ -407,6 +407,8 @@
"WhatHappensWhenLicenseEndsExplanation5": "Você não pode usar o ABP Suite",
"WhatHappensWhenLicenseEndsExplanation6": "Você não pode mais obter o <a href==\"{0}\">apoio de premium</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Você pode estender (renovar) sua licença se quiser continuar obtendo esses benefícios. Se você estender sua licença dentro de <strong>{3} dias</strong> após a expiração de sua licença, os seguintes descontos serão aplicados: Licença de equipe {0}; Licença Comercial {1}; Licença empresarial {2}.",
"MultipleOrganizationInfo": "Veja todas as suas organizações"
"MultipleOrganizationInfo": "Veja todas as suas organizações",
"PaymentFailedInfo": "Desculpe, o pagamento falhou! ",
"UsedPayment": "Este pagamento já foi usado"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json

@ -384,6 +384,8 @@
"TrialLicenseExpiredInfo": "Perioada de licență de probă a expirat!",
"CommercialNewsletterConfirmationMessage": "Sunt de acord cu <a href=\"https://commercial.abp.io/TermsConditions\">Termenii și condițiile</a> și cu <a href=\"https://commercial.abp.io/Privacy\">Politica de confidențialitate </a>.",
"BlackFridayDiscount": "Black Friday Discount",
"MultipleOrganizationInfo": "Vedeți toate organizațiile dvs"
"MultipleOrganizationInfo": "Vedeți toate organizațiile dvs",
"PaymentFailedInfo": "Ne pare rău, plata nu a reușit! ",
"UsedPayment": "Această plată a fost deja utilizată"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json

@ -1085,6 +1085,8 @@
"CampaignDiscountText": "Скидка на Черную пятницу",
"CampaignDiscountName": "Черная пятница",
"CampaignName:BlackFriday": "Черная пятница",
"MultipleOrganizationInfo": "Просмотреть все ваши организации"
"MultipleOrganizationInfo": "Просмотреть все ваши организации",
"PaymentFailedInfo": "Извините, оплата не удалась! ",
"UsedPayment": "Этот платеж уже использован"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json

@ -403,6 +403,8 @@
"WhatHappensWhenLicenseEndsExplanation7": "Ak chcete naďalej využívať tieto výhody, môžete si licenciu predĺžiť (obnoviť). Ak predĺžite svoju licenciu do <strong>30 dní</strong> po vypršaní platnosti licencie, budú sa uplatňovať nasledujúce zľavy: Tímová licencia {0}; Obchodná licencia {1}; Podniková licencia {2}",
"BlazoriseLicense": "Musíme si kúpiť licenciu Blazorise?",
"BlazoriseLicenseExplanation": "Máme dohodu medzi spoločnosťami Volosoft a Megabit, na základe ktorej je licencia Blazorise pribalená k produktom ABP Commercial, preto si naši zákazníci nemusia kupovať ďalšiu licenciu Blazorise.",
"MultipleOrganizationInfo": "Pozrite si všetky vaše organizácie"
"MultipleOrganizationInfo": "Pozrite si všetky vaše organizácie",
"PaymentFailedInfo": "Ľutujeme, platba zlyhala! ",
"UsedPayment": "Táto platba už bola použitá"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json

@ -384,6 +384,8 @@
"TrialLicenseExpiredInfo": "Vaša preizkusna licenca je potekla!",
"CommercialNewsletterConfirmationMessage": "Strinjam se s <a href=\"https://commercial.abp.io/TermsConditions\">pogoji in določili</a> in <a href=\"https://commercial.abp.io/Privacy\">pravilnikom o zasebnosti </a>.",
"BlackFridayDiscount": "Popust Black Friday",
"MultipleOrganizationInfo": "Oglejte si vse svoje organizacije"
"MultipleOrganizationInfo": "Oglejte si vse svoje organizacije",
"PaymentFailedInfo": "Žal plačilo ni uspelo! ",
"UsedPayment": "To plačilo je že bilo uporabljeno"
}
}

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

@ -842,6 +842,16 @@
"OneCodeBaseMultipleDevices_Description": "ABP Mobil uygulamaları çapraz platformdur. iOS ve Android cihazlara yüklenmeye ve çalıştırılmaya hazırdırlar ve tek bir kod tabanı kullanarak farklı form faktörlerine uyum sağlarlar. Geliştiricilerin kullanıcı arayüzünü ve ön uç kodunu yalnızca bir kez oluşturması gerekir, desteklemek istediğiniz her cihaz için kodu uyarlamanıza gerek yoktur.",
"ComesWithTheSourceCode": "Kaynak Koduyla Birlikte Geliyor",
"ComesWithTheSourceCode_Description": "Mobil uygulamalar kaynak koduyla birlikte sağlanır. Marka yönergelerini karşılamak için uygulamalarınızın UX/UI'sini kolayca özelleştirin.",
"MultipleOrganizationInfo": "Tüm Organizasyonlarınızı Görün"
"MultipleOrganizationInfo": "Tüm Organizasyonlarınızı Görün",
"PaymentFailedInfo": "Üzgünüz, Ödeme başarısız oldu! Bu hata, yatersiz bakiye, yanlış kredi kartı numarası veya yanlış PIN numarasından dolayı olabilir.",
"UsedPayment": "Bu ödeme zaten kullanımda.",
"TestimonialText": "Referans Yazınız",
"Position": "Poziyonunuz",
"ExperienceYear": "Yazılım Sektöründeki Tecrübeniz (Yıl)",
"Select": "Seçiniz",
"TestimonialTitle": "Referans",
"TestimonialInfo": "Düşüncelerinizi Paylaşın",
"Share": "Paylaş",
"YouAreNotAuthorizedToWriteTestimonial" : "Referansınızı paylaşabilmeniz için giriş yapmanız gerekmektedir"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json

@ -384,6 +384,8 @@
"TrialLicenseExpiredInfo": "Thời gian cấp phép dùng thử của bạn đã hết hạn!",
"CommercialNewsletterConfirmationMessage": "Tôi đồng ý với <a href=\"https://commercial.abp.io/TermsConditions\"> Điều khoản & điều kiện </a> và <a href=\"https://commercial.abp.io/Privacy\"> Chính sách quyền riêng tư </a>.",
"BlackFridayDiscount": "Giảm giá Black Friday",
"MultipleOrganizationInfo": "Xem tất cả các tổ chức của bạn"
"MultipleOrganizationInfo": "Xem tất cả các tổ chức của bạn",
"PaymentFailedInfo": "Rất tiếc, thanh toán không thành công! ",
"UsedPayment": "Khoản thanh toán này đã được sử dụng"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json

@ -843,6 +843,8 @@
"BlazoriseSupportExplanation5": "您可以在support网站上发布您的问题,并为您的应用程序生成一个产品令牌。",
"ExtraQuestionCreditsFaqTitle": "我可以购买额外的问题支持次数吗?",
"ExtraQuestionCreditsFaqExplanation": "是的,您可以购买额外的问题支持次数,请发送电子邮件至<a href=\"mailto:info@abp.io\">info@abp.io</a>,并提供您的组织名称。以下是额外问题支持次数的价格列表: <ul><li>50次问题 $999</li><li>25次问题 $625</li><li>15次问题 $450</li></ul>",
"MultipleOrganizationInfo": "查看您的所有组织"
"MultipleOrganizationInfo": "查看您的所有组织",
"PaymentFailedInfo": "抱歉,支付失败!",
"UsedPayment": "该付款已被使用"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json

@ -409,6 +409,8 @@
"WhatHappensWhenLicenseEndsExplanation7": "如果您想繼續獲得這些好處,您可以延長(更新)您的許可證。如果您在許可到期後 <strong>{3} 天</strong> 內延長許可,將應用以下折扣:團隊許可 {0};營業執照{1};企業許可證{2}。",
"DoesTheSubscriptionRenewAutomatically": "許可會自動續費嗎?",
"DoesTheSubscriptionRenewAutomaticallyExplanation": "ABP 商業版沒有自動續費的計費模式。因此,在您的許可期結束時,<strong>您的訂閱將不會自動續訂</strong>。如果您希望繼續享受ABP商業版的服務,請在<a href=\"/my-organizations\">組織管理頁面</a>手動進行續費操作。如果您擁有多個組織,您可以點擊即將到期的組織上的\"管理\"按鈕,然後點擊\"立即續費\"按鈕來續訂您的許可。您還可以查看<a href=\"/faq#what-happens-when-license-ends\">許可到期後會發生什麼?</a>部分了解更多信息。",
"MultipleOrganizationInfo": "查看您的所有組織"
"MultipleOrganizationInfo": "查看您的所有組織",
"PaymentFailedInfo": "抱歉,支付失败!",
"UsedPayment": "该付款已被使用"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json

@ -191,7 +191,7 @@
"DiscordPageTitle": "ABP Discord Community",
"ViewVideo": "View Video",
"AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework",
"CommunitySlogan": "A unique community platform for <span class=\"d-inline-block d-md-block gradient-community\">ABP Lovers</span>",
"CommunitySlogan": "A unique community platform for <span class=\"{0}\">ABP Lovers</span>",
"RaffleIsNotActive": "Raffle is not active",
"YouAreAlreadyJoinedToThisRaffle": "You are already joined to this raffle",
"InvalidSubscriptionCode": "Invalid subscription code",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "أنت تركز على رمز عملك وتدع إطار العمل للتعامل مع عقود الإيجار المتعددة نيابة عنك.",
"BootstrapTagHelpersExplanation": "بدلاً من كتابة التفاصيل المتكررة لمكونات التمهيد يدويًا، استخدم مساعدي علامات ABP لتبسيطها والاستفادة من IntelliSense. يمكنك بالتأكيد استخدام Bootstrap متى احتجت إليه.",
"DynamicFormsExplanation": "يمكن لمساعدي النموذج الديناميكي وعلامات الإدخال إنشاء النموذج الكامل من فئة C # كنموذج.",
"AuthenticationAuthorizationExplanation": "خيارات المصادقة والرخصة الغنية المدمجة في ASP.NET Core Identity & IdentityServer4. يوفر نظام إذن موسع ومفصل.",
"AuthenticationAuthorizationExplanation": "خيارات المصادقة والرخصة الغنية المدمجة في ASP.NET Core Identity & OpenIddict. يوفر نظام إذن موسع ومفصل.",
"CrossCuttingConcernsExplanation": "لا تكرر نفسك لتنفيذ كل هذه الأشياء الشائعة مرارًا وتكرارًا. ركز على كود عملك ودع ABP يقوم بأتمتة ذلك من خلال الاتفاقيات.",
"DatabaseConnectionTransactionManagement": "اتصال قاعدة البيانات وإدارة المعاملات",
"CorrelationIdTracking": "تتبع معرف الارتباط",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/cs.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Soustředíte se na svůj obchodní kód a necháte framework, aby za vás zpracovával multi-tenancy.",
"BootstrapTagHelpersExplanation": "Místo ručního psaní opakujících se podrobností o komponentách bootstrapu použijte pomocníky značek ABP, abyste to zjednodušili a využili výhody intellisense. Bootstrap můžete určitě použít, kdykoli budete potřebovat.",
"DynamicFormsExplanation": "Pomocníci dynamického formuláře a vstupní značky mohou vytvořit kompletní formulář z třídy C# jako model.",
"AuthenticationAuthorizationExplanation": "Bohaté možnosti ověřování a autorizace integrované do ASP.NET Core Identity & IdentityServer4. Poskytuje rozšiřitelný a podrobný systém oprávnění.",
"AuthenticationAuthorizationExplanation": "Bohaté možnosti ověřování a autorizace integrované do ASP.NET Core Identity & OpenIddict. Poskytuje rozšiřitelný a podrobný systém oprávnění.",
"CrossCuttingConcernsExplanation": "Neopakujte se, abyste zavedli všechny tyto běžné věci znovu a znovu. Zaměřte se na svůj obchodní kód a nechte je ABP automatizovat podle konvencí.",
"DatabaseConnectionTransactionManagement": "Připojení k databázi a správa transakcí",
"CorrelationIdTracking": "Correlation-Id Tracking",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/de.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Sie konzentrieren sich auf Ihren geschäftsspezifischen Code und lassen das Framework die Mandantenfähigkeit für Sie übernehmen.",
"BootstrapTagHelpersExplanation": "Anstatt die sich wiederholenden Details von Bootstrap-Komponenten manuell zu schreiben, verwenden Sie die Tag-Helper von ABP, um diese zu vereinfachen und dabei die Vorteile von Intellisense zu nutzen. Sie können Bootstrap weitherhin verwenden, wann immer Sie es benötigen.",
"DynamicFormsExplanation": "Helfer für dynamische Formular- und Input-Tags können das vollständige Formular anhand einer C#-Klasse als Model erstellen.",
"AuthenticationAuthorizationExplanation": "Umfangreiche Authentifizierungs- und Autorisierungsoptionen, die in ASP.NET Core Identity & IdentityServer4 integriert sind. Bietet ein erweiterbares und detailliertes Berechtigungssystem.",
"AuthenticationAuthorizationExplanation": "Umfangreiche Authentifizierungs- und Autorisierungsoptionen, die in ASP.NET Core Identity & OpenIddict integriert sind. Bietet ein erweiterbares und detailliertes Berechtigungssystem.",
"CrossCuttingConcernsExplanation": "Wiederholen Sie sich nicht, um all diese allgemeinen Dinge immer wieder zu implementieren. Konzentrieren Sie sich auf Ihren geschäftsspezifischen Code und lassen Sie ihn von ABP durch Konventionen automatisieren.",
"DatabaseConnectionTransactionManagement": "Datenbankverbindungs- und Transaktionsmanagement",
"CorrelationIdTracking": "Correlation-ID-Verfolgung",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en-GB.json

@ -121,7 +121,7 @@
"MultiTenancyExplanation4": "You focus on your business code and let the framework to handle multi-tenancy on behalf of you.",
"BootstrapTagHelpersExplanation": "Instead of manually writing the repeating details of bootstrap components, use ABP's tag helpers to simplify and take advantage of intellisense. You can use Bootstrap whenever you need it.",
"DynamicFormsExplanation": "Dynamic form & input tag helpers can create the complete form from a C# class as the model.",
"AuthenticationAuthorizationExplanation": "Rich authentication & authorization options integrated to ASP.NET Core Identity & IdentityServer4. Provides an extensible & detailed permission system.",
"AuthenticationAuthorizationExplanation": "Rich authentication & authorization options integrated to ASP.NET Core Identity & OpenIddict. Provides an extensible & detailed permission system.",
"CrossCuttingConcernsExplanation": "Don't repeat yourself when implementing common features. Instead, focus on your business logic and let ABP automate by convention.",
"DatabaseConnectionTransactionManagement": "Database Connection & Transaction Management",
"CorrelationIdTracking": "Correlation-Id Tracking",

26
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "You focus on your business code and let the framework handle multi-tenancy on behalf of you.",
"BootstrapTagHelpersExplanation": "Instead of manually writing the repeating details of bootstrap components, use ABP's tag helpers to simplify it and take advantage of the IntelliSense. You can definitely use Bootstrap whenever you need it.",
"DynamicFormsExplanation": "Dynamic form & input tag helpers can create the complete form from a C# class as the model.",
"AuthenticationAuthorizationExplanation": "Rich authentication & authorization options integrated to ASP.NET Core Identity & IdentityServer4. Provides an extensible & detailed permission system.",
"AuthenticationAuthorizationExplanation": "Rich authentication & authorization options integrated to ASP.NET Core Identity & OpenIddict. Provides an extensible & detailed permission system.",
"CrossCuttingConcernsExplanation": "Don't repeat yourself to implement all this common stuff again & again. Focus on your business code and let ABP automate them by conventions.",
"DatabaseConnectionTransactionManagement": "Database Connection & Transaction Management",
"CorrelationIdTracking": "Correlation-Id Tracking",
@ -440,7 +440,29 @@
"Index_Page_Testimonial_2": "ABP Framework is not only a framework, it is also a guidance for project development/management, because it provides DDD, GenericRepository, DI, Microservice, Modularity trainings. Even if you are not going to use framework itself, you can develop yourself with docs.abp.io which is well and professionally prepared. (OpenIddict, Redis, Quartz etc.)\nBecause many thing pre-built, it shortens project development time significantly. (Such as login page, exception handling, data filtering-seeding, audit logging, localization, auto api controller etc.)\nAs an example from our app, i have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler.\nIt is wonderful not to lose time for CreationTime, CreatorId. They are filled automatically.",
"VideosLoginAndRegisterMessage": "To be able to watch videos, you must sign in.",
"Filter": "Filter",
"VideoCourses": "Video Courses"
"VideoCourses": "Video Courses",
"TestimonialText": "Your testimonial",
"Position": "Position",
"ExperienceYear": "Years of Experience",
"FullName": "Full Name",
"CompanySize": "Company Size",
"Image": "Your profile picture",
"TestimonialTitle": "Let's hear your testimonial",
"TestimonialInfo": "What our customers say matters! Tell us about your experience with our product and service.",
"Country": "Country",
"TestimonialTextPlaceholder": "Write a brief story about how ABP helped you build and deliver your project. ",
"PositionPlaceholder": "Your position at your company.",
"SelectExperienceYearPlaceholder": "How many years have you been in software stuff",
"FullNamePlaceholder": "Your full name.",
"CompanyNamePlaceholder": "Your company name.",
"SelectCompanySizePlaceholder": "Employee count",
"ImagePlaceholder": "Your image.",
"SelectCountryPlaceholder": "Your country.",
"YouAreNotAuthorizedToWriteTestimonial": "To be able to write testimonial letter, you must be sign in.",
"UnAuthorizeTestimonialInfo": "If you want to share your opinion, you must be <a id='signin-btn'>sign in</a>",
"TheFileIsTooLargeForImage": "Your profile picture cannot be more than 1 MB",
"ThisExtensionIsNotAllowedForImage": "This extension is not allowed.",
"FileUploadError": "File upload error"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/es.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Enfocate en tu código y deja al framework que maneje multi-inquilino en tu nombre.",
"BootstrapTagHelpersExplanation": "En vez de escribir repetidamente los detalle de componentes bootstrap, usa ABP's tag helpers para simplificarlo y obtener ventaja de intellisence. Tu puedes definitivamente usar Bootstrp cuando tu lo necesites.",
"DynamicFormsExplanation": "Los formularios dinámicos y tag helpers de entrada pueden crear el formulario completo a partir de una clase de C# como modelo. ",
"AuthenticationAuthorizationExplanation": "Autenticación enriquecidad y opciones de autorización integradas con ASP.NET Core Identity & IdentityServer4. Proporciona un extensible y detallado sistema de permisos.",
"AuthenticationAuthorizationExplanation": "Autenticación enriquecidad y opciones de autorización integradas con ASP.NET Core Identity & OpenIddict. Proporciona un extensible y detallado sistema de permisos.",
"CrossCuttingConcernsExplanation": "No te repitas tu mismo al implementar todas esas cosas comunes una y otra vez. Enfocate en tu negocio y permite a ABP automatizarlos por convención.",
"DatabaseConnectionTransactionManagement": "Conexión de base de datos y gestión de transacciones",
"CorrelationIdTracking": "Correlation-Id de seguimiento",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fi.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Keskity yrityksesi koodiin ja annat kehyksen hoitamaan monivuokrausta puolestasi.",
"BootstrapTagHelpersExplanation": "Sen sijaan, että kirjoittaisit manuaalisesti uudelleenkäynnistyskomponenttien yksityiskohtia, käytä ABP: n tunnisteita yksinkertaistaaksesi sitä ja hyödyntäksesi älykkäitä ominaisuuksia. Voit ehdottomasti käyttää Bootstrapia milloin tahansa.",
"DynamicFormsExplanation": "Dynaamiset lomake- ja syöttötunnisteiden apurit voivat luoda täydellisen lomakkeen mallina C# -luokasta.",
"AuthenticationAuthorizationExplanation": "ASP.NET Core Identity & IdentityServer4 -palveluun integroidut monipuoliset todennus- ja todennusvaihtoehdot. Tarjoaa laajennettavan ja yksityiskohtaisen lupajärjestelmän.",
"AuthenticationAuthorizationExplanation": "ASP.NET Core Identity & OpenIddict -palveluun integroidut monipuoliset todennus- ja todennusvaihtoehdot. Tarjoaa laajennettavan ja yksityiskohtaisen lupajärjestelmän.",
"CrossCuttingConcernsExplanation": "Älä toista itseäsi kaikkien näiden yleisten asioiden toteuttamiseksi uudelleen ja uudelleen. Keskity yrityskoodiin ja anna ABP: n automatisoida ne käytäntöjen mukaan.",
"DatabaseConnectionTransactionManagement": "Tietokantayhteys ja tapahtumien hallinta",
"CorrelationIdTracking": "Korrelaatio-Id-seuranta",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fr.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Vous vous concentrez sur votre code métier et laissez le framework gérer la multi-souscrivants en votre nom.",
"BootstrapTagHelpersExplanation": "Au lieu d'écrire manuellement les détails répétitifs des composants Boostrap, utilisez les aides de balises d'ABP pour le simplifier et tirer parti d'intellisense. Vous pouvez certainement utiliser Bootstrap chaque fois que vous en avez besoin.",
"DynamicFormsExplanation": "Les assistants dynamiques de formulaire et de balise d'entrée peuvent créer le formulaire complet à partir d'une classe C# comme modèle.",
"AuthenticationAuthorizationExplanation": "Options d'authentification et d'autorisation riches intégrées à ASP.NET Core Identity & IdentityServer4. Fournit un système d'autorisation extensible et détaillé.",
"AuthenticationAuthorizationExplanation": "Options d'authentification et d'autorisation riches intégrées à ASP.NET Core Identity & OpenIddict. Fournit un système d'autorisation extensible et détaillé.",
"CrossCuttingConcernsExplanation": "Ne vous répétez pas pour mettre en œuvre toutes ces choses courantes encore et encore. Concentrez-vous sur votre code métier et laissez ABP les automatiser par des conventions.",
"DatabaseConnectionTransactionManagement": "Connexion à la base de données et gestion des transactions",
"CorrelationIdTracking": "Suivi des identifiants de corrélation",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hr.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Fokusirate se na svoj poslovni kod i prepuštate okviru da umjesto vas upravlja multi-stanarstvom.",
"BootstrapTagHelpersExplanation": "Umjesto ručnog pisanja ponavljajućih detalja komponenti pokretanja sustava, upotrijebite ABP-ove pomoćnike oznaka da to pojednostavite i iskoristite IntelliSense. Definitivno možete koristiti Bootstrap kad god vam zatreba.",
"DynamicFormsExplanation": "Pomoćnici dinamičkih obrazaca i oznaka za unos mogu stvoriti potpuni obrazac iz C# klase kao modela.",
"AuthenticationAuthorizationExplanation": "Bogate opcije provjere autentičnosti i autorizacije integrirane u ASP.NET Core Identity &amp; IdentityServer4. Omogućuje proširiv i detaljan sustav dopuštenja.",
"AuthenticationAuthorizationExplanation": "Bogate opcije provjere autentičnosti i autorizacije integrirane u ASP.NET Core Identity &amp; OpenIddict. Omogućuje proširiv i detaljan sustav dopuštenja.",
"CrossCuttingConcernsExplanation": "Nemojte se ponavljati kako biste iznova i iznova implementirali sve ove uobičajene stvari. Usredotočite se na svoj poslovni kod i dopustite ABP-u da ih automatizira prema konvencijama.",
"DatabaseConnectionTransactionManagement": "Povezivanje baze podataka i upravljanje transakcijama",
"CorrelationIdTracking": "Praćenje ID-a korelacije",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hu.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Ön az üzleti kódjára összpontosít, és hagyja, hogy a keretrendszer kezelje a több bérlést az Ön nevében.",
"BootstrapTagHelpersExplanation": "A bootstrap komponensek ismétlődő részleteinek manuális megírása helyett használja az ABP címkesegédjét az egyszerűsítéshez és az intellisense előnyeinek kihasználásához. Határozottan használhatja a Bootstrapet, amikor csak szüksége van rá.",
"DynamicFormsExplanation": "A dinamikus űrlap- és beviteli címke-segítők modellként létrehozhatják a teljes űrlapot egy C# osztályból.",
"AuthenticationAuthorizationExplanation": "Az ASP.NET Core Identity & IdentityServer4-be integrált gazdag hitelesítési és engedélyezési lehetőségek. Bővíthető és részletes engedélyezési rendszert biztosít.",
"AuthenticationAuthorizationExplanation": "Az ASP.NET Core Identity & OpenIddict-be integrált gazdag hitelesítési és engedélyezési lehetőségek. Bővíthető és részletes engedélyezési rendszert biztosít.",
"CrossCuttingConcernsExplanation": "Ne ismételje magát, hogy újra és újra végrehajtsa ezeket a gyakori dolgokat. Koncentráljon az üzleti kódjára, és hagyja, hogy az ABP konvenciók szerint automatizálja azokat.",
"DatabaseConnectionTransactionManagement": "Adatbázis-kapcsolat és tranzakciókezelés",
"CorrelationIdTracking": "Korreláció-azonosító követés",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/is.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Þú leggur áherslu á viðskiptakóðann þinn og lætur umgjörðina annast tenata virknina fyrir þína hönd.",
"BootstrapTagHelpersExplanation": "Í stað þess að skrifa handvirkt að endurtaka upplýsingar um bootstrap íhluti skaltu nota merkimiðla ABP til að einfalda það og nýta þér intellisense. Þú getur örugglega notað Bootstrap hvenær sem þú þarft á því að halda.",
"DynamicFormsExplanation": "Dynamísk form og input tag hjálp getur búið til fullbúið form úr C# klasa sem fyrirmynd",
"AuthenticationAuthorizationExplanation": "Ríkur auðkenningar- og heimildarmöguleiki samþættur með ASP.NET Core Identity & IdentityServer4. Veitir stækkanlegt og ítarlegt leyfiskerfi.",
"AuthenticationAuthorizationExplanation": "Ríkur auðkenningar- og heimildarmöguleiki samþættur með ASP.NET Core Identity & OpenIddict. Veitir stækkanlegt og ítarlegt leyfiskerfi.",
"CrossCuttingConcernsExplanation": "Ekki endurtaka sjálfan þig við að innleiða alla þessu sameiginlegu hluti aftur og aftur. Einbeittu þér að viðskiptakóðanum þínum og láttu ABP þá gera þau sjálfvirt með venjum.",
"DatabaseConnectionTransactionManagement": "Tengistrengir og færsluyfirlit",
"CorrelationIdTracking": "Samþættingar auðkennis yfirlit",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/it.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Ti concentri sul tuo codice aziendale e lasci che il framework gestisca il multi-tenancy per tuo conto.",
"BootstrapTagHelpersExplanation": "Invece di scrivere manualmente i dettagli ripetuti dei componenti bootstrap, usa gli helper tag di ABP per semplificarlo e sfruttare intellisense. Puoi sicuramente usare Bootstrap ogni volta che ne hai bisogno.",
"DynamicFormsExplanation": "Gli helper dei moduli dinamici e dei tag di input possono creare il modulo completo da una classe C# come modello.",
"AuthenticationAuthorizationExplanation": "Ricche opzioni di autenticazione e autorizzazione integrate in ASP.NET Core Identity & IdentityServer4. Fornisce un sistema di autorizzazione estensibile e dettagliato.",
"AuthenticationAuthorizationExplanation": "Ricche opzioni di autenticazione e autorizzazione integrate in ASP.NET Core Identity & OpenIddict. Fornisce un sistema di autorizzazione estensibile e dettagliato.",
"CrossCuttingConcernsExplanation": "Non ripetere te stesso per implementare tutte queste cose comuni ancora e ancora. Concentrati sul tuo codice aziendale e lascia che ABP li automatizzi secondo le convenzioni.",
"DatabaseConnectionTransactionManagement": "Connessione al database e gestione delle transazioni",
"CorrelationIdTracking": "Monitoraggio dell'ID di correlazione",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/nl.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "U concentreert zich op uw bedrijfscode en laat het framework multi-tenancy voor u afhandelen.",
"BootstrapTagHelpersExplanation": "In plaats van handmatig de herhalende details van bootstrap-componenten te schrijven, gebruikt u de tag-helpers van ABP om het te vereenvoudigen en te profiteren van intellisense. Je kunt Bootstrap zeker gebruiken wanneer je het nodig hebt.",
"DynamicFormsExplanation": "Dynamische formulier- en invoertaghelpers kunnen het volledige formulier maken vanuit een C#-klasse als model.",
"AuthenticationAuthorizationExplanation": "Uitgebreide authenticatie- en autorisatie-opties geïntegreerd in ASP.NET Core Identity & IdentityServer4. Biedt een uitbreidbaar en gedetailleerd toestemmingssysteem.",
"AuthenticationAuthorizationExplanation": "Uitgebreide authenticatie- en autorisatie-opties geïntegreerd in ASP.NET Core Identity & OpenIddict. Biedt een uitbreidbaar en gedetailleerd toestemmingssysteem.",
"CrossCuttingConcernsExplanation": "Herhaal jezelf niet om al deze veelvoorkomende dingen keer op keer te implementeren. Concentreer u op uw bedrijfscode en laat ABP ze automatiseren volgens conventies.",
"DatabaseConnectionTransactionManagement": "Databaseverbinding en transactiebeheer",
"CorrelationIdTracking": "Correlatie-ID-tracking",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pl-PL.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Skupiasz się na kodzie biznesowym i pozwalasz, by framework obsługiwał wielodostępność w Twoim imieniu.",
"BootstrapTagHelpersExplanation": "Zamiast ręcznie pisać powtarzające się szczegóły komponentów ładowania początkowego, użyj pomocników tagów ABP, aby to uprościć i wykorzystać intellisense. Zdecydowanie możesz używać Bootstrapa, kiedy tylko tego potrzebujesz.",
"DynamicFormsExplanation": "Pomocnicy dynamicznych formularzy i tagów wejściowych mogą tworzyć kompletny formularz z klasy C# jako modelu.",
"AuthenticationAuthorizationExplanation": "Bogate opcje uwierzytelniania i autoryzacji zintegrowane z ASP.NET Core Identity & IdentityServer4. Zapewnia rozszerzalny i szczegółowy system uprawnień.",
"AuthenticationAuthorizationExplanation": "Bogate opcje uwierzytelniania i autoryzacji zintegrowane z ASP.NET Core Identity & OpenIddict. Zapewnia rozszerzalny i szczegółowy system uprawnień.",
"CrossCuttingConcernsExplanation": "Nie powtarzaj się, aby ciągle wdrażać te wszystkie typowe rzeczy. Skoncentruj się na kodzie biznesowym i pozwól ABP zautomatyzować je zgodnie z konwencjami.",
"DatabaseConnectionTransactionManagement": "Połączenie z bazą danych i zarządzanie transakcjami",
"CorrelationIdTracking": "Śledzenie identyfikatora korelacji",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Você se concentra no seu código comercial e deixa o framework lidar com a multilocação em seu nome.",
"BootstrapTagHelpersExplanation": "Em vez de escrever manualmente os detalhes repetidos dos componentes do bootstrap, use os tag helpers da ABP para simplificá-lo e tirar proveito do intellisense. Você pode definitivamente usar o Bootstrap sempre que precisar.",
"DynamicFormsExplanation": "Formulário dinâmico e entrada de tag helpers pode criar o formulário completo a partir de uma classe C# como modelo.",
"AuthenticationAuthorizationExplanation": "Opções avançadas de autenticação e autorização integradas ao ASP.NET Core Identity & IdentityServer4. Fornece um sistema de permissões extensível e detalhado.",
"AuthenticationAuthorizationExplanation": "Opções avançadas de autenticação e autorização integradas ao ASP.NET Core Identity & OpenIddict. Fornece um sistema de permissões extensível e detalhado.",
"CrossCuttingConcernsExplanation": "Não se repita para implementar todas essas coisas comuns repetidamente. Concentre-se no seu código comercial e permita que a ABP os automatize por convenções.",
"DatabaseConnectionTransactionManagement": "Gerenciamento de conexão e transação de banco de dados",
"CorrelationIdTracking": "Rastreamento de ID de correlação",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Vă focusaţi pe codul dumneavoastră şi lăsaţi framework-ul să se ocupe de multi-tenancy pentru dumneavoastră.",
"BootstrapTagHelpersExplanation": "În loc să scrieţi manual detaliile repetate ale componentelor bootstrap, folosiţi tag helperele ABP pentru a simplifica şi profita de inteligenţă. Puteţi folosi cu siguranţă Bootstrap ori de câte ori aveţi nevoie de el.",
"DynamicFormsExplanation": "Formulare dinamice & tag helpere de intrare pot crea formularul complet dintr-o clasă C# ca model.",
"AuthenticationAuthorizationExplanation": "Opţiuni variate de autentificare şi autorizare integrate cu ASP.NET Core Identity & IdentityServer4. Furnizează un sistem de permisiuni extensibil şi detaliat.",
"AuthenticationAuthorizationExplanation": "Opţiuni variate de autentificare şi autorizare integrate cu ASP.NET Core Identity & OpenIddict. Furnizează un sistem de permisiuni extensibil şi detaliat.",
"CrossCuttingConcernsExplanation": "Nu vă repetaţi pentru a implementa din nou şi din nou toate aceste lucruri obişniuite. Concentraţi-vă pe codul dumneavoastră de business şi lăsaţi ABP să le automatizeze prin convenţii.",
"DatabaseConnectionTransactionManagement": "Conectare la baza de date & Gestionarea tranzacţiilor",
"CorrelationIdTracking": "Correlation-Id Tracking",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ru.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Вы сосредотачиваетесь на своем бизнес-коде и позволяете фреймворку обрабатывать мультитенантность от вашего имени.",
"BootstrapTagHelpersExplanation": "Вместо того, чтобы вручную писать повторяющиеся детали компонентов начальной загрузки, используйте помощники тегов ABP, чтобы упростить его и воспользоваться преимуществами intellisense. Вы определенно можете использовать Bootstrap, когда вам это нужно.",
"DynamicFormsExplanation": "Помощники динамических форм и тегов ввода могут создавать полную форму из класса C # в качестве модели.",
"AuthenticationAuthorizationExplanation": "Расширенные возможности аутентификации и авторизации, интегрированные в ASP.NET Core Identity и IdentityServer4. Предоставляет расширяемую и подробную систему разрешений.",
"AuthenticationAuthorizationExplanation": "Расширенные возможности аутентификации и авторизации, интегрированные в ASP.NET Core Identity и OpenIddict. Предоставляет расширяемую и подробную систему разрешений.",
"CrossCuttingConcernsExplanation": "Не повторяйте себя, чтобы реализовать все эти обычные вещи снова и снова. Сосредоточьтесь на своем бизнес-коде и позвольте ABP автоматизировать их по соглашениям.",
"DatabaseConnectionTransactionManagement": "Подключение к базе данных и управление транзакциями",
"CorrelationIdTracking": "Отслеживание корреляционных идентификаторов",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sk.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Sústreďte sa na svoj biznis kód a nechajte framework, aby sa vo vašom mene postaral o multitenantnosť.",
"BootstrapTagHelpersExplanation": "Namiesto ručného písania opakujúcich sa bootstrap komponentov, použite ABP tag pomocníka na zjednodušenie a využitie výhod intellisense. Bootstrap určite využijete vždy, keď ho budete potrebovať.",
"DynamicFormsExplanation": "Dynamické formuláre & vstup Tag pomocníka môžu vytvoriť kompletný formulár z C# triedy ako modelu.",
"AuthenticationAuthorizationExplanation": "Bohaté možnosti overovania & autorizácie integrované do ASP.NET Core Identity & IdentityServer4. Poskytuje rozšíriteľný a podrobný systém oprávnení.",
"AuthenticationAuthorizationExplanation": "Bohaté možnosti overovania & autorizácie integrované do ASP.NET Core Identity & OpenIddict. Poskytuje rozšíriteľný a podrobný systém oprávnení.",
"CrossCuttingConcernsExplanation": "Neopakujte sa pri implementácii všetkých týchto bežných vecí znova a znova. Zamerajte sa na svoj biznis kód a nechajte ich automatizovať pomocou konvencií.",
"DatabaseConnectionTransactionManagement": "Pripojenie k databáze & správa transakcií",
"CorrelationIdTracking": "Sledovanie korelačnej identifikácie",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sl.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Osredotočite se na svojo poslovno kodo in dovolite, da okvir obravnava večnajemne storitve v vašem imenu.",
"BootstrapTagHelpersExplanation": "Namesto ročnega pisanja ponavljajočih se podrobnosti komponent zagonskega zagona, uporabite pomočnike oznak ABP, da ga poenostavite in izkoristite prednosti intellisense. Vsekakor lahko uporabite Bootstrap, kadar koli ga potrebujete.",
"DynamicFormsExplanation": "Pomočniki za dinamične oblike in oznake za vnos lahko ustvarijo celoten obrazec iz razreda C# kot model.",
"AuthenticationAuthorizationExplanation": "Bogate možnosti preverjanja pristnosti in avtorizacije, integrirane v ASP.NET Core Identity & IdentityServer4. Zagotavlja razširljiv in podroben sistem dovoljenj.",
"AuthenticationAuthorizationExplanation": "Bogate možnosti preverjanja pristnosti in avtorizacije, integrirane v ASP.NET Core Identity & OpenIddict. Zagotavlja razširljiv in podroben sistem dovoljenj.",
"CrossCuttingConcernsExplanation": "Ne ponavljajte se, da bi vedno znova izvajali vse te običajne stvari. Osredotočite se na svojo poslovno kodo in dovolite, da jih ABP avtomatizira po dogovorih.",
"DatabaseConnectionTransactionManagement": "Povezava z bazo podatkov in upravljanje transakcij",
"CorrelationIdTracking": "Sledenje korelacijskim ID-jem",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Sen kendi uygulama kodunu odaklan ve bırak framework sizin adınıza multi-tenancy üstesinden gelsin.",
"BootstrapTagHelpersExplanation": "Bootstrap komponentlerinin tekrar eden detaylarını manuel olarak yazmak yerine, Bu işlemi basitleştirmek ve iyileştirme avantajından faydalanmak için ABP'nin tag helperlarını kullanın. Dinamik form bir C# sınıfından model olarak eksiksik form oluşturabilir.",
"DynamicFormsExplanation": "Dinamik form & input tag helpers bir C# sınıfından model olarak eksiksik form oluşturabilir.",
"AuthenticationAuthorizationExplanation": "ASP.NET Core Identity & IdentityServer4 ile entegre edilmiş zengin kimlik doğrulama ve yetkilendirme opsiyonları. Genişletilebilir ve detaylandırılabilr bir izin sistemi sunar.",
"AuthenticationAuthorizationExplanation": "ASP.NET Core Identity & OpenIddict ile entegre edilmiş zengin kimlik doğrulama ve yetkilendirme opsiyonları. Genişletilebilir ve detaylandırılabilr bir izin sistemi sunar.",
"CrossCuttingConcernsExplanation": "Tüm bu ortak şeyleri geliştirmek için kendini sürekli tekrar etme. Kendi iş koduna odaklan ve bırak ABP bunları kurallar ile otomatik hale getirsin.",
"DatabaseConnectionTransactionManagement": "Veritabanı Bğlantısı & İşlem Yönetimi",
"CorrelationIdTracking": "Correlation-Id Tracking",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/vi.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "Bạn tập trung vào mã doanh nghiệp của mình và để khuôn khổ xử lý việc thuê nhiều người thay cho bạn.",
"BootstrapTagHelpersExplanation": "Thay vì viết thủ công các chi tiết lặp lại của các thành phần bootstrap, hãy sử dụng trình trợ giúp thẻ của ABP để đơn giản hóa nó và tận dụng lợi thế của intellisense. Bạn chắc chắn có thể sử dụng Bootstrap bất cứ khi nào bạn cần.",
"DynamicFormsExplanation": "Trình trợ giúp biểu mẫu động & thẻ nhập có thể tạo biểu mẫu hoàn chỉnh từ lớp C # làm mô hình.",
"AuthenticationAuthorizationExplanation": "Các tùy chọn xác thực & ủy quyền phong phú được tích hợp vào ASP.NET Core Identity & IdentityServer4. Cung cấp hệ thống quyền chi tiết và có thể mở rộng.",
"AuthenticationAuthorizationExplanation": "Các tùy chọn xác thực & ủy quyền phong phú được tích hợp vào ASP.NET Core Identity & OpenIddict. Cung cấp hệ thống quyền chi tiết và có thể mở rộng.",
"CrossCuttingConcernsExplanation": "Đừng lặp lại chính mình để thực hiện lại tất cả những thứ phổ biến này. Tập trung vào mã doanh nghiệp của bạn và để ABP tự động hóa chúng theo quy ước.",
"DatabaseConnectionTransactionManagement": "Kết nối cơ sở dữ liệu & Quản lý giao dịch",
"CorrelationIdTracking": "Theo dõi Id tương quan",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "你专注于业务代码,并让该框架为你处理多租户.",
"BootstrapTagHelpersExplanation": "与其手动编写重复细节的bootstrap组件,不如使用ABP的tag helper来简化它并利用智能感知.你当然也可以在需要时直接使用Bootstrap.",
"DynamicFormsExplanation": "动态表单和tag helpers可从作为模型的C#类创建完整的表单.",
"AuthenticationAuthorizationExplanation": "集成到ASP.NET Core Identity和IdentityServer4的丰富身份验证和授权选项.提供可扩展且详细的权限系统.",
"AuthenticationAuthorizationExplanation": "集成到ASP.NET Core Identity和OpenIddict的丰富身份验证和授权选项.提供可扩展且详细的权限系统.",
"CrossCuttingConcernsExplanation": "不要重复自己一次又一次地实现所有这些常见的东西.专注于你的业务代码,并让ABP按照约定自动执行.",
"DatabaseConnectionTransactionManagement": "数据库连接和事务管理",
"CorrelationIdTracking": "关联ID跟踪",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json

@ -122,7 +122,7 @@
"MultiTenancyExplanation4": "您專注於業務邏輯,並讓該框架為您處理多租戶.",
"BootstrapTagHelpersExplanation": "與其手動撰寫重複細節的bootstrap組件,不如使用ABP的tag helper來簡化它並利用自動完成.您當然也可以在需要時直接使用Bootstrap.",
"DynamicFormsExplanation": "動態表單和tag helpers可以利用C#類別做為模型來建立完整的表單.",
"AuthenticationAuthorizationExplanation": "整合到ASP.NET Core Identity和IdentityServer4的豐富身份驗證和授權選項.提供可擴展且詳細的權限系統.",
"AuthenticationAuthorizationExplanation": "整合到ASP.NET Core Identity和OpenIddict的豐富身份驗證和授權選項.提供可擴展且詳細的權限系統.",
"CrossCuttingConcernsExplanation": "部要重複資幾一次又一次地實作所有這寫常見的東西.專注於您的業務邏輯,並讓ABP按照習慣自動執行.",
"DatabaseConnectionTransactionManagement": "資料庫連接和交易管理",
"CorrelationIdTracking": "關聯ID追蹤",

84
docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/POST.md

@ -0,0 +1,84 @@
# ABP.IO Platform 8.0 Has Been Released Based on .NET 8.0
Today, [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 8.0 versions have been released based on [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0).
## What's New With Version 8.0?
All the new features were explained in detail in the [8.0 RC Announcement Post](https://blog.abp.io/abp/announcing-abp-8-0-release-candidate), so there is no need to review them again. You can check it out for more details.
## Getting Started with 8.0
### Creating New Solutions
You can create a new solution with the ABP Framework version 8.0 by either using the `abp new` command or generating the CLI command on the [get started page](https://abp.io/get-started).
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for more.
### How to Upgrade an Existing Solution
#### Install/Update the ABP CLI
First, install the ABP CLI or upgrade it to the latest version.
If you haven't installed it yet:
```bash
dotnet tool install -g Volo.Abp.Cli
```
To update the existing CLI:
```bash
dotnet tool update -g Volo.Abp.Cli
```
#### Upgrading Existing Solutions with the ABP Update Command
[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:
```bash
abp update
```
Run this command in the root folder of your solution.
## Migration Guides
There are breaking changes in this version that may affect your application.
Please see the following migration documents if you are upgrading from v7.x or earlier:
* [ABP Framework 7.x to 8.0 Migration Guide](https://docs.abp.io/en/abp/8.0/Migration-Guides/Abp-8_0)
* [ABP Commercial 7.x to 8.0 Migration Guide](https://docs.abp.io/en/commercial/8.0/migration-guides/v8_0)
## Community News
### We were at China .NET Conf 2023
China's most influential .NET event officially kicked off on December 16, 2023. The conference has invited 30+ technical experts from various fields to share the new features of .NET 8, full-stack Blazor, AI, .NET MAUI, and more...
![](abp-china-team.jpeg)
As one of the community partners of .NET Conf China 2023, our ABP.IO China team was at the event. At the event, we showed developers the latest news and related updates on ABP.IO.
Through this event, we gained a lot and felt the enthusiasm and support of the developers community for ABP.IO. If you want to learn more, we have shared our impressions and takeaways in a blog post, which you can find at [https://blog.abp.io/abp/ABP-at-China-NET-Conf-2023](https://blog.abp.io/abp/ABP-at-China-NET-Conf-2023).
### ABP Commercial Won 5 Recognitions from Gartner
![](awards.jpeg)
2023 was the year for ABP.IO to strive with the community. On top of last year's [Software Advice's Front Runner of Application Development in 2022](https://blog.abp.io/abp/abpcommercial-2022-front-runner-in-app-development-category) and [GetApp's Application Development Category Leader in 2022](https://blog.abp.io/abp/abpcommercial-2022-category-leader-in-app-development-category), we won **5 awards** this year from **Gartner**!
> If you are interested in these awards and want to learn more, you can check out our [blog post](https://blog.abp.io/abp/ABP-Commercial-Won-5-Recognitions-from-Gartner-in-2023)!
### New ABP Community Posts
There are exciting articles contributed by the ABP community, as always. I will highlight some of them here:
* [Performance Optimization of .NET-based application](https://community.abp.io/posts/performance-optimization-of-.netbased-and-also-abpbased-application-pmdwhwxc) by [Leon Košak](https://github.com/leonkosak)
* [Video: ABP Framework Consuming HTTP APIs from a .NET Client](https://community.abp.io/videos/abp-framework-consuming-http-apis-from-a-.net-client-uzul9og4) by [Hamza Albreem](https://github.com/braim23)
Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/articles/submit) to the ABP Community.
## About the Next Version
The next feature version will be 8.1. You can follow the [release planning here](https://github.com/abpframework/abp/milestones). Please [submit an issue](https://github.com/abpframework/abp/issues/new) if you have any problems with this version.

BIN
docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/abp-china-team.jpeg

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

BIN
docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/awards.jpeg

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
docs/en/Blog-Posts/2023-12-20 v8_0_Release_Stable/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

18
docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md

@ -2,7 +2,7 @@
A new .NET version was released on November 14, 2023 and ABP 8.0 RC.1 shipped based on .NET 8.0 just after Microsoft's .NET 8.0 release. Therefore, it's a good time to see what we need to do to upgrade our existing projects to .NET 8.0.
Despite all the related dependency upgrades and changes made on ABP Framework and ABP Commercial sides, we still need to make some changes. Let's see the required actions that need to be taken in the following sections.
Despite all the related dependency upgrades and changes made on the ABP Framework and ABP Commercial sides, we still need to make some changes. Let's see the required actions that need to be taken in the following sections.
## Installing the .NET 8.0 SDK
@ -52,7 +52,7 @@ For example, you can update the ASP.NET Core image as follows:
```diff
- FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim AS base
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0
```
You can check the related images from Docker Hub and update them accordingly:
@ -63,22 +63,28 @@ You can check the related images from Docker Hub and update them accordingly:
## Upgrading Your Existing Projects to ABP 8.0
Updating your application to ABP 8.0 is pretty straight-forward. You first need to upgrade the ABP CLI to version `8.0.0-rc.1` using a command line terminal:
Updating your application to ABP 8.0 is pretty straight-forward. You first need to upgrade the ABP CLI to version `8.0.0` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 8.0.0-rc.1
dotnet tool update Volo.Abp.Cli -g --version 8.0.0
````
**or install** it if you haven't before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 8.0.0-rc.1
dotnet tool install Volo.Abp.Cli -g --version 8.0.0
````
Then, you can use the `abp update` command to update all the ABP related NuGet and NPM packages in your solution:
```bash
abp update --version 8.0.0-rc.1
abp update --version 8.0.0
```
Also, if you are using ABP Commercial, you can update the ABP Suite version with the following command:
```bash
abp suite update --version 8.0.0
```
After that, you need to check the migration guide documents, listed below:

10
docs/en/Entity-Cache.md

@ -45,13 +45,13 @@ public class ProductAppService : ApplicationService, IProductAppService
}
```
> Note that we've used the `ObjectMapper` service to map from `Product` to `ProductDto`. You should configure that [object mapping](Object-To-Object-Mapping.md) to make that example service properly works.
> Note that we've used the `ObjectMapper` service to map from `Product` to `ProductDto`. You should configure that [object mapping](Object-To-Object-Mapping.md) to make that example service properly work.
That's all. The cache name (in the distributed cache server) will be full name (with namespace) of the `Product` class. You can use the `[CacheName]` attribute to change it. Please refer to the [caching document](Caching.md) for details.
That's all. The cache name (in the distributed cache server) will be the full name (with namespace) of the `Product` class. You can use the `[CacheName]` attribute to change it. Please refer to the [caching document](Caching.md) for details.
## Using a Cache Item Class
In the previous section, we've directly cached the `Product` entity. In that case, the `Product` class must be serializable to JSON (and deserializable from JSON). Sometimes that might not be possible or you may want to use another class to store the cache data. For example, we may want to use the `ProductDto` class instead of the `Product` class for the cached object if the `Product` entity.
In the previous section, we've directly cached the `Product` entity. In that case, the `Product` class must be serializable to JSON (and deserializable from JSON). Sometimes that might not be possible or you may want to use another class to store the cache data. For example, we may want to use the `ProductDto` class instead of the `Product` class for the cached object of the `Product` entity.
Assume that we've created a `ProductDto` class as shown below:
@ -102,7 +102,7 @@ public class ProductAppService : ApplicationService, IProductAppService
}
```
Notice that the `_productCache.GetAsync` method already returns a `ProductDto` object, so we could directly return it from out application service.
Notice that the `_productCache.GetAsync` method already returns a `ProductDto` object, so we could directly return it from our application service.
## Configuration
@ -122,7 +122,7 @@ context.Services.AddEntityCache<Product, ProductDto, Guid>(
## Additional Notes
* Entity classes should be serializable/deserializable to/from JSON to be cached (because it's serialized to JSON when saving in the [Distributed Cache](Caching.md)). If your entity class is not serializable, you can consider using a cache-item/DTO class instead, as explained before.
* Entity Caching System is designed as **read-only**. You should use the standard [repository](Repositories.md) methods to manipulate the entity if you need. If you need to manipulate (update) the entity, do not get it from the entity cache. Instead, read it from the repository, change it and update using the repository.
* Entity Caching System is designed as **read-only**. You should use the standard [repository](Repositories.md) methods to manipulate the entity if you need to. If you need to manipulate (update) the entity, do not get it from the entity cache. Instead, read it from the repository, change it and update using the repository.
## See Also

72
docs/en/Entity-Framework-Core-Oracle-Devart.md

@ -60,6 +60,78 @@ This will scaffold a new migration for Oracle.
Run the `.DbMigrator` project to create the database, apply the changes and seed the initial data.
## ORA-12899: value too large for column fix
Oracle limits strings to `NVARCHAR2(2000)` when the migration is created. Some of the entity properties may extend it. You can check the known and reported properties of ABP modules entities that can extend this limit. To prevent this problem, you need to convert the `string` type to `long` type first and generate a new migration. Then convert the `long` type to `clob` type with maximum length.
### First Migration
Update you application DbContext `OnModelCreating` method:
```csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.Entity<OpenIddictToken>(b =>
{
b.Property(q => q.Payload).HasColumnType("long").HasMaxLength(int.MaxValue);
});
builder.Entity<AuditLog>(b =>
{
b.Property(x => x.Exceptions).HasColumnType("long").HasMaxLength(int.MaxValue);
});
builder.Entity<AuditLogAction>(b =>
{
b.Property(x => x.Parameters).HasColumnType("long").HasMaxLength(int.MaxValue);
});
/* Configure your own tables/entities inside here */
}
```
Create a new migration using dotnet tooling under EntityFrameworkCore layer of your solution: `dotnet ef migrations add Oracle_Long_Conversion`
### Second Migration
Update you application DbContext `OnModelCreating` method:
```csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.Entity<OpenIddictToken>(b =>
{
b.Property(q => q.Payload).HasColumnType("clob").HasMaxLength(4000);
});
builder.Entity<AuditLog>(b =>
{
b.Property(x => x.Exceptions).HasColumnType("clob").HasMaxLength(4000);
});
builder.Entity<AuditLogAction>(b =>
{
b.Property(x => x.Parameters).HasColumnType("clob").HasMaxLength(4000);
});
/* Configure your own tables/entities inside here */
}
```
Create a new migration using dotnet tooling under EntityFrameworkCore layer of your solution: `dotnet ef migrations add Oracle_Clob_Conversion`
Run DbMigrator (or use dotnet tooling) to migrate the oracle database.
## Run the Application
It is ready. Just run the application and enjoy coding.

70
docs/en/Entity-Framework-Core-Oracle-Official.md

@ -55,6 +55,76 @@ This will scaffold a new migration for Oracle.
Run the `.DbMigrator` project to create the database, apply the changes and seed the initial data.
## ORA-12899: value too large for column fix
Oracle limits strings to `NVARCHAR2(2000)` when the migration is created. Some of the entity properties may extend it. You can check the known and reported properties of ABP modules entities that can extend this limit. To prevent this problem, you need to convert the `string` type to `long` type first and generate a new migration. Then convert the `long` type to `clob` type with maximum length.
### First Migration
Update you application DbContext `OnModelCreating` method:
```csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.Entity<OpenIddictToken>(b =>
{
b.Property(q => q.Payload).HasColumnType("long").HasMaxLength(int.MaxValue);
});
builder.Entity<AuditLog>(b =>
{
b.Property(x => x.Exceptions).HasColumnType("long").HasMaxLength(int.MaxValue);
});
builder.Entity<AuditLogAction>(b =>
{
b.Property(x => x.Parameters).HasColumnType("long").HasMaxLength(int.MaxValue);
});
/* Configure your own tables/entities inside here */
}
```
Create a new migration using dotnet tooling under EntityFrameworkCore layer of your solution: `dotnet ef migrations add Oracle_Long_Conversion`
### Second Migration
Update you application DbContext `OnModelCreating` method:
```csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.Entity<OpenIddictToken>(b =>
{
b.Property(q => q.Payload).HasColumnType("clob").HasMaxLength(4000);
});
builder.Entity<AuditLog>(b =>
{
b.Property(x => x.Exceptions).HasColumnType("clob").HasMaxLength(4000);
});
builder.Entity<AuditLogAction>(b =>
{
b.Property(x => x.Parameters).HasColumnType("clob").HasMaxLength(4000);
});
/* Configure your own tables/entities inside here */
}
```
Create a new migration using dotnet tooling under EntityFrameworkCore layer of your solution: `dotnet ef migrations add Oracle_Clob_Conversion`
Run DbMigrator (or use dotnet tooling) to migrate the oracle database.
## Run the Application
It is ready. Just run the application and enjoy coding.

2
docs/en/Tutorials/Part-1.md

@ -368,7 +368,7 @@ public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;

14
docs/en/Tutorials/Part-10.md

@ -614,19 +614,19 @@ using System.Threading.Tasks;
using Acme.BookStore.Authors;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]{{end}}
public class BookAppService_Tests : BookStoreApplicationTestBase
public abstract class BookAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IBookAppService _bookAppService;
private readonly IAuthorAppService _authorAppService;
public BookAppService_Tests()
protected BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
_authorAppService = GetRequiredService<IAuthorAppService>();
@ -643,7 +643,7 @@ public class BookAppService_Tests : BookStoreApplicationTestBase
//Assert
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Name == "1984" &&
b.AuthorName == "George Orwell");
b.AuthorName == "George Orwell");
}
[Fact]
@ -788,7 +788,7 @@ public class CreateModalModel : BookStorePageModel
[Required]
[StringLength(128)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;
@ -871,7 +871,7 @@ public class EditModalModel : BookStorePageModel
[Required]
[StringLength(128)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;

55
docs/en/Tutorials/Part-4.md

@ -82,19 +82,18 @@ using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
{{end}}
public class BookAppService_Tests : BookStoreApplicationTestBase
public abstract class BookAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IBookAppService _bookAppService;
public BookAppService_Tests()
protected BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
}
@ -114,6 +113,41 @@ public class BookAppService_Tests : BookStoreApplicationTestBase
}
````
{{if DB == "EF"}}
Add a new implementation class of `BookAppService_Tests` class, named `EfCoreBookAppService_Tests` in the `EntityFrameworkCore\Applications\Books` namespace (folder) of the `Acme.BookStore.EntityFrameworkCore.Tests` project:
````csharp
using Acme.BookStore.Books;
using Xunit;
namespace Acme.BookStore.EntityFrameworkCore.Applications.Books;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class EfCoreBookAppService_Tests : BookAppService_Tests<BookStoreEntityFrameworkCoreTestModule>
{
}
````
{{end}}
{{if DB == "Mongo"}}
Add a new implementation class of `BookAppService_Tests` class, named `MongoDBBookAppService_Tests` in the `MongoDb\Applications\Books` namespace (folder) of the `Acme.BookStore.MongoDB.Tests` project:
````csharp
using Acme.BookStore.MongoDB;
using Acme.BookStore.Books;
using Xunit;
namespace Acme.BookStore.MongoDb.Applications.Books;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class MongoDBBookAppService_Tests : BookAppService_Tests<BookStoreMongoDbTestModule>
{
}
````
{{end}}
* `Should_Get_List_Of_Books` test simply uses `BookAppService.GetListAsync` method to get and check the list of books.
* We can safely check the book "1984" by its name, because we know that this books is available in the database since we've added it in the seed data.
@ -174,19 +208,18 @@ using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
{{end}}
public class BookAppService_Tests : BookStoreApplicationTestBase
public abstract class BookAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IBookAppService _bookAppService;
public BookAppService_Tests()
protected BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
}
@ -203,7 +236,7 @@ public class BookAppService_Tests : BookStoreApplicationTestBase
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Name == "1984");
}
[Fact]
public async Task Should_Create_A_Valid_Book()
{

16
docs/en/Tutorials/Part-6.md

@ -75,9 +75,9 @@ public class Author : FullAuditedAggregateRoot<Guid>
internal Author(
Guid id,
[NotNull] string name,
string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
string? shortBio = null)
: base(id)
{
SetName(name);
@ -85,13 +85,13 @@ public class Author : FullAuditedAggregateRoot<Guid>
ShortBio = shortBio;
}
internal Author ChangeName([NotNull] string name)
internal Author ChangeName(string name)
{
SetName(name);
return this;
}
private void SetName([NotNull] string name)
private void SetName(string name)
{
Name = Check.NotNullOrWhiteSpace(
name,
@ -146,9 +146,9 @@ public class AuthorManager : DomainService
}
public async Task<Author> CreateAsync(
[NotNull] string name,
string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
string? shortBio = null)
{
Check.NotNullOrWhiteSpace(name, nameof(name));
@ -167,8 +167,8 @@ public class AuthorManager : DomainService
}
public async Task ChangeNameAsync(
[NotNull] Author author,
[NotNull] string newName)
Author author,
string newName)
{
Check.NotNull(author, nameof(author));
Check.NotNullOrWhiteSpace(newName, nameof(newName));

52
docs/en/Tutorials/Part-8.md

@ -123,12 +123,12 @@ public class CreateAuthorDto
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
````
@ -146,12 +146,12 @@ public class UpdateAuthorDto
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
````
@ -481,18 +481,17 @@ Finally, we can write some tests for the `IAuthorAppService`. Add a new class, n
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Acme.BookStore.Authors;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
{{end}}
public class AuthorAppService_Tests : BookStoreApplicationTestBase
public abstract class AuthorAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IAuthorAppService _authorAppService;
public AuthorAppService_Tests()
protected AuthorAppService_Tests()
{
_authorAppService = GetRequiredService<IAuthorAppService>();
}
@ -554,6 +553,41 @@ public class AuthorAppService_Tests : BookStoreApplicationTestBase
}
````
{{if DB == "EF"}}
Add a new implementation class of `AuthorAppService_Tests` class, named `EfCoreAuthorAppService_Tests` in the `EntityFrameworkCore\Applications\Authors` namespace (folder) of the `Acme.BookStore.EntityFrameworkCore.Tests` project:
````csharp
using Acme.BookStore.Authors;
using Xunit;
namespace Acme.BookStore.EntityFrameworkCore.Applications.Authors;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class EfCoreAuthorAppService_Tests : AuthorAppService_Tests<BookStoreEntityFrameworkCoreTestModule>
{
}
````
{{end}}
{{if DB == "Mongo"}}
Add a new implementation class of `AuthorAppService_Tests` class, named `MongoDBAuthorAppService_Tests` in the `MongoDb\Applications\Authors` namespace (folder) of the `Acme.BookStore.MongoDB.Tests` project:
````csharp
using Acme.BookStore.MongoDB;
using Acme.BookStore.Authors;
using Xunit;
namespace Acme.BookStore.MongoDb.Applications.Authors;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class MongoDBAuthorAppService_Tests : AuthorAppService_Tests<BookStoreMongoDbTestModule>
{
}
````
{{end}}
Created some tests for the application service methods, which should be clear to understand.
## The Next Part

8
docs/en/Tutorials/Part-9.md

@ -331,14 +331,14 @@ public class CreateModalModel : BookStorePageModel
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[TextArea]
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
}
```
@ -454,14 +454,14 @@ public class EditModalModel : BookStorePageModel
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[TextArea]
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
}
```

130
docs/en/UI/Angular/Authorization.md

@ -1,9 +1,9 @@
## Authorization in Angular UI
OAuth is preconfigured in Angular application templates. So, when you start a project using the CLI (or Suite, for that matter), authorization already works. ABP Angular UI packages are using [angular-oauth2-oidc library](https://github.com/manfredsteyer/angular-oauth2-oidc#logging-in) for managing OAuth in the Angular client.
OAuth is preconfigured in Angular application templates. So, when you start a project using the CLI (or Suite, for that matter), authorization already works. ABP Angular UI packages are using [angular-oauth2-oidc library](https://github.com/manfredsteyer/angular-oauth2-oidc#logging-in) for managing OAuth in the Angular client.
You can find **OAuth configuration** in the _environment.ts_ files.
### Authorization Code Flow
### Authorization Code Flow
```js
import { Config } from '@abp/ng.core';
@ -29,7 +29,6 @@ export const environment = {
This configuration results in an [OAuth authorization code flow with PKCE](https://tools.ietf.org/html/rfc7636).
According to this flow, the user is redirected to an external login page which is built with MVC. So, if you need **to customize the login page**, please follow [this community article](https://community.abp.io/articles/how-to-customize-the-login-page-for-mvc-razor-page-applications-9a40f3cd).
### Resource Owner Password Flow
If you have used the [Angular UI account module](./Account-Module) in your project, you can switch to the resource owner password flow by changing the OAuth configuration in the _environment.ts_ files as shown below:
@ -52,3 +51,128 @@ export const environment = {
```
According to this flow, the user is redirected to the login page in the account module.
### Error Filtering
In [AuthFlowStrategy](https://github.com/abpframework/abp/blob/21e70fd66154d4064d03b1a438f20a2e4318715e/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts#L24) class, there is a method called `listenToOauthErrors` that listens to `OAuthErrorEvent` errors. This method clears the localStorage for OAuth keys. However, in certain cases, we might want to skip this process. To achieve this, we can use the `AuthErrorFilterService`.
The `AuthErrorFilterService` is an abstract service that needs to be replaced with a custom implementation
> By default, this service is replaced in the `@abp/ng.oauth` package
**Usage**
1.Create an auth-filter.provider
```js
import { APP_INITIALIZER, inject } from '@angular/core';
import { AuthErrorFilter, AuthErrorEvent, AuthErrorFilterService } from '@abp/ng.core';
import { eCustomersAuthFilterNames } from '../enums';
export const CUSTOMERS_AUTH_FILTER_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureAuthFilter, multi: true },
];
type Reason = object & { error: { grant_type: string | undefined } };
function configureAuthFilter() {
const errorFilterService = inject(
AuthErrorFilterService<AuthErrorFilter<AuthErrorEvent>, AuthErrorEvent>,
);
const filter: AuthErrorFilter = {
id: eCustomersAuthFilterNames.LinkedUser,
executable: true,
execute: (event: AuthErrorEvent) => {
const { reason } = event;
const {
error: { grant_type },
} = <Reason>(reason || {});
return !!grant_type && grant_type === eCustomersAuthFilterNames.LinkedUser;
},
};
return () => errorFilterService.add(filter);
}
```
- `AuthErrorFilter:` is a model for filter object and it have 3 properties
- `id:` a unique key in the list for the filter object
- `executable:` a status for the filter object. If it's false then it won't work, yet it'll stay in the list
- `execute:` a function that stores the skip logic
2.Add to the FeatureConfigModule
```js
import { ModuleWithProviders, NgModule } from "@angular/core";
import { CUSTOMERS_AUTH_FILTER_PROVIDER } from "./providers/auth-filter.provider";
@NgModule()
export class CustomersConfigModule {
static forRoot(): ModuleWithProviders<CustomersConfigModule> {
return {
ngModule: CustomersConfigModule,
providers: [CUSTOMERS_AUTH_FILTER_PROVIDER],
};
}
}
```
Now it'll skip the clearing of OAuth storage keys for `LinkedUser` grant_type if any `OAuthErrorEvent` occurs
**Replace with custom implementation**
- Use the `AbstractAuthErrorFilter<T,E>` class for signs of process.
**Example**
`my-auth-error-filter.service.ts`
```js
import { Injectable, signal } from '@angular/core';
import { MyAuthErrorEvent } from 'angular-my-auth-oidc';
import { AbstractAuthErrorFilter, AuthErrorFilter } from '@abp/ng.core';
@Injectable({ providedIn: 'root' })
export class OAuthErrorFilterService extends AbstractAuthErrorFilter<
AuthErrorFilter<MyAuthErrorEvent>,
MyAuthErrorEvent
> {
protected readonly _filters = signal<Array<AuthErrorFilter<MyAuthErrorEvent>>>([]);
readonly filters = this._filters.asReadonly();
get(id: string): AuthErrorFilter<MyAuthErrorEvent> {
return this._filters().find(({ id: _id }) => _id === id);
}
add(filter: AuthErrorFilter<MyAuthErrorEvent>): void {
this._filters.update(items => [...items, filter]);
}
patch(item: Partial<AuthErrorFilter<MyAuthErrorEvent>>): void {
const _item = this.filters().find(({ id }) => id === item.id);
if (!_item) {
return;
}
Object.assign(_item, item);
}
remove(id: string): void {
const item = this.filters().find(({ id: _id }) => _id === id);
if (!item) {
return;
}
this._filters.update(items => items.filter(({ id: _id }) => _id !== id));
}
run(event: MyAuthErrorEvent): boolean {
return this.filters()
.filter(({ executable }) => !!executable)
.map(({ execute }) => execute(event))
.some(item => item);
}
}
```

134
docs/en/UI/Angular/Component-Replacement.md

@ -77,6 +77,140 @@ export class AppComponent {
![Layout Components](./images/layout-components.png)
### How to Add a New Layout Component
To add a new layout component, you need to follow these steps:
#### Step 1: Create a New Angular Component
This component should have a 'router-outlet' for dynamic content loading. You can create a new component using the Angular CLI. Run the following command in your terminal:
```bash
ng generate component new-layout
```
This command will create a new component named `new-layout`. Now, open the new-layout.component.html file and add a `router-outlet` to it:
```html
<router-outlet></router-outlet>
```
This 'router-outlet' will act as a placeholder that Angular dynamically fills based on the current router state.
note: (don't forget: you should add the app in the app.module.ts file)
#### Step 2: Define a Variable for the Layout Component
Although this step is optional, it can be useful if you're going to use the layout component's value multiple times. You can define a variable for the layout component like this:
```javascript
export const eCustomLayout = {
key: 'CustomLayout',
component: 'CustomLayoutComponent',
};
```
In this variable, `key` is a unique identifier for the layout component, and `component` is the name of the layout component.
You can use this variable when you need to refer to the layout component.
#### Step 3: Add the Layout Component to the ABP Replaceable-System
Next, you need to add the new layout component to the `ReplaceableComponentsService`. This service allows you to replace a component with another one dynamically.
You can do this by defining a provider for `APP_INITIALIZER` that uses a factory function. In this function, you inject the `ReplaceableComponentsService` and use its `add` method to add the new layout component.
Here's how you can do it:
```javascript
export const CUSTOM_LAYOUT_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureLayoutFn, deps: [ReplaceableComponentsService], multi: true },
];
function configureLayoutFn() {
const service= inject( ReplaceableComponentsService)
return () =>{
service.add({
key: eCustomLayout.component,
component: CustomLayoutComponent,
})
}
}
```
In this code, `configureLayoutFn` is a factory function that adds the new layout component to the `ReplaceableComponentsService`. The `APP_INITIALIZER` provider runs this function when the application starts.
note: (don't forget: you should add the CUSTOM_LAYOUT_PROVIDERS in the app.module.ts file)
#### Step 4: Define the Application's Dynamic Layouts
Finally, you need to define the application's dynamic layouts. This is a map where the keys are the layout keys and the values are the layout components.
You can add the new layout to the existing layouts like this:
```javascript
export const myDynamicLayouts = new Map<string, string>([...DEFAULT_DYNAMIC_LAYOUTS, [eCustomLayout.key, eCustomLayout.component]]);
```
#### Step 5: Pass the Dynamic Layouts to the CoreModule
The final step is to pass the dynamic layouts to the `CoreModule` using the `forRoot` method. This method allows you to configure the module with a static method.
Here's how you can do it:
```javascript
@NgModule({
declarations: [AppComponent],
imports: [
// other imports...
CoreModule.forRoot({
dynamicLayouts: myDynamicLayouts,
environment,
registerLocaleFn: registerLocale(),
}),
// other imports...
NewLayoutComponent
],
providers: [APP_ROUTE_PROVIDER, CUSTOM_LAYOUT_PROVIDERS],
bootstrap: [AppComponent],
})
export class AppModule {}
```
In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `CoreModule` using the `forRoot` method.
Now that you have defined the new layout, you can use it in the router definition. You do this by adding a new route that uses the new layout.
Here's how you can do it:
```javascript
// route.provider.ts
import { eCustomLayout } from './custom-layout/custom-layout.provider';
import { RoutesService, eLayoutType } from '@abp/ng.core';
import { APP_INITIALIZER } from '@angular/core';
export const APP_ROUTE_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
function configureRoutes(routes: RoutesService) {
return () => {
routes.add([
{
path: '/',
name: '::Menu:Home',
iconClass: 'fas fa-home',
order: 1,
layout: eLayoutType.application,
},
{
path: '/dashboard',
name: '::Menu:Dashboard',
iconClass: 'fas fa-chart-line',
order: 2,
layout: eCustomLayout.key as eLayoutType,
requiredPolicy: 'MyProjectName.Dashboard.Host || MyProjectName.Dashboard.Tenant',
},
]);
};
}
```
#### How to Replace LogoComponent
![LogoComponent](./images/logo-component.png)

2
docs/en/UI/Common/Utils/Linked-List.md

@ -958,7 +958,7 @@ list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail();
// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}
list.dropByValue(0, (value, searchedValue) => value.x === searchedValue);
list.dropByValueAll(0, (value, searchedValue) => value.x === searchedValue);
// {"x":1} <-> {"x":2} <-> {"x":3}
```

2
docs/zh-Hans/UI/Common/Utils/Linked-List.md

@ -925,7 +925,7 @@ list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail();
// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}
list.dropByValue(0, (value, searchedValue) => value.x === searchedValue);
list.dropByValueAll(0, (value, searchedValue) => value.x === searchedValue);
// {"x":1} <-> {"x":2} <-> {"x":3}
```

7
framework/Volo.Abp.sln

@ -463,6 +463,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Imaging.SkiaSharp"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Imaging.SkiaSharp.Tests", "test\Volo.Abp.Imaging.SkiaSharp.Tests\Volo.Abp.Imaging.SkiaSharp.Tests.csproj", "{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.RemoteServices.Tests", "test\Volo.Abp.RemoteServices.Tests\Volo.Abp.RemoteServices.Tests.csproj", "{DACD4485-61BE-4DE5-ACAE-4FFABC122500}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1381,6 +1383,10 @@ Global
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Release|Any CPU.Build.0 = Release|Any CPU
{DACD4485-61BE-4DE5-ACAE-4FFABC122500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DACD4485-61BE-4DE5-ACAE-4FFABC122500}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DACD4485-61BE-4DE5-ACAE-4FFABC122500}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DACD4485-61BE-4DE5-ACAE-4FFABC122500}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1614,6 +1620,7 @@ Global
{F19A6E0C-F719-4ED9-A024-14E4B8D40883} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{198683D0-7DC6-40F2-B81B-8E446E70A9DE} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{DACD4485-61BE-4DE5-ACAE-4FFABC122500} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

22
framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/Extensions/DependencyInjection/AbpApiVersioningExtensions.cs

@ -1,8 +1,7 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Versioning;
using Asp.Versioning;
using Asp.Versioning.ApplicationModels;
using Volo.Abp.ApiVersioning;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
@ -12,32 +11,37 @@ namespace Microsoft.Extensions.DependencyInjection;
public static class AbpApiVersioningExtensions
{
public static IServiceCollection AddAbpApiVersioning(this IServiceCollection services, Action<ApiVersioningOptions> setupAction)
public static IServiceCollection AddAbpApiVersioning(
this IServiceCollection services,
Action<ApiVersioningOptions>? apiVersioningOptionsSetupAction = null,
Action<MvcApiVersioningOptions>? mvcApiVersioningOptionsSetupAction = null)
{
services.AddTransient<IRequestedApiVersion, HttpContextRequestedApiVersion>();
services.AddTransient<IApiControllerSpecification, AbpConventionalApiControllerSpecification>();
services.AddApiVersioning(setupAction);
apiVersioningOptionsSetupAction ??= _ => { };
mvcApiVersioningOptionsSetupAction ??= _ => { };
services.AddApiVersioning(apiVersioningOptionsSetupAction).AddMvc(mvcApiVersioningOptionsSetupAction);
return services;
}
public static void ConfigureAbp(this ApiVersioningOptions options, AbpAspNetCoreMvcOptions mvcOptions)
public static void ConfigureAbp(this MvcApiVersioningOptions options, AbpAspNetCoreMvcOptions mvcOptions)
{
foreach (var setting in mvcOptions.ConventionalControllers.ConventionalControllerSettings)
{
if (setting.ApiVersionConfigurer == null)
if (setting.MvcApiVersioningConfigurer == null)
{
ConfigureApiVersionsByConvention(options, setting);
}
else
{
setting.ApiVersionConfigurer.Invoke(options);
setting.MvcApiVersioningConfigurer.Invoke(options);
}
}
}
private static void ConfigureApiVersionsByConvention(ApiVersioningOptions options, ConventionalControllerSetting setting)
private static void ConfigureApiVersionsByConvention(MvcApiVersioningOptions options, ConventionalControllerSetting setting)
{
foreach (var controllerType in setting.ControllerTypes)
{

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj

@ -31,7 +31,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" />
<PackageReference Include="Asp.Versioning.Mvc" />
</ItemGroup>
</Project>

5
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -2,19 +2,16 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Asp.Versioning;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.Utils;
using Volo.Abp.DependencyInjection;

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpConventionalApiControllerSpecification.cs

@ -1,3 +1,4 @@
using Asp.Versioning.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.Options;

13
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs

@ -1,12 +1,11 @@
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Versioning;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Asp.Versioning;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc.Conventions;
@ -60,7 +59,7 @@ public class ConventionalControllerSetting
public List<ApiVersion> ApiVersions { get; }
public Action<ApiVersioningOptions>? ApiVersionConfigurer { get; set; }
public Action<MvcApiVersioningOptions>? MvcApiVersioningConfigurer { get; set; }
public ConventionalControllerSetting(
[NotNull] Assembly assembly,
@ -87,7 +86,7 @@ public class ConventionalControllerSetting
ControllerTypes.Add(type);
}
}
public IReadOnlyList<Type> GetControllerTypes()
{
return ControllerTypes.ToImmutableList();
@ -113,14 +112,14 @@ public class ConventionalControllerSetting
return false;
}
private bool IsPreferredApplicationServiceType(Type type)
{
if (ApplicationServiceTypes == ApplicationServiceTypes.ApplicationServices)
{
return !IntegrationServiceAttribute.IsDefinedOrInherited(type);
}
if (ApplicationServiceTypes == ApplicationServiceTypes.IntegrationServices)
{
return IntegrationServiceAttribute.IsDefinedOrInherited(type);
@ -128,4 +127,4 @@ public class ConventionalControllerSetting
return true;
}
}
}

46
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs

@ -29,6 +29,7 @@ public class CliService : ITransientDependency
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected PackageVersionCheckerService PackageVersionCheckerService { get; }
public ICmdHelper CmdHelper { get; }
protected CliVersionService CliVersionService { get; }
public CliService(
ICommandLineArgumentParser commandLineArgumentParser,
@ -36,7 +37,8 @@ public class CliService : ITransientDependency
IServiceScopeFactory serviceScopeFactory,
PackageVersionCheckerService nugetService,
ICmdHelper cmdHelper,
MemoryService memoryService)
MemoryService memoryService,
CliVersionService cliVersionService)
{
_memoryService = memoryService;
CommandLineArgumentParser = commandLineArgumentParser;
@ -44,13 +46,14 @@ public class CliService : ITransientDependency
ServiceScopeFactory = serviceScopeFactory;
PackageVersionCheckerService = nugetService;
CmdHelper = cmdHelper;
CliVersionService = cliVersionService;
Logger = NullLogger<CliService>.Instance;
}
public async Task RunAsync(string[] args)
{
var currentCliVersion = await GetCurrentCliVersionInternalAsync(typeof(CliService).Assembly);
var currentCliVersion = await CliVersionService.GetCurrentCliVersionAsync();
Logger.LogInformation($"ABP CLI {currentCliVersion}");
var commandLineArgs = CommandLineArgumentParser.Parse(args);
@ -248,41 +251,6 @@ public class CliService : ITransientDependency
return assembly.Location.Substring(0, assembly.Location.IndexOf(".store", StringComparison.Ordinal));
}
public async Task<SemanticVersion> GetCurrentCliVersionAsync(Assembly assembly)
{
return await GetCurrentCliVersionInternalAsync(assembly);
}
private async Task<SemanticVersion> GetCurrentCliVersionInternalAsync(Assembly assembly)
{
SemanticVersion currentCliVersion = default;
var consoleOutput = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list -g", out int exitCode));
string line;
while ((line = await consoleOutput.ReadLineAsync()) != null)
{
if (line.StartsWith("volo.abp.cli", StringComparison.InvariantCultureIgnoreCase))
{
var version = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1];
SemanticVersion.TryParse(version, out currentCliVersion);
break;
}
}
if (currentCliVersion == null)
{
// If not a tool executable, fallback to assembly version and treat as dev without updates
// Assembly revisions are not supported by SemVer scheme required for NuGet, trim to {major}.{minor}.{patch}
var assemblyVersion = string.Join(".", assembly.GetFileVersion().Split('.').Take(3));
return SemanticVersion.Parse(assemblyVersion + "-dev");
}
return currentCliVersion;
}
private UpdateChannel GetUpdateChannel(SemanticVersion currentCliVersion)
{
if (!currentCliVersion.IsPrerelease)
@ -332,12 +300,12 @@ public class CliService : ITransientDependency
var toolPathArg = IsGlobalTool(toolPath) ? "-g" : $"--tool-path {toolPath}";
Logger.LogWarning($"A newer {updateChannel.ToString().ToLowerInvariant()} version of the ABP CLI is available: {latestVersion}.");
if (!string.IsNullOrWhiteSpace(message))
{
Logger.LogWarning(message);
}
Logger.LogWarning(string.Empty);
Logger.LogWarning("Update Command: ");

69
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs

@ -12,6 +12,7 @@ using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using NuGet.Versioning;
using Volo.Abp.Cli.GitHub;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.ProjectBuilding.Templates.App;
@ -19,6 +20,7 @@ using Volo.Abp.Cli.ProjectBuilding.Templates.Console;
using Volo.Abp.Cli.ProjectBuilding.Templates.Maui;
using Volo.Abp.Cli.ProjectBuilding.Templates.MvcModule;
using Volo.Abp.Cli.ProjectBuilding.Templates.Wpf;
using Volo.Abp.Cli.Version;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.IO;
@ -37,18 +39,21 @@ public class AbpIoSourceCodeStore : ISourceCodeStore, ITransientDependency
protected ICancellationTokenProvider CancellationTokenProvider { get; }
private readonly CliHttpClientFactory _cliHttpClientFactory;
protected CliVersionService CliVersionService { get; }
public AbpIoSourceCodeStore(
IOptions<AbpCliOptions> options,
IJsonSerializer jsonSerializer,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
ICancellationTokenProvider cancellationTokenProvider,
CliHttpClientFactory cliHttpClientFactory)
CliHttpClientFactory cliHttpClientFactory,
CliVersionService cliVersionService)
{
JsonSerializer = jsonSerializer;
RemoteServiceExceptionHandler = remoteServiceExceptionHandler;
CancellationTokenProvider = cancellationTokenProvider;
_cliHttpClientFactory = cliHttpClientFactory;
CliVersionService = cliVersionService;
Options = options.Value;
Logger = NullLogger<AbpIoSourceCodeStore>.Instance;
@ -63,8 +68,8 @@ public class AbpIoSourceCodeStore : ISourceCodeStore, ITransientDependency
bool skipCache = false)
{
DirectoryHelper.CreateIfNotExists(CliPaths.TemplateCache);
var userSpecifiedVersion = version != null;
var latestVersion = version ?? await GetLatestSourceCodeVersionAsync(name, type, null, includePreReleases);
if (version == null)
{
if (latestVersion == null)
@ -86,14 +91,68 @@ public class AbpIoSourceCodeStore : ISourceCodeStore, ITransientDependency
version = latestVersion;
}
else
var currentCliVersion = await CliVersionService.GetCurrentCliVersionAsync();
var templateVersion = SemanticVersion.Parse(version);
var outputWarning = false;
if (currentCliVersion.Major != templateVersion.Major || currentCliVersion.Minor != templateVersion.Minor)
{
// major and minor version are different
outputWarning = true;
}
else if (currentCliVersion.Major == templateVersion.Major &&
currentCliVersion.Minor == templateVersion.Minor &&
currentCliVersion.Patch < templateVersion.Patch)
{
if (!await IsVersionExists(name, version))
// major and minor version are same but patch version is lower
outputWarning = true;
}
else if(currentCliVersion.Major == templateVersion.Major &&
currentCliVersion.Minor == templateVersion.Minor &&
currentCliVersion.Patch == templateVersion.Patch &&
currentCliVersion.IsPrerelease && templateVersion.IsPrerelease)
{
// major and minor and patch version are same but prerelease version may be lower
var cliRcVersion = currentCliVersion.ReleaseLabels.LastOrDefault();
var templateRcVersion = templateVersion.ReleaseLabels.LastOrDefault();
if (cliRcVersion != null && templateRcVersion != null)
{
throw new Exception("There is no version found with given version: " + version);
if (int.TryParse(cliRcVersion, out var cliRcVersionNumber) && int.TryParse(templateRcVersion, out var templateRcVersionNumber))
{
if (cliRcVersionNumber < templateRcVersionNumber)
{
outputWarning = true;
}
}
}
}
if (outputWarning)
{
version = currentCliVersion.ToString();
Logger.LogWarning(userSpecifiedVersion
? $"The specified template version ({templateVersion}) is different than the CLI version ({currentCliVersion}). This may cause compatibility issues."
: $"The latest template version ({templateVersion}) is different than the CLI version ({currentCliVersion}). This may cause compatibility issues.");
Logger.LogWarning("Please upgrade/downgrade the CLI version to the template version.");
Logger.LogWarning($"> dotnet tool uninstall -g volo.abp.cli");
Logger.LogWarning(!templateVersion.IsPrerelease
? $"> dotnet tool install -g volo.abp.cli --version \"{templateVersion.Major}.{templateVersion.Minor}.*\""
: $"> dotnet tool install -g volo.abp.cli --version {templateVersion}");
if (!userSpecifiedVersion)
{
version = currentCliVersion.ToString();
Logger.LogWarning($"We have changed the template version as the cli version.");
Logger.LogWarning($"New version: {version}");
}
}
if (!await IsVersionExists(name, version))
{
throw new Exception("There is no version found with given version: " + version);
}
var nugetVersion = (await GetTemplateNugetVersionAsync(name, type, version)) ?? version;
if (!string.IsNullOrWhiteSpace(templateSource) && !IsNetworkSource(templateSource))

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs

@ -73,6 +73,7 @@ public class ProjectReferenceReplaceStep : ProjectBuildPipelineStep
private readonly List<FileEntry> _entries;
private readonly bool _isMicroserviceServiceTemplate;
private readonly string _projectName;
protected bool CentralPackageManagement { get; }
protected ProjectReferenceReplacer(
ProjectBuildContext context,
@ -81,6 +82,7 @@ public class ProjectReferenceReplaceStep : ProjectBuildPipelineStep
_entries = context.Files;
_isMicroserviceServiceTemplate = MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(context.Template?.Name);
_projectName = projectName;
CentralPackageManagement = context.Files.Any(x => x.Name.EndsWith("Directory.Packages.props"));
}
public void Run()
@ -165,7 +167,7 @@ public class ProjectReferenceReplaceStep : ProjectBuildPipelineStep
includeAttr.Value = ConvertToNugetReference(oldNodeIncludeValue);
newNode.Attributes.Append(includeAttr);
var versionAttr = doc.CreateAttribute("Version");
var versionAttr = doc.CreateAttribute(CentralPackageManagement ? "VersionOverride" : "Version");
versionAttr.Value = _nugetPackageVersion;
newNode.Attributes.Append(versionAttr);
return newNode;

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs

@ -431,7 +431,6 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.HttpApi.Host"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
}
@ -457,7 +456,6 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.IdentityServer"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
@ -551,7 +549,6 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.IdentityServer"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
@ -589,7 +586,6 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.IdentityServer"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs

@ -12,6 +12,8 @@ public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep
private const string LocalhostPfx = "localhost.pfx -p 00000000-0000-0000-0000-000000000000";
private const string DotnetDevCerts = "openiddict.pfx -p 00000000-0000-0000-0000-000000000000";
private const string ProductionEncryptionAndSigningCertificate = "AddProductionEncryptionAndSigningCertificate(\"openiddict.pfx\", \"00000000-0000-0000-0000-000000000000\");";
private const string ReadmeCallout = "`00000000-0000-0000-0000-000000000000`";
private readonly static string RandomPassword = Guid.NewGuid().ToString("D");
public readonly static string RandomOpenIddictPassword = Guid.NewGuid().ToString("D");
@ -59,6 +61,13 @@ public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep
RandomOpenIddictPassword));
}
if (lines[i].Contains(ReadmeCallout))
{
lines[i] = lines[i].Replace(ReadmeCallout,
ReadmeCallout.Replace(DefaultPassword,
RandomOpenIddictPassword));
}
if (lines[i].Contains(ProductionEncryptionAndSigningCertificate))
{
lines[i] = lines[i].Replace(ProductionEncryptionAndSigningCertificate,

33
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RemoveUnnecessaryPortsStep.cs

@ -12,7 +12,6 @@ public class RemoveUnnecessaryPortsStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
RemoveUnnecessaryDbMigratorClients(context);
RemoveUnnecessaryHttpApiHostPorts(context);
}
@ -66,36 +65,4 @@ public class RemoveUnnecessaryPortsStep : ProjectBuildPipelineStep
httpApiHostAppSettings.SetLines(newlines);
}
private static void RemoveUnnecessaryDbMigratorClients(ProjectBuildContext context)
{
var dbMigratorAppSettings = context.Files
.FirstOrDefault(f =>
f.Name.Contains("MyCompanyName.MyProjectName.DbMigrator") && f.Name.EndsWith("appsettings.json"));
if (dbMigratorAppSettings == null)
{
return;
}
var appSettingsJsonObject = JObject.Parse(dbMigratorAppSettings.Content);
var authServerJsonObject = (JObject)appSettingsJsonObject?["IdentityServer"] ?? (JObject)appSettingsJsonObject["OpenIddict"];
var clientsJsonObject = (JObject)authServerJsonObject?["Clients"] ?? (JObject)authServerJsonObject?["Applications"];
if (clientsJsonObject == null)
{
return;
}
if (context.BuildArgs.UiFramework != UiFramework.Blazor)
{
clientsJsonObject.Remove("MyProjectName_Blazor");
}
if (!context.BuildArgs.PublicWebSite)
{
clientsJsonObject.Remove("MyProjectName_Web_Public");
}
dbMigratorAppSettings.SetContent(appSettingsJsonObject.ToString(Formatting.Indented));
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/Angular/AngularServiceProxyGenerator.cs

@ -7,6 +7,7 @@ using NuGet.Versioning;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.Utils;
using Volo.Abp.Cli.Version;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
@ -16,18 +17,18 @@ public class AngularServiceProxyGenerator : ServiceProxyGeneratorBase<AngularSer
{
public const string Name = "NG";
private readonly CliService _cliService;
private readonly CliVersionService _cliVersionService;
private readonly ICmdHelper _cmdhelper;
public AngularServiceProxyGenerator(
CliHttpClientFactory cliHttpClientFactory,
IJsonSerializer jsonSerializer,
ICmdHelper cmdhelper,
CliService cliService) :
CliVersionService cliVersionService) :
base(cliHttpClientFactory, jsonSerializer)
{
_cmdhelper = cmdhelper;
_cliService = cliService;
_cliVersionService = cliVersionService;
}
public async override Task GenerateProxyAsync(GenerateProxyArgs args)
@ -123,7 +124,7 @@ public class AngularServiceProxyGenerator : ServiceProxyGeneratorBase<AngularSer
return;
}
var cliVersion = await _cliService.GetCurrentCliVersionAsync(typeof(CliService).Assembly);
var cliVersion = await _cliVersionService.GetCurrentCliVersionAsync();
if (semanticSchematicsVersion < cliVersion)
{
Logger.LogWarning("\"@abp/ng.schematics\" version is lower than ABP Cli version.");

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/CSharp/CSharpServiceProxyGenerator.cs

@ -220,7 +220,7 @@ public class CSharpServiceProxyGenerator : ServiceProxyGeneratorBase<CSharpServi
}
classTemplate.Replace($"{UsingPlaceholder}", string.Join(Environment.NewLine, classUsingNamespaceList.Distinct().OrderBy(x => x).Select(x => x)));
classTemplate.Replace($"{Environment.NewLine}{Environment.NewLine} {MethodPlaceholder}", string.Empty);
classTemplate.Replace($"{Environment.NewLine}{Environment.NewLine} {MethodPlaceholder}", string.Empty).Replace(MethodPlaceholder, string.Empty);
filePath = Path.Combine(args.WorkDirectory, folder, $"{clientProxyName}.Generated.cs");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));

49
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/CliVersionService.cs

@ -0,0 +1,49 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using NuGet.Versioning;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Version;
public class CliVersionService : ITransientDependency
{
private CmdHelper CmdHelper { get; }
public CliVersionService(CmdHelper cmdHelper)
{
CmdHelper = cmdHelper;
}
public async Task<SemanticVersion> GetCurrentCliVersionAsync()
{
SemanticVersion currentCliVersion = default;
var consoleOutput = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list -g", out int exitCode));
string line;
while ((line = await consoleOutput.ReadLineAsync()) != null)
{
if (line.StartsWith("volo.abp.cli", StringComparison.InvariantCultureIgnoreCase))
{
var version = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1];
SemanticVersion.TryParse(version, out currentCliVersion);
break;
}
}
if (currentCliVersion == null)
{
// If not a tool executable, fallback to assembly version and treat as dev without updates
// Assembly revisions are not supported by SemVer scheme required for NuGet, trim to {major}.{minor}.{patch}
var assemblyVersion = string.Join(".", Assembly.GetExecutingAssembly().GetFileVersion().Split('.').Take(3));
return SemanticVersion.Parse(assemblyVersion + "-dev");
}
return currentCliVersion;
}
}

9
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/IMultiTenantUrlProvider.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.MultiTenancy;
public interface IMultiTenantUrlProvider
{
Task<string> GetUrlAsync(string templateUrl);
}

78
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantUrlProvider.cs

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.MultiTenancy;
public class MultiTenantUrlProvider : IMultiTenantUrlProvider , ITransientDependency
{
public const string TenantPlaceHolder = "{0}";
public const string TenantIdPlaceHolder = "{{tenantId}}";
public const string TenantNamePlaceHolder = "{{tenantName}}";
protected ICurrentTenant CurrentTenant { get; }
protected ITenantStore TenantStore { get; }
public MultiTenantUrlProvider(
ICurrentTenant currentTenant,
ITenantStore tenantStore)
{
CurrentTenant = currentTenant;
TenantStore = tenantStore;
}
public virtual async Task<string> GetUrlAsync(string templateUrl)
{
return await ReplacePlaceHoldersAsync(templateUrl);
}
protected virtual async Task<string> ReplacePlaceHoldersAsync(string templateUrl)
{
templateUrl = await ReplacePlaceHolderAsync(templateUrl, TenantIdPlaceHolder);
templateUrl = await ReplacePlaceHolderAsync(templateUrl, TenantNamePlaceHolder);
templateUrl = await ReplacePlaceHolderAsync(templateUrl, TenantPlaceHolder);
return templateUrl;
}
protected virtual async Task<string> ReplacePlaceHolderAsync(string templateUrl, string placeHolder)
{
if (!templateUrl.Contains(placeHolder))
{
return templateUrl;
}
var placeHolderValue = string.Empty;
if (CurrentTenant.IsAvailable)
{
placeHolderValue = (placeHolder == TenantIdPlaceHolder ? CurrentTenant.Id!.Value.ToString() : await GetCurrentTenantNameAsync()) + ".";
}
if (templateUrl.Contains(placeHolder + '.'))
{
placeHolder += '.';
}
templateUrl = templateUrl.Replace(
placeHolder,
placeHolderValue
);
return templateUrl;
}
protected virtual async Task<string> GetCurrentTenantNameAsync()
{
if (CurrentTenant.Id.HasValue && CurrentTenant.Name.IsNullOrEmpty())
{
var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value);
return tenantConfiguration!.Name;
}
return CurrentTenant.Name!;
}
}

1
framework/src/Volo.Abp.RemoteServices/Volo.Abp.RemoteServices.csproj

@ -18,6 +18,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy.Abstractions\Volo.Abp.MultiTenancy.Abstractions.csproj" />
</ItemGroup>
</Project>

8
framework/src/Volo.Abp.RemoteServices/Volo/Abp/Http/Client/RemoteServiceConfiguration.cs

@ -30,4 +30,12 @@ public class RemoteServiceConfiguration : Dictionary<string, string?>
this[nameof(BaseUrl)] = baseUrl;
this[nameof(Version)] = version;
}
public RemoteServiceConfiguration(RemoteServiceConfiguration configuration)
{
foreach (var keyValuePair in configuration)
{
this.Add(keyValuePair.Key, keyValuePair.Value);
}
}
}

39
framework/src/Volo.Abp.RemoteServices/Volo/Abp/Http/Client/RemoteServiceConfigurationProvider.cs

@ -1,25 +1,54 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Http.Client;
public class RemoteServiceConfigurationProvider : IRemoteServiceConfigurationProvider, IScopedDependency
{
protected AbpRemoteServiceOptions Options { get; }
protected IMultiTenantUrlProvider MultiTenantUrlProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
public RemoteServiceConfigurationProvider(IOptionsMonitor<AbpRemoteServiceOptions> options)
public RemoteServiceConfigurationProvider(
IOptionsMonitor<AbpRemoteServiceOptions> options,
IMultiTenantUrlProvider multiTenantUrlProvider,
ICurrentTenant currentTenant)
{
MultiTenantUrlProvider = multiTenantUrlProvider;
CurrentTenant = currentTenant;
Options = options.CurrentValue;
}
public Task<RemoteServiceConfiguration> GetConfigurationOrDefaultAsync(string name)
public virtual async Task<RemoteServiceConfiguration> GetConfigurationOrDefaultAsync(string name)
{
return Task.FromResult(Options.RemoteServices.GetConfigurationOrDefault(name));
return (await GetMultiTenantConfigurationAsync(Options.RemoteServices.GetConfigurationOrDefault(name)))!;
}
public Task<RemoteServiceConfiguration?> GetConfigurationOrDefaultOrNullAsync(string name)
public virtual async Task<RemoteServiceConfiguration?> GetConfigurationOrDefaultOrNullAsync(string name)
{
return Task.FromResult(Options.RemoteServices.GetConfigurationOrDefaultOrNull(name));
return await GetMultiTenantConfigurationAsync(Options.RemoteServices.GetConfigurationOrDefaultOrNull(name));
}
protected virtual async Task<RemoteServiceConfiguration?> GetMultiTenantConfigurationAsync(RemoteServiceConfiguration? configuration)
{
if (configuration == null)
{
return configuration;
}
var baseUrl = await MultiTenantUrlProvider.GetUrlAsync(configuration.BaseUrl);
if (baseUrl == configuration.BaseUrl)
{
return configuration;
}
var multiTenantConfiguration = new RemoteServiceConfiguration(configuration)
{
BaseUrl = baseUrl
};
return multiTenantConfiguration;
}
}

2
framework/src/Volo.Abp.RemoteServices/Volo/Abp/RemoteServices/AbpRemoteServicesModule.cs

@ -1,9 +1,11 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.RemoteServices;
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
public class AbpRemoteServicesModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)

7
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimTypes.cs

@ -87,9 +87,14 @@ public static class AbpClaimTypes
/// Default: "impersonator_username".
/// </summary>
public static string ImpersonatorUserName { get; set; } = "impersonator_username";
/// <summary>
/// Default: "picture".
/// </summary>
public static string Picture { get; set; } = "picture";
/// <summary>
/// Default: "remember_me".
/// </summary>
public static string RememberMe { get; set; } = "remember_me";
}

63
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs

@ -13,29 +13,23 @@ namespace Volo.Abp.UI.Navigation.Urls;
public class AppUrlProvider : IAppUrlProvider, ITransientDependency
{
public const string TenantIdPlaceHolder = "{{tenantId}}";
public const string TenantNamePlaceHolder = "{{tenantName}}";
protected AppUrlOptions Options { get; }
protected ICurrentTenant CurrentTenant { get; }
protected ITenantStore TenantStore { get; }
protected IMultiTenantUrlProvider MultiTenantUrlProvider { get; }
public ILogger<AppUrlProvider> Logger { get; set; }
public AppUrlProvider(
IOptions<AppUrlOptions> options,
ICurrentTenant currentTenant,
ITenantStore tenantStore)
IMultiTenantUrlProvider multiTenantUrlProvider)
{
CurrentTenant = currentTenant;
TenantStore = tenantStore;
MultiTenantUrlProvider = multiTenantUrlProvider;
Options = options.Value;
Logger = NullLogger<AppUrlProvider>.Instance;
}
public virtual async Task<string> GetUrlAsync(string appName, string? urlName = null)
{
return await ReplacePlaceHoldersAsync(
return await MultiTenantUrlProvider.GetUrlAsync(
await GetConfiguredUrl(
appName,
urlName
@ -59,8 +53,8 @@ public class AppUrlProvider : IAppUrlProvider, ITransientDependency
{
return url;
}
return await ReplacePlaceHoldersAsync(url!);
return await MultiTenantUrlProvider.GetUrlAsync(url!);
}
protected virtual async Task<string> GetConfiguredUrl(string appName, string? urlName)
@ -83,51 +77,6 @@ public class AppUrlProvider : IAppUrlProvider, ITransientDependency
);
}
protected virtual async Task<string> ReplacePlaceHoldersAsync(string url)
{
url = url.Replace(
TenantIdPlaceHolder,
CurrentTenant.Id.HasValue ? CurrentTenant.Id.Value.ToString() : ""
);
if (!url.Contains(TenantNamePlaceHolder))
{
return url;
}
var tenantNamePlaceHolder = TenantNamePlaceHolder;
if (url.Contains(TenantNamePlaceHolder + '.'))
{
tenantNamePlaceHolder = TenantNamePlaceHolder + '.';
}
if (url.Contains(tenantNamePlaceHolder))
{
if (CurrentTenant.Id.HasValue)
{
url = url.Replace(tenantNamePlaceHolder, await GetCurrentTenantNameAsync() + ".");
}
else
{
url = url.Replace(tenantNamePlaceHolder, "");
}
}
return url;
}
private async Task<string> GetCurrentTenantNameAsync()
{
if (CurrentTenant.Id.HasValue && CurrentTenant.Name.IsNullOrEmpty())
{
var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value);
return tenantConfiguration!.Name;
}
return CurrentTenant.Name!;
}
public Task<string?> GetUrlOrNullAsync([NotNull] string appName, string? urlName = null)
{
var app = Options.Applications[appName];

6
framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/AbpAspNetCoreMvcVersioningTestModule.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Builder;
using Asp.Versioning;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.TestBase;
@ -51,7 +52,8 @@ public class AbpAspNetCoreMvcVersioningTestModule : AbpModule
//options.ApiVersionReader = new HeaderApiVersionReader("api-version"); //Supports header too
//options.ApiVersionReader = new MediaTypeApiVersionReader(); //Supports accept header too
}, options =>
{
options.ConfigureAbp(preActions.Configure());
});

2
framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/HelloController.cs

@ -1,4 +1,6 @@
using System.Threading.Tasks;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Volo.Abp.AspNetCore.Mvc.Versioning.App;

57
framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenantUrlProivder_Tests.cs

@ -0,0 +1,57 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.MultiTenancy.ConfigurationStore;
using Xunit;
namespace Volo.Abp.MultiTenancy;
public class MultiTenantUrlProivder_Tests : MultiTenancyTestBase
{
private readonly ICurrentTenant _currentTenant;
private readonly IMultiTenantUrlProvider _multiTenantUrlProvider;
private readonly Guid _tenantAId = Guid.NewGuid();
public MultiTenantUrlProivder_Tests()
{
_currentTenant = ServiceProvider.GetRequiredService<ICurrentTenant>();
_multiTenantUrlProvider = ServiceProvider.GetRequiredService<IMultiTenantUrlProvider>();
}
protected override void BeforeAddApplication(IServiceCollection services)
{
services.Configure<AbpDefaultTenantStoreOptions>(options =>
{
options.Tenants =
[
new TenantConfiguration(_tenantAId, "TenantA")
];
});
}
[Fact]
public async Task GetUrlAsync()
{
var tenantNameHolderUrl = "https://{{tenantName}}.abp.io";
var tenantIdHolderUrl = "https://{{tenantId}}.abp.io";
var tenantHolderUrl = "https://{0}.abp.io";
var hostUrl = "https://abp.io";
_currentTenant.Id.ShouldBeNull();
(await _multiTenantUrlProvider.GetUrlAsync(tenantNameHolderUrl)).ShouldBe(hostUrl);
(await _multiTenantUrlProvider.GetUrlAsync(tenantIdHolderUrl)).ShouldBe(hostUrl);
(await _multiTenantUrlProvider.GetUrlAsync(tenantHolderUrl)).ShouldBe(hostUrl);
(await _multiTenantUrlProvider.GetUrlAsync(hostUrl)).ShouldBe(hostUrl);
using (_currentTenant.Change(_tenantAId))
{
_currentTenant.Id.ShouldBe(_tenantAId);
(await _multiTenantUrlProvider.GetUrlAsync(tenantNameHolderUrl)).ShouldBe("https://TenantA.abp.io");
(await _multiTenantUrlProvider.GetUrlAsync(tenantIdHolderUrl)).ShouldBe("https://"+_tenantAId+".abp.io");
(await _multiTenantUrlProvider.GetUrlAsync(tenantHolderUrl)).ShouldBe("https://TenantA.abp.io");
(await _multiTenantUrlProvider.GetUrlAsync(hostUrl)).ShouldBe(hostUrl);
}
}
}

17
framework/test/Volo.Abp.RemoteServices.Tests/Volo.Abp.RemoteServices.Tests.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.RemoteServices\Volo.Abp.RemoteServices.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>
</Project>

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

Loading…
Cancel
Save