Browse Source

Merge branch 'dev' into issue-3384/L

pull/18854/head
honurbu 3 years ago
parent
commit
3522e098ab
  1. 1
      Directory.Packages.props
  2. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  3. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  4. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json
  5. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json
  6. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json
  7. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
  8. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  9. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json
  10. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json
  11. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json
  12. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json
  13. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json
  14. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json
  15. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json
  16. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json
  17. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json
  18. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json
  19. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json
  20. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
  21. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ru.json
  22. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json
  23. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json
  24. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json
  25. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json
  26. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
  27. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json
  28. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  29. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  30. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json
  31. 72
      docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/Post.md
  32. BIN
      docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/deepl.jpg
  33. 85
      docs/en/Migration-Guides/Abp-8_1.md
  34. 6
      docs/en/Multi-Tenancy.md
  35. 20
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs
  36. 5
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs
  37. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs
  38. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs
  39. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalFooterTagHelperService.cs
  40. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs
  41. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs
  42. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js
  43. 5
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  44. 31
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcActionDescriptorProvider.cs
  45. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs
  46. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs
  47. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs
  48. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs
  49. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs
  50. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs
  51. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs
  52. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs
  53. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs
  54. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs
  55. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs
  56. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs
  57. 5
      framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs
  58. 5
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs
  59. 7
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs
  60. 5
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs
  61. 6
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Filters/IAbpFilter.cs
  62. 19
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Middleware/AbpMiddlewareBase.cs
  63. 5
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs
  64. 5
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs
  65. 5
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs
  66. 5
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs
  67. 7
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs
  68. 12
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs
  69. 26
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs
  70. 17
      framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs
  71. 2
      framework/src/Volo.Abp.BlazoriseUI/Components/UiMessageAlert.razor
  72. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  73. 1
      framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj
  74. 25
      framework/src/Volo.Abp.Core/Volo/Abp/DisableAbpFeaturesAttribute.cs
  75. 20
      framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs
  76. 43
      framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProviderManager.cs
  77. 8
      framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureValueProviderManager.cs
  78. 6
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantNormalizer.cs
  79. 4
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantStore.cs
  80. 10
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs
  81. 11
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/UpperInvariantTenantNormalizer.cs
  82. 8
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/DefaultTenantStore.cs
  83. 7
      framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfigurationProvider.cs
  84. 27
      framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProviderManager.cs
  85. 3
      framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs
  86. 3
      framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs
  87. 5
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationMiddleware.cs
  88. 74
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Filters/MvcDisableAbpFeaturesAttribute_Tests.cs
  89. 3
      framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs
  90. 59
      framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs
  91. 31
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs
  92. 11
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AlwaysExceptionAsyncInterceptor.cs
  93. 41
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/DisableInterceptionTargetClass.cs
  94. 54
      framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureValueProviderManager_Tests.cs
  95. 62
      framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingValueProviderManager_Tests.cs
  96. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml
  97. 56
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  98. 2
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js
  99. 4
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor
  100. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs

1
Directory.Packages.props

@ -107,7 +107,6 @@
<PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />
<PackageVersion Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NuGet.Versioning" Version="6.7.0" />

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

@ -592,6 +592,8 @@
"OrganizationId": "Organization Id",
"RemoveAllWinnersConfirmationMessage": "Are you sure you want to remove all winners?",
"AutoRenewals": "Auto Renewals",
"OrganizationHasCreditCard": "Organization has credit card. Please remove credit card first!"
"OrganizationHasCreditCard": "Organization has credit card. Please remove credit card first!",
"DisplayName:DontSendEmailForLicenseExpire": "Don't Send Email For License Expire",
"DontSendEmailForLicenseExpire": "Don't Send Email For License Expire"
}
}

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

@ -1131,6 +1131,7 @@
"NameOnCard": "Name on Card",
"BillingDetails": "Billing Details",
"ThereIsNoDeveloper": "There is no developer.",
"CardDetails": "Card Details"
"CardDetails": "Debit/Credit Card Details",
"NoActiveLicence": "You are not eligible for this action! You have no active license."
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "أحدث المقالات",
"RaffleHeader": "مرحبًا عضو مجتمع برنامج الجسر الأكاديمي!",
"RafflesInfo": "<br>هذه هي صفحة السحب المخصصة لإظهار تقديرنا لك لكونك عضوًا نشطًا في المجتمع. نحن نقوم بإجراء <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">محادثات مجتمعية لبرنامج ABP</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">، ومؤتمر ABP .NET</a> ، ونحضر أو نرعى الأحداث المتعلقة بـ .NET والتي نقدم فيها بعض الهدايا.<br><br> يمكنك متابعة هذه الصفحة لرؤية السحوبات القادمة أو حضورها أو الاطلاع على السحوبات السابقة التي قمنا بسحبها بما في ذلك الفائزين.<br><br> شكرا لكونك عضوا نشطا! نراكم في السحوبات القادمة.",
"RafflesInfoTitle": "<span class=\"gradient-community\">سحوبات</span> مجتمع ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">سحوبات</span> مجتمع ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> أيد.",
"Preview": "معاينة"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "poslední články",
"RaffleHeader": "Dobrý den, člen komunity ABP!",
"RafflesInfo": "<br>Toto je stránka s losováním věnovaná tomu, abychom vám ukázali naše uznání za to, že jste aktivním členem komunity. Pořádáme <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET Conference</a> , účastníme se nebo sponzorujeme akce související s .NET, ve kterých rozdáváme nějaké dárky.<br><br> Na této stránce můžete sledovat nadcházející tomboly, zúčastnit se jich nebo si prohlédnout předchozí tomboly, které losujeme, včetně výherců.<br><br> Děkujeme, že jste aktivním členem! Uvidíme se v nadcházejícím slosování.",
"RafflesInfoTitle": "Komunitní <span class=\"gradient-community\">tomboly</span> ABP"
"RafflesInfoTitle": "Komunitní <span class=\"gradient-community\">tomboly</span> ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> podporováno.",
"Preview": "Náhled"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Neueste Artikel",
"RaffleHeader": "Hallo ABP-Community-Mitglied!",
"RafflesInfo": "<br>Auf dieser Verlosungsseite möchten wir Ihnen unsere Wertschätzung dafür zeigen, dass Sie ein aktives Community-Mitglied sind. Wir veranstalten <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">und ABP .NET Conferences</a> , nehmen an .NET-bezogenen Veranstaltungen teil oder sponsern diese, bei denen wir einige Geschenke verschenken.<br><br> Sie können dieser Seite folgen, um die bevorstehenden Verlosungen zu sehen, daran teilzunehmen oder frühere Verlosungen, die wir verlosen, einschließlich der Gewinner, anzusehen.<br><br> Vielen Dank, dass Sie ein aktives Mitglied sind! Wir sehen uns bei den kommenden Gewinnspielen.",
"RafflesInfoTitle": "ABP-Community- <span class=\"gradient-community\">Verlosungen</span>"
"RafflesInfoTitle": "ABP-Community- <span class=\"gradient-community\">Verlosungen</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> unterstützt.",
"Preview": "Vorschau"
}
}

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

@ -103,6 +103,8 @@
"Language": "Language",
"CreatePostLanguageInfo": "Language of the post",
"SeeMore": "See More",
"MemberNotPublishedPostYet": "This member hasn't published any posts yet."
"MemberNotPublishedPostYet": "This member hasn't published any posts yet.",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
"Preview": "Preview"
}
}

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

@ -256,6 +256,8 @@
"RaffleHeader": "Hello ABP Community Member!",
"RafflesInfo": "<br>This is the raffle page dedicated to show our appreciation towards you for being an active Community Member. We do <a class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">,ABP .NET Conference</a>, attend or sponsor to the .NET-related events in which we give away some gifts. <br><br>You can follow this page to see the upcoming raffles, attend them, or see previous raffles we draw including the winners. <br><br>Thank you for being an active member! See you in the upcoming raffles.",
"RafflesInfoTitle": "ABP Community <span class=\"gradient-community\">Raffles</span>",
"ToLuckyWinner": "to 1 lucky winner"
"ToLuckyWinner": "to 1 lucky winner",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
"Preview": "Preview"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "últimos artículos",
"RaffleHeader": "¡Hola miembro de la comunidad ABP!",
"RafflesInfo": "<br>Esta es la página del sorteo dedicada a mostrarle nuestro agradecimiento por ser un miembro activo de la comunidad. Realizamos <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">charlas comunitarias de ABP</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, conferencias ABP .NET</a> , asistimos o patrocinamos eventos relacionados con .NET en los que regalamos algunos obsequios.<br><br> Puedes seguir esta página para ver los próximos sorteos, asistir a ellos o ver sorteos anteriores que sorteamos incluyendo a los ganadores.<br><br> ¡Gracias por ser un miembro activo! Nos vemos en los próximos sorteos.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Rifas</span> de la Comunidad ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Rifas</span> de la Comunidad ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> soportado.",
"Preview": "Avance"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Viimeisimmät artikkelit",
"RaffleHeader": "Hei ABP-yhteisön jäsen!",
"RafflesInfo": "<br>Tämä on arvontasivu, joka on omistettu osoittamaan kiitollisuuttamme sinua kohtaan, että olet aktiivinen yhteisön jäsen. Teemme <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talksia</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET -konferenssia</a> , osallistumme tai sponsoroimme .NET-tapahtumia, joissa annamme lahjoja.<br><br> Voit seurata tätä sivua nähdäksesi tulevat arvonnat, osallistua niihin tai nähdäksesi aiemmat arvonnamme, mukaan lukien voittajat.<br><br> Kiitos aktiivisesta jäsenyydestäsi! Nähdään tulevissa arvonnassa.",
"RafflesInfoTitle": "ABP-yhteisön <span class=\"gradient-community\">arpajaiset</span>"
"RafflesInfoTitle": "ABP-yhteisön <span class=\"gradient-community\">arpajaiset</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> tuettu.",
"Preview": "Esikatselu"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Derniers articles",
"RaffleHeader": "Bonjour membre de la communauté ABP !",
"RafflesInfo": "<br>Ceci est la page de tirage au sort dédiée à vous montrer notre gratitude pour votre participation active à la communauté. Nous organisons <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">des discussions communautaires ABP</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, des conférences ABP .NET</a> , assistons ou sponsorisons des événements liés à .NET au cours desquels nous offrons des cadeaux.<br><br> Vous pouvez suivre cette page pour voir les tirages au sort à venir, y assister ou voir les tirages au sort précédents que nous tirons, y compris les gagnants.<br><br> Merci d&#39;être un membre actif ! Rendez-vous lors des prochains tirages au sort.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Tirages</span> au sort communautaires ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Tirages</span> au sort communautaires ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> prise en charge.",
"Preview": "Aperçu"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "नवीनतम लेख",
"RaffleHeader": "नमस्ते एबीपी समुदाय सदस्य!",
"RafflesInfo": "<br>यह रैफ़ल पेज है जो एक सक्रिय समुदाय सदस्य होने के लिए आपके प्रति हमारी सराहना दिखाने के लिए समर्पित है। हम <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">एबीपी सामुदायिक वार्ता</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, एबीपी .NET सम्मेलन</a> करते हैं, .NET से संबंधित कार्यक्रमों में भाग लेते हैं या प्रायोजित करते हैं जिसमें हम कुछ उपहार देते हैं।<br><br> आप आगामी रैफ़ल देखने, उनमें भाग लेने, या विजेताओं सहित हमारे द्वारा निकाले गए पिछले रैफ़ल देखने के लिए इस पृष्ठ का अनुसरण कर सकते हैं।<br><br> सक्रिय सदस्य बनने के लिए धन्यवाद! आगामी रैफ़ल में मिलते हैं।",
"RafflesInfoTitle": "एबीपी कम्युनिटी <span class=\"gradient-community\">रैफल्स</span>"
"RafflesInfoTitle": "एबीपी कम्युनिटी <span class=\"gradient-community\">रैफल्स</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> का समर्थन किया।",
"Preview": "पूर्व दर्शन"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Najnoviji članci",
"RaffleHeader": "Pozdrav članu ABP zajednice!",
"RafflesInfo": "<br>Ovo je stranica za nagradnu igru namijenjena da vam pokažemo našu zahvalnost što ste aktivni član zajednice. Vodimo <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">razgovore o ABP zajednici</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET konferenciji</a> , prisustvujemo ili sponzoriramo događaje vezane uz .NET na kojima dijelimo neke darove.<br><br> Možete pratiti ovu stranicu kako biste vidjeli nadolazeće nagradne igre, prisustvovali im ili vidjeli prethodne nagradne igre koje izvlačimo uključujući dobitnike.<br><br> Hvala vam što ste aktivan član! Vidimo se u nadolazećim nagradnim igrama.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Izvlačenje nagradne igre</span> zajednice ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Izvlačenje nagradne igre</span> zajednice ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> podržan.",
"Preview": "Pregled"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Legfrissebb cikkek",
"RaffleHeader": "Kedves ABP közösségi tag!",
"RafflesInfo": "<br>Ez az a sorsolási oldal, amelynek célja, hogy kifejezzük hálánkat feléd, amiért aktív közösségi tag vagy. <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">Az ABP Community Talks-okat</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, az ABP .NET konferenciákat</a> szervezzük, részt veszünk vagy szponzorálunk olyan .NET-hez kapcsolódó eseményeket, amelyeken ajándékokat adunk.<br><br> Ezt az oldalt követheti, hogy megtekinthesse a közelgő sorsolásokat, részt vegyen azokon, vagy megtekinthesse korábbi sorsolásainkat, beleértve a nyerteseket is.<br><br> Köszönjük, hogy aktív tag vagy! Találkozunk a sorsoláson.",
"RafflesInfoTitle": "ABP közösségi <span class=\"gradient-community\">tombola</span>"
"RafflesInfoTitle": "ABP közösségi <span class=\"gradient-community\">tombola</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> támogatott.",
"Preview": "Előnézet"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Nýjustu greinar",
"RaffleHeader": "Halló ABP samfélagsmeðlimur!",
"RafflesInfo": "<br>Þetta er happdrættisíðan sem er tileinkuð þér að þakka þér fyrir að vera virkur samfélagsmeðlimur. Við gerum <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET ráðstefnu</a> , sækjum eða styrkjum .NET tengda viðburði þar sem við gefum nokkrar gjafir.<br><br> Þú getur fylgst með þessari síðu til að sjá komandi happdrætti, mæta á þær eða sjá fyrri happdrætti sem við drögum út, þar á meðal vinningshafa.<br><br> Þakka þér fyrir að vera virkur meðlimur! Sjáumst í komandi happdrætti.",
"RafflesInfoTitle": "ABP <span class=\"gradient-community\">samfélagshappdrætti</span>"
"RafflesInfoTitle": "ABP <span class=\"gradient-community\">samfélagshappdrætti</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> stutt.",
"Preview": "Forskoðun"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Articoli Recenti",
"RaffleHeader": "Ciao membro della comunità ABP!",
"RafflesInfo": "<br>Questa è la pagina della lotteria dedicata a mostrare il nostro apprezzamento nei tuoi confronti per essere un membro attivo della comunità. Organizziamo <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET Conference</a> , partecipiamo o sponsorizziamo eventi relativi a .NET in cui regaliamo alcuni regali.<br><br> Puoi seguire questa pagina per vedere le prossime lotterie, parteciparvi o vedere le lotterie precedenti che estraiamo, compresi i vincitori.<br><br> Grazie per essere un membro attivo! Ci vediamo alle prossime lotterie.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Lotterie</span> comunitarie ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Lotterie</span> comunitarie ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supportato.",
"Preview": "Anteprima"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Laatste artikels",
"RaffleHeader": "Hallo ABP Community-lid!",
"RafflesInfo": "<br>Dit is de loterijpagina die bedoeld is om onze waardering voor u te tonen omdat u een actief lid van de community bent. We houden <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET Conference</a> , wonen of sponsoren de .NET-gerelateerde evenementen bij waarin we een aantal geschenken weggeven.<br><br> U kunt deze pagina volgen om de komende loterijen te zien, deze bij te wonen of eerdere loterijen te zien die we trekken, inclusief de winnaars.<br><br> Bedankt dat u een actief lid bent! Tot ziens bij de komende loterijen.",
"RafflesInfoTitle": "ABP- <span class=\"gradient-community\">gemeenschaploterijen</span>"
"RafflesInfoTitle": "ABP- <span class=\"gradient-community\">gemeenschaploterijen</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> ondersteund.",
"Preview": "Voorbeeld"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "ostatnie artykuły",
"RaffleHeader": "Witaj, członku społeczności ABP!",
"RafflesInfo": "<br>To jest strona loterii, której celem jest wyrażenie naszego uznania dla Ciebie za bycie aktywnym członkiem społeczności. Prowadzimy <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">rozmowy społecznościowe ABP</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, konferencje ABP .NET</a> , uczestniczymy lub sponsorujemy wydarzenia związane z .NET, podczas których rozdajemy prezenty.<br><br> Możesz śledzić tę stronę, aby zobaczyć nadchodzące loterie, wziąć w nich udział lub zobaczyć poprzednie loterie, które losowaliśmy, w tym zwycięzców.<br><br> Dziękujemy za bycie aktywnym członkiem! Do zobaczenia w nadchodzących loteriach.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Loterie</span> społecznościowe ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Loterie</span> społecznościowe ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> utrzymany.",
"Preview": "Zapowiedź"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Artigos Mais Recentes",
"RaffleHeader": "Olá, membro da comunidade ABP!",
"RafflesInfo": "<br>Esta é a página do sorteio dedicada a mostrar nosso agradecimento por você ser um membro ativo da comunidade. Fazemos <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET Conference</a> , participamos ou patrocinamos eventos relacionados ao .NET nos quais distribuímos alguns presentes.<br><br> Você pode seguir esta página para ver os próximos sorteios, participar deles ou ver os sorteios anteriores que sorteamos, incluindo os vencedores.<br><br> Obrigado por ser um membro ativo! Nos vemos nos próximos sorteios.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Sorteios</span> da Comunidade ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Sorteios</span> da Comunidade ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> suportado.",
"Preview": "Visualização"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "ultimele articole",
"RaffleHeader": "Bună ziua, membru al comunității ABP!",
"RafflesInfo": "<br>Aceasta este pagina de tombolă dedicată pentru a arăta aprecierea noastră față de dvs. pentru că sunteți un membru activ al comunității. Facem <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET Conference</a> , participăm sau sponsorizăm evenimentele legate de .NET în care oferim câteva cadouri.<br><br> Puteți urmări această pagină pentru a vedea tombolele viitoare, a participa la ele sau pentru a vedea tombolele anterioare pe care le extragem, inclusiv câștigătorii.<br><br> Vă mulțumim că sunteți un membru activ! Ne vedem la tombolele viitoare.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Tombole</span> comunitare ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Tombole</span> comunitare ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> sprijinit.",
"Preview": "previzualizare"
}
}

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

@ -258,6 +258,8 @@
"LatestArticles": "Последние статьи",
"RaffleHeader": "Привет, участник сообщества ABP!",
"RafflesInfo": "<br>Эта страница розыгрыша посвящена тому, чтобы выразить нашу признательность вам за то, что вы являетесь активным членом сообщества. <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">Обсуждения сообщества ABP</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">,Конференция ABP .NET</a>, посещать или спонсировать мероприятия, связанные с .NET, на которых мы раздаем подарки. <br><br>Вы можете подписаться на эту страницу, чтобы увидеть предстоящие розыгрыши, посетить их или просмотреть предыдущие розыгрыши, которые мы проводим, включая победителей. <br><br>Спасибо за активное участие! ",
"RafflesInfoTitle": "Сообщество АБП <span class=\"gradient-community\">Розыгрыши</span>"
"RafflesInfoTitle": "Сообщество АБП <span class=\"gradient-community\">Розыгрыши</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> поддерживается.",
"Preview": "Предварительный просмотр"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Najnovšie články",
"RaffleHeader": "Dobrý deň, člen komunity ABP!",
"RafflesInfo": "<br>Toto je stránka žrebovania venovaná na vyjadrenie nášho uznania vám za to, že ste aktívnym členom komunity. Robíme <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET konferenciu</a> , zúčastňujeme sa alebo sponzorujeme podujatia súvisiace s .NET, na ktorých rozdávame nejaké darčeky.<br><br> Na tejto stránke si môžete pozrieť pripravované tomboly, zúčastniť sa ich alebo si pozrieť predchádzajúce žrebovanie, ktoré vyžrebujeme vrátane výhercov.<br><br> Ďakujeme, že ste aktívnym členom! Vidíme sa v najbližšom žrebovaní.",
"RafflesInfoTitle": "Komunitné <span class=\"gradient-community\">tomboly</span> ABP"
"RafflesInfoTitle": "Komunitné <span class=\"gradient-community\">tomboly</span> ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> podporované.",
"Preview": "Náhľad"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Najnovejši članki",
"RaffleHeader": "Pozdravljeni član skupnosti ABP!",
"RafflesInfo": "<br>To je stran za nagradno igro, namenjena izkazovanju naše hvaležnosti do vas, ker ste aktivni član skupnosti. Izvajamo <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, ABP .NET Conference</a> , se udeležujemo ali sponzoriramo dogodke, povezane z .NET, na katerih podarimo nekaj daril.<br><br> To stran lahko spremljate in si ogledate prihajajoče nagradne igre, se jih udeležite ali si ogledate prejšnje nagradne igre, ki smo jih izžrebali, vključno z zmagovalci.<br><br> Hvala, ker ste aktivni član! Se vidimo na prihajajočih nagradnih igrah.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Žrebanje</span> skupnosti ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Žrebanje</span> skupnosti ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> podprt.",
"Preview": "Predogled"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json

@ -189,6 +189,8 @@
"Layout_MetaDescription": "ABP Topluluğu, insanların ABP çerçevesi hakkında paylaşımlarda bulunabileceği ve projeleri takip edebileceği bir ortamdır.",
"Index_Page_CommunityIntroduction": "Burası ABP Çerçevesi, .NET ve yazılım geliştirme için bir merkezdir. Makaleleri okuyabilir, eğitim videolarını izleyebilir, ABP'nin gelişim süreci ve ABP ile ilgili etkinlikler hakkında bilgi alabilir, diğer geliştiricilere yardımcı olabilir ve uzmanlığınızı ABP topluluğu ile paylaşabilirsiniz.",
"IConsentToMedium": "Bu yazının https://medium.com/volosoft adresinde yayınlanmasına izin veriyorum.",
"DiscordPageTitle": "ABP Discord Topluluğu"
"DiscordPageTitle": "ABP Discord Topluluğu",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> destekleniyor.",
"Preview": "Ön izleme"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "Bài viết mới nhất",
"RaffleHeader": "Xin chào Thành viên Cộng đồng ABP!",
"RafflesInfo": "<br>Đây là trang xổ số dành riêng để thể hiện sự đánh giá cao của chúng tôi đối với bạn vì đã trở thành Thành viên cộng đồng tích cực. Chúng tôi tổ chức <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">các buổi nói chuyện cộng đồng ABP</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">, Hội nghị ABP .NET</a> , tham dự hoặc tài trợ cho các sự kiện liên quan đến .NET mà trong đó chúng tôi tặng một số quà tặng.<br><br> Bạn có thể theo dõi trang này để xem các cuộc xổ số sắp tới, tham dự hoặc xem các cuộc xổ số trước đây mà chúng tôi rút ra bao gồm cả những người chiến thắng.<br><br> Cảm ơn bạn đã là thành viên tích cực! Hẹn gặp lại các bạn trong đợt xổ số sắp tới.",
"RafflesInfoTitle": "<span class=\"gradient-community\">Xổ</span> số cộng đồng ABP"
"RafflesInfoTitle": "<span class=\"gradient-community\">Xổ</span> số cộng đồng ABP",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> được hỗ trợ.",
"Preview": "Xem trước"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "最新文章",
"RaffleHeader": "你好,ABP 社区成员!",
"RafflesInfo": "<br>这是一个抽奖页面,旨在感谢您成为活跃的社区成员。我们举办 <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP 社区讲座</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">、ABP .NET 会议</a>,参加或赞助与 .NET 相关的活动,并在活动中赠送一些礼品。<br><br>您可以关注此页面,查看即将举行的抽奖活动、参加这些活动或查看我们以前举行的抽奖活动(包括获奖者)。<br><br>感谢您成为我们的活跃成员!在即将举行的抽奖活动中再见。",
"RafflesInfoTitle": "ABP 社区<span class=\"gradient-community\">来抽奖</span"
"RafflesInfoTitle": "ABP 社区<span class=\"gradient-community\">来抽奖</span",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> 支持的。",
"Preview": "预览"
}
}

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

@ -255,6 +255,8 @@
"LatestArticles": "最新的文章",
"RaffleHeader": "ABP 社群成員您好!",
"RafflesInfo": "<br>這是抽獎頁面,旨在表達我們對您作為活躍社區成員的感謝。我們舉辦<a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP 社群講座</a><a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">、ABP .NET 會議</a>、參加或贊助 .NET 相關活動,並在活動中贈送一些禮物。<br><br>您可以關注此頁面查看即將舉行的抽獎活動、參加抽獎活動或查看我們之前抽獎的抽獎活動(包括獲獎者)。<br><br>感謝您成為活躍會員!在即將到來的抽獎活動中再見。",
"RafflesInfoTitle": "ABP 社區<span class=\"gradient-community\">萊佛士</span>"
"RafflesInfoTitle": "ABP 社區<span class=\"gradient-community\">萊佛士</span>",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> 支持的。",
"Preview": "预览"
}
}

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

@ -353,6 +353,8 @@
"BuildSolutionsWithAbp": "Build maintainable .NET solutions by following software development best practices using ABP.",
"BuyOnAmazon": "Buy on Amazon",
"BuyOnPackt": "Buy on Packt",
"BuyOnDangDang": "Buy on DangDang",
"BuyOnJD": "Buy on JD",
"Discounted": "Discounted",
"MasteringAbpFramework_Book_KeyFeatures": "Key Features",
"MasteringAbpFramework_Book_Key_Features_Description_1": "Build robust, maintainable, modular, and scalable software solutions using ABP Framework.",

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

@ -353,6 +353,8 @@
"BuildSolutionsWithAbp": "使用 ABP,遵循软件开发最佳实践,构建可维护的 .NET 解决方案。",
"BuyOnAmazon": "在亚马逊上购买",
"BuyOnPackt": "在 Packt 购买",
"BuyOnDangDang": "在当当网购买",
"BuyOnJD": "在京东上购买",
"Discounted": "折扣",
"MasteringAbpFramework_Book_KeyFeatures": "主要功能",
"MasteringAbpFramework_Book_Key_Features_Description_1": "使用 ABP 框架构建稳健、可维护、模块化和可扩展的软件解决方案。",

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

@ -353,6 +353,8 @@
"BuildSolutionsWithAbp": "使用 ABP 遵循軟體開發最佳實務來建立可維護的 .NET 解決方案。",
"BuyOnAmazon": "在亞馬遜上購買",
"BuyOnPackt": "在 Packt 上購買",
"BuyOnDangDang": "在當當上購買",
"BuyOnJD": "在京東上購買",
"Discounted": "折扣",
"MasteringAbpFramework_Book_KeyFeatures": "主要特徵",
"MasteringAbpFramework_Book_Key_Features_Description_1": "使用 ABP 框架建構健壯、可維護、模組化和可擴展的軟體解決方案。",

72
docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/Post.md

@ -0,0 +1,72 @@
# Use Deepl to translate localization files
Translating localized text during the development of ABP modules is a boring job. For this reason, we have added the `translate` command to the CLI tool to translate the localization files, but it still requires manual translation of texts by the developer.
Now, we introduce a new way to translate the target language, which is to use the [Deepl](https://www.deepl.com/translator) translation service to translate the target language.
You can use the `translate --online` command in your module directory to translate the target language.
For example, if you have added all `en` localization texts to your module, and you want to translate them to `zh-Hans`, you can run the following command:
```
abp translate -r en -c zh-Hans --online --deepl-auth-key your_auth_key
```
* `-r` parameter is used to specify the source language. It is usually a localized file that you have created.
* `-c` parameter is used to specify the target language. It is usually a language that you want to translate.
* `--online` parameter is used to indicate that the translation is performed from the Deepl service.
* `--deepl-auth-key` parameter is the API key of your Deepl account. You can get it from [here](https://support.deepl.com/hc/en-us/articles/360020695820-Authentication-Key).
The output of the above command is as follows:
```
ABP CLI 8.0.0
Abp translate online...
Target culture: zh-Hans
Reference culture: en
Create translation: Settings => 设置
Create translation: SuccessfullySaved => 成功保存
Create translation: Permission:SettingManagement => 设置管理
Create translation: Permission:Emailing => 发送电子邮件
Create translation: Permission:EmailingTest => 电子邮件测试
Create translation: Permission:TimeZone => 时区
Create translation: SendTestEmail => 发送测试电子邮件
Create translation: SenderEmailAddress => 发件人电子邮件地址
Create translation: TargetEmailAddress => 目标电子邮件地址
Create translation: Subject => 主题
Create translation: Body => 正文
Create translation: TestEmailSubject => 测试电子邮件 {0}
Create translation: TestEmailBody => 在此测试电子邮件正文信息
Create translation: SuccessfullySent => 成功发送
Create translation: Send => 发送
Create translation: Menu:Emailing => 发送电子邮件
Create translation: Menu:TimeZone => 时区
Create translation: DisplayName:Timezone => 时区
Create translation: TimezoneHelpText => 此设置用于应用程序范围或基于租户的设置。
Create translation: SmtpHost => 主机
Create translation: SmtpPort => 端口
Create translation: SmtpUserName => 用户名
Create translation: SmtpPassword => 密码
Create translation: SmtpDomain => 域名
Create translation: SmtpEnableSsl => 启用 ssl
Create translation: SmtpUseDefaultCredentials => 使用默认凭据
Create translation: DefaultFromAddress => 默认地址
Create translation: DefaultFromDisplayName => 显示名称的默认值
Create translation: Feature:SettingManagementGroup => 设置管理
Create translation: Feature:SettingManagementEnable => 启用设置管理
Create translation: Feature:SettingManagementEnableDescription => 在应用程序中启用设置管理系统。
Create translation: Feature:AllowChangingEmailSettings => 允许更改电子邮件设置。
Create translation: Feature:AllowChangingEmailSettingsDescription => 允许更改电子邮件设置。
Write translation json to setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hans.json.
```
The generated `zh-Hans.json` as follow:
![zh-Hans.json](deepl.jpg)
In this example, It only translates one `en.json` to `zh-Hans.json`, but if there are multiple `en.json` files in the module, it will translate all `en.json` files to `zh-Hans.json`.
Of course, the translation is not always correct, you can update the translation in the generated `zh-Hans.json` files.
Enjoy it!

BIN
docs/en/Community-Articles/2024-01-04-CLI-Online-Translate/deepl.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

85
docs/en/Migration-Guides/Abp-8_1.md

@ -0,0 +1,85 @@
# ABP Version 8.1 Migration Guide
This document is a guide for upgrading ABP v8.0 solutions to ABP v8.1. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application.
## Added `NormalizedName` property to `Tenant`
The `Tenant` entity has a new property called `NormalizedName`. It is used to find/cache a tenant by its name in a case-insensitive way.
This property is automatically set when a tenant is created or updated. It gets the normalized name of the tenant name by `UpperInvariantTenantNormalizer(ITenantNormalizer)` service. You can implement this service to change the normalization logic.
### `ITenantStore`
The `ITenantStore` will use the `NormalizedName` parameter to get tenants, Please use the `ITenantNormalizer` to normalize the tenant name before calling the `ITenantStore` methods.
### Update `NormalizedName` in `appsettings.json`
If your tenants defined in the `appsettings.json` file, you should add the `NormalizedName` property to your tenants.
````json
"Tenants": [
{
"Id": "446a5211-3d72-4339-9adc-845151f8ada0",
"Name": "tenant1",
"NormalizedName": "TENANT1" // <-- Add this property
},
{
"Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d",
"Name": "tenant2",
"NormalizedName": "TENANT2", // <-- Add this property
"ConnectionStrings": {
"Default": "...tenant2's db connection string here..."
}
}
]
````
### Update `NormalizedName` in the database
Please add a sql script to your migration to set the `NormalizedName` property of the existing tenants. You can use the following script:
> This script is for the SQL Server database. You can change it for your database.
> The table name `SaasTenants` is used for ABP commercial Saas module. `AbpTenants` is for the ABP open-source Tenant Management module.
```sql
UPDATE SaasTenants SET NormalizedName = UPPER(Name) WHERE NormalizedName IS NULL OR NormalizedName = ''
```
```csharp
/// <inheritdoc />
public partial class Add_NormalizedName : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "NormalizedName",
table: "SaasTenants",
type: "nvarchar(64)",
nullable: false,
defaultValue: "");
migrationBuilder.Sql("UPDATE SaasTenants SET NormalizedName = UPPER(Name) WHERE NormalizedName IS NULL OR NormalizedName = ''");
migrationBuilder.CreateIndex(
name: "IX_SaasTenants_NormalizedName",
table: "SaasTenants",
column: "NormalizedName");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_SaasTenants_NormalizedName",
table: "SaasTenants");
migrationBuilder.DropColumn(
name: "NormalizedName",
table: "SaasTenants");
}
}
```
See https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/managing?tabs=dotnet-core-cli#adding-raw-sql to learn how to add raw SQL to migrations.

6
docs/en/Multi-Tenancy.md

@ -394,6 +394,8 @@ app.UseMultiTenancy();
`ITenantStore` is used to get the tenant configuration from a data source.
> Tenant names are not case-sensitive. `ITenantStore` will use the `NormalizedName` parameter to get tenants, You need to use `ITenantNormalizer` to normalize tenant names.
#### Tenant Management Module
The [tenant management module](Modules/Tenant-Management) is **included in the startup templates** and implements the `ITenantStore` interface to get the tenants and their configuration from a database. It also provides the necessary functionality and UI to manage the tenants and their connection strings.
@ -408,11 +410,13 @@ The [tenant management module](Modules/Tenant-Management) is **included in the s
"Tenants": [
{
"Id": "446a5211-3d72-4339-9adc-845151f8ada0",
"Name": "tenant1"
"Name": "tenant1",
"NormalizedName": "TENANT1"
},
{
"Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d",
"Name": "tenant2",
"NormalizedName": "TENANT2",
"ConnectionStrings": {
"Default": "...tenant2's db connection string here..."
}

20
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorRemoteTenantStore.cs

@ -23,13 +23,13 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency
Cache = cache;
}
public async Task<TenantConfiguration?> FindAsync(string name)
public async Task<TenantConfiguration?> FindAsync(string normalizedName)
{
var cacheKey = CreateCacheKey(name);
var cacheKey = CreateCacheKey(normalizedName);
var tenantConfiguration = await Cache.GetOrAddAsync(
cacheKey,
async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name))!,
async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(normalizedName))!,
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
@ -57,13 +57,13 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency
return tenantConfiguration;
}
public TenantConfiguration? Find(string name)
public TenantConfiguration? Find(string normalizedName)
{
var cacheKey = CreateCacheKey(name);
var cacheKey = CreateCacheKey(normalizedName);
var tenantConfiguration = Cache.GetOrAdd(
cacheKey,
() => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name)))!,
() => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(normalizedName)))!,
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
@ -98,16 +98,16 @@ public class MauiBlazorRemoteTenantStore : ITenantStore, ITransientDependency
return null;
}
return new TenantConfiguration(tenantResultDto.TenantId.Value, tenantResultDto.Name!);
return new TenantConfiguration(tenantResultDto.TenantId.Value, tenantResultDto.Name!, tenantResultDto.NormalizedName!);
}
protected virtual string CreateCacheKey(string tenantName)
protected virtual string CreateCacheKey(string normalizedName)
{
return $"RemoteTenantStore_Name_{tenantName}";
return $"RemoteTenantStore_Name_{normalizedName}";
}
protected virtual string CreateCacheKey(Guid tenantId)
{
return $"RemoteTenantStore_Id_{tenantId:N}";
}
}
}

5
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
@ -15,7 +16,7 @@ using Volo.Abp.Settings;
namespace Volo.Abp.AspNetCore.MultiTenancy;
public class MultiTenancyMiddleware : IMiddleware, ITransientDependency
public class MultiTenancyMiddleware : AbpMiddlewareBase, ITransientDependency
{
public ILogger<MultiTenancyMiddleware> Logger { get; set; }
@ -38,7 +39,7 @@ public class MultiTenancyMiddleware : IMiddleware, ITransientDependency
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
TenantConfiguration? tenant = null;
try

12
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcRemoteTenantStore.cs

@ -29,9 +29,9 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
Options = options.Value;
}
public async Task<TenantConfiguration?> FindAsync(string name)
public async Task<TenantConfiguration?> FindAsync(string normalizedName)
{
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name);
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(normalizedName);
var httpContext = HttpContextAccessor?.HttpContext;
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
@ -42,7 +42,7 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
var tenantConfiguration = await Cache.GetAsync(cacheKey);
if (tenantConfiguration == null)
{
await TenantAppService.FindTenantByNameAsync(name);
await TenantAppService.FindTenantByNameAsync(normalizedName);
tenantConfiguration = await Cache.GetAsync(cacheKey);
}
@ -79,9 +79,9 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
return tenantConfiguration?.Value;
}
public TenantConfiguration? Find(string name)
public TenantConfiguration? Find(string normalizedName)
{
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name);
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(normalizedName);
var httpContext = HttpContextAccessor?.HttpContext;
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
@ -92,7 +92,7 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
var tenantConfiguration = Cache.Get(cacheKey);
if (tenantConfiguration == null)
{
AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(name));
AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(normalizedName));
tenantConfiguration = Cache.Get(cacheKey);
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/MultiTenancy/FindTenantResultDto.cs

@ -11,5 +11,7 @@ public class FindTenantResultDto
public string? Name { get; set; }
public string? NormalizedName { get; set; }
public bool IsActive { get; set; }
}

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalFooterTagHelperService.cs

@ -90,13 +90,13 @@ public class AbpModalFooterTagHelperService : AbpTagHelperService<AbpModalFooter
return element.ToHtmlString();
}
protected virtual string GetCancelButton()
protected virtual string GetCancelButton(bool isDestructive = false)
{
var element = new TagBuilder("button");
element.Attributes.Add("type", "button");
element.Attributes.Add("data-bs-dismiss", "modal");
element.AddCssClass("btn");
element.AddCssClass("btn-secondary");
element.AddCssClass("btn-outline-primary");
element.InnerHtml.Append(_localizer["Cancel"]);
return element.ToHtmlString();

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs

@ -9,15 +9,17 @@ namespace Pages.Abp.MultiTenancy;
public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
{
protected ITenantStore TenantStore { get; }
protected ITenantNormalizer TenantNormalizer { get; }
public AbpTenantAppService(ITenantStore tenantStore)
public AbpTenantAppService(ITenantStore tenantStore, ITenantNormalizer tenantNormalizer)
{
TenantStore = tenantStore;
TenantNormalizer = tenantNormalizer;
}
public virtual async Task<FindTenantResultDto> FindTenantByNameAsync(string name)
{
var tenant = await TenantStore.FindAsync(name);
var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(name)!);
if (tenant == null)
{
@ -29,6 +31,7 @@ public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
Success = true,
TenantId = tenant.Id,
Name = tenant.Name,
NormalizedName = tenant.NormalizedName,
IsActive = tenant.IsActive
};
}
@ -47,6 +50,7 @@ public class AbpTenantAppService : ApplicationService, IAbpTenantAppService
Success = true,
TenantId = tenant.Id,
Name = tenant.Name,
NormalizedName = tenant.NormalizedName,
IsActive = tenant.IsActive
};
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs

@ -18,13 +18,16 @@ public class TenantSwitchModalModel : AbpPageModel
public TenantInfoModel Input { get; set; } = default!;
protected ITenantStore TenantStore { get; }
protected ITenantNormalizer TenantNormalizer { get; }
protected AbpAspNetCoreMultiTenancyOptions Options { get; }
public TenantSwitchModalModel(
ITenantStore tenantStore,
ITenantNormalizer tenantNormalizer,
IOptions<AbpAspNetCoreMultiTenancyOptions> options)
{
TenantStore = tenantStore;
TenantNormalizer = tenantNormalizer;
Options = options.Value;
LocalizationResourceType = typeof(AbpUiMultiTenancyResource);
}
@ -45,7 +48,7 @@ public class TenantSwitchModalModel : AbpPageModel
Guid? tenantId = null;
if (!Input.Name.IsNullOrEmpty())
{
var tenant = await TenantStore.FindAsync(Input.Name!);
var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(Input.Name!)!);
if (tenant == null)
{
throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]);

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js

@ -103,6 +103,13 @@ var abp = abp || {};
abp.libs.sweetAlert.config.default.confirmButtonText = l('Ok');
abp.libs.sweetAlert.config.default.denyButtonText = l('No');
abp.libs.sweetAlert.config.default.cancelButtonText = l('Cancel');
abp.libs.sweetAlert.config.default.buttonsStyling = false;
abp.libs.sweetAlert.config.default.customClass = {
confirmButton: "btn btn-primary",
cancelButton: "btn btn-outline-primary mx-2",
denyButton: "btn btn-outline-primary mx-2"
};
abp.libs.sweetAlert.config.confirm.title = l('AreYouSure');
abp.libs.sweetAlert.config.confirm.confirmButtonText = l('Yes');
abp.libs.sweetAlert.config.confirm.showCancelButton = true;

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

@ -14,6 +14,7 @@ using System.Linq;
using System.Net;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.RazorPages;
@ -25,6 +26,7 @@ using Volo.Abp.ApiVersioning;
using Volo.Abp.Application;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.AspNetCore.Mvc.ApiExploring;
using Volo.Abp.AspNetCore.Mvc.ApplicationModels;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.DependencyInjection;
@ -176,6 +178,7 @@ public class AbpAspNetCoreMvcModule : AbpModule
context.Services.Replace(ServiceDescriptor.Singleton<IValidationAttributeAdapterProvider, AbpValidationAttributeAdapterProvider>());
context.Services.AddSingleton<ValidationAttributeAdapterProvider>();
context.Services.TryAddEnumerable(ServiceDescriptor.Transient<IActionDescriptorProvider, AbpMvcActionDescriptorProvider>());
context.Services.AddOptions<MvcOptions>()
.Configure<IServiceProvider>((mvcOptions, serviceProvider) =>
{
@ -247,7 +250,7 @@ public class AbpAspNetCoreMvcModule : AbpModule
.Distinct();
AddToApplicationParts(partManager, controllerAssemblies);
var additionalAssemblies = moduleContainer
.Modules
.SelectMany(m => m.GetAdditionalAssemblies())

31
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcActionDescriptorProvider.cs

@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Volo.Abp.AspNetCore.Filters;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationModels;
public class AbpMvcActionDescriptorProvider : IActionDescriptorProvider
{
public virtual int Order => -1000 + 10;
public virtual void OnProvidersExecuting(ActionDescriptorProviderContext context)
{
}
public virtual void OnProvidersExecuted(ActionDescriptorProviderContext context)
{
foreach (var action in context.Results.Where(x => x is ControllerActionDescriptor).Cast<ControllerActionDescriptor>())
{
var disableAbpFeaturesAttribute = action.ControllerTypeInfo.GetCustomAttribute<DisableAbpFeaturesAttribute>(true);
if (disableAbpFeaturesAttribute != null && disableAbpFeaturesAttribute.DisableMvcFilters)
{
action.FilterDescriptors.RemoveAll(x => x.Filter is ServiceFilterAttribute serviceFilterAttribute &&
typeof(IAbpFilter).IsAssignableFrom(serviceFilterAttribute.ServiceType));
}
}
}
}

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs

@ -5,12 +5,13 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.Auditing;
public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency
public class AbpAuditActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditPageFilter.cs

@ -5,12 +5,13 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.Auditing;
public class AbpAuditPageFilter : IAsyncPageFilter, ITransientDependency
public class AbpAuditPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs

@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling;
@ -18,7 +19,7 @@ using Volo.Abp.Json;
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency
public class AbpExceptionFilter : IAsyncExceptionFilter, IAbpFilter, ITransientDependency
{
public virtual async Task OnExceptionAsync(ExceptionContext context)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs

@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling;
@ -18,7 +19,7 @@ using Volo.Abp.Json;
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
public class AbpExceptionPageFilter : IAsyncPageFilter, ITransientDependency
public class AbpExceptionPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs

@ -2,12 +2,13 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace Volo.Abp.AspNetCore.Mvc.Features;
public class AbpFeatureActionFilter : IAsyncActionFilter, ITransientDependency
public class AbpFeatureActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeaturePageFilter.cs

@ -2,12 +2,13 @@
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace Volo.Abp.AspNetCore.Mvc.Features;
public class AbpFeaturePageFilter : IAsyncPageFilter, ITransientDependency
public class AbpFeaturePageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeatureActionFilter.cs

@ -6,12 +6,13 @@ using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.GlobalFeatures;
namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures;
public class GlobalFeatureActionFilter : IAsyncActionFilter, ITransientDependency
public class GlobalFeatureActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/GlobalFeatures/GlobalFeaturePageFilter.cs

@ -6,12 +6,13 @@ using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Aspects;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.GlobalFeatures;
namespace Volo.Abp.AspNetCore.Mvc.GlobalFeatures;
public class GlobalFeaturePageFilter : IAsyncPageFilter, ITransientDependency
public class GlobalFeaturePageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs

@ -2,11 +2,12 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.Response;
public class AbpNoContentActionFilter : IAsyncActionFilter, ITransientDependency
public class AbpNoContentActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs

@ -4,12 +4,13 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Mvc.Uow;
public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency
public class AbpUowActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs

@ -4,13 +4,14 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.AspNetCore.Uow;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Mvc.Uow;
public class AbpUowPageFilter : IAsyncPageFilter, ITransientDependency
public class AbpUowPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependency
{
public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs

@ -3,13 +3,14 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.Validation;
public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
public class AbpValidationActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDependency
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{

5
framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs

@ -5,6 +5,7 @@ using Microsoft.Extensions.Options;
using Serilog.Context;
using Serilog.Core;
using Serilog.Core.Enrichers;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.Clients;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
@ -13,7 +14,7 @@ using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Serilog;
public class AbpSerilogMiddleware : IMiddleware, ITransientDependency
public class AbpSerilogMiddleware : AbpMiddlewareBase, ITransientDependency
{
private readonly ICurrentClient _currentClient;
private readonly ICurrentTenant _currentTenant;
@ -35,7 +36,7 @@ public class AbpSerilogMiddleware : IMiddleware, ITransientDependency
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var enrichers = new List<ILogEventEnricher>();

5
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs

@ -4,11 +4,12 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
namespace Microsoft.AspNetCore.RequestLocalization;
public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependency
public class AbpRequestLocalizationMiddleware : AbpMiddlewareBase, ITransientDependency
{
public const string HttpContextItemName = "__AbpSetCultureCookie";
@ -23,7 +24,7 @@ public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependenc
_loggerFactory = loggerFactory;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var middleware = new RequestLocalizationMiddleware(
next,

7
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
@ -11,7 +12,7 @@ using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Auditing;
public class AbpAuditingMiddleware : IMiddleware, ITransientDependency
public class AbpAuditingMiddleware : AbpMiddlewareBase, ITransientDependency
{
private readonly IAuditingManager _auditingManager;
protected AbpAuditingOptions AuditingOptions { get; }
@ -34,9 +35,9 @@ public class AbpAuditingMiddleware : IMiddleware, ITransientDependency
AspNetCoreAuditingOptions = aspNetCoreAuditingOptions.Value;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (!AuditingOptions.IsEnabled || IsIgnoredUrl(context))
if (await ShouldSkipAsync(context, next) || !AuditingOptions.IsEnabled || IsIgnoredUrl(context))
{
await next(context);
return;

5
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs

@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
@ -14,7 +15,7 @@ using Volo.Abp.Json;
namespace Volo.Abp.AspNetCore.ExceptionHandling;
public class AbpExceptionHandlingMiddleware : IMiddleware, ITransientDependency
public class AbpExceptionHandlingMiddleware : AbpMiddlewareBase, ITransientDependency
{
private readonly ILogger<AbpExceptionHandlingMiddleware> _logger;
@ -27,7 +28,7 @@ public class AbpExceptionHandlingMiddleware : IMiddleware, ITransientDependency
_clearCacheHeadersDelegate = ClearCacheHeaders;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{

6
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Filters/IAbpFilter.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AspNetCore.Filters;
public interface IAbpFilter
{
}

19
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Middleware/AbpMiddlewareBase.cs

@ -0,0 +1,19 @@
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
namespace Volo.Abp.AspNetCore.Middleware;
public abstract class AbpMiddlewareBase : IMiddleware
{
protected Task<bool> ShouldSkipAsync(HttpContext context, RequestDelegate next)
{
var endpoint = context.GetEndpoint();
var controllerActionDescriptor = endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>();
var disableAbpFeaturesAttribute = controllerActionDescriptor?.ControllerTypeInfo.GetCustomAttribute<DisableAbpFeaturesAttribute>();
return Task.FromResult(disableAbpFeaturesAttribute != null && disableAbpFeaturesAttribute.DisableMiddleware);
}
public abstract Task InvokeAsync(HttpContext context, RequestDelegate next);
}

5
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs

@ -5,11 +5,12 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Security;
public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency
public class AbpSecurityHeadersMiddleware : AbpMiddlewareBase, ITransientDependency
{
public IOptions<AbpSecurityHeadersOptions> Options { get; set; }
protected const string ScriptSrcKey = "script-src";
@ -20,7 +21,7 @@ public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency
Options = options;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
/*X-Content-Type-Options header tells the browser to not try and “guess” what a mimetype of a resource might be, and to just take what mimetype the server has returned as fact.*/
AddHeader(context, "X-Content-Type-Options", "nosniff");

5
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs

@ -4,14 +4,15 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Security.Claims;
public class AbpClaimsMapMiddleware : IMiddleware, ITransientDependency
public class AbpClaimsMapMiddleware : AbpMiddlewareBase, ITransientDependency
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var currentPrincipalAccessor = context.RequestServices
.GetRequiredService<ICurrentPrincipalAccessor>();

5
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs

@ -2,14 +2,15 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Security.Claims;
public class AbpDynamicClaimsMiddleware : IMiddleware, ITransientDependency
public class AbpDynamicClaimsMiddleware : AbpMiddlewareBase, ITransientDependency
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (context.User.Identity?.IsAuthenticated == true)
{

5
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs

@ -3,12 +3,13 @@ using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Tracing;
namespace Volo.Abp.AspNetCore.Tracing;
public class AbpCorrelationIdMiddleware : IMiddleware, ITransientDependency
public class AbpCorrelationIdMiddleware : AbpMiddlewareBase, ITransientDependency
{
private readonly AbpCorrelationIdOptions _options;
private readonly ICorrelationIdProvider _correlationIdProvider;
@ -20,7 +21,7 @@ public class AbpCorrelationIdMiddleware : IMiddleware, ITransientDependency
_correlationIdProvider = correlationIdProvider;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var correlationId = GetCorrelationIdFromRequest(context);
using (_correlationIdProvider.Change(correlationId))

7
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs

@ -3,12 +3,13 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Uow;
public class AbpUnitOfWorkMiddleware : IMiddleware, ITransientDependency
public class AbpUnitOfWorkMiddleware : AbpMiddlewareBase, ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly AbpAspNetCoreUnitOfWorkOptions _options;
@ -21,9 +22,9 @@ public class AbpUnitOfWorkMiddleware : IMiddleware, ITransientDependency
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (IsIgnoredUrl(context))
if (await ShouldSkipAsync(context, next) || IsIgnoredUrl(context))
{
await next(context);
return;

12
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
@ -34,7 +33,10 @@ public class WebContentFileProvider : IWebContentFileProvider, ISingletonDepende
public virtual IFileInfo GetFileInfo(string subpath)
{
Check.NotNullOrEmpty(subpath, nameof(subpath));
if (string.IsNullOrEmpty(subpath))
{
return new NotFoundFileInfo(subpath);
}
if (PathUtils.PathNavigatesAboveRoot(subpath))
{
@ -53,11 +55,9 @@ public class WebContentFileProvider : IWebContentFileProvider, ISingletonDepende
return _fileProvider.GetFileInfo(_rootPath + subpath);
}
public virtual IDirectoryContents GetDirectoryContents([NotNull] string subpath)
public virtual IDirectoryContents GetDirectoryContents(string subpath)
{
Check.NotNullOrEmpty(subpath, nameof(subpath));
if (PathUtils.PathNavigatesAboveRoot(subpath))
if (subpath == null || PathUtils.PathNavigatesAboveRoot(subpath))
{
return NotFoundDirectoryContents.Singleton;
}

26
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs

@ -13,19 +13,31 @@ public class PermissionValueProviderManager : IPermissionValueProviderManager, I
private readonly Lazy<List<IPermissionValueProvider>> _lazyProviders;
protected AbpPermissionOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
public PermissionValueProviderManager(
IServiceProvider serviceProvider,
IOptions<AbpPermissionOptions> options)
{
Options = options.Value;
ServiceProvider = serviceProvider;
_lazyProviders = new Lazy<List<IPermissionValueProvider>>(
() => Options
.ValueProviders
.Select(c => serviceProvider.GetRequiredService(c) as IPermissionValueProvider)
.ToList()!,
true
);
_lazyProviders = new Lazy<List<IPermissionValueProvider>>(GetProviders, true);
}
protected virtual List<IPermissionValueProvider> GetProviders()
{
var providers = Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IPermissionValueProvider)!)
.ToList();
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1);
if(multipleProviders != null)
{
throw new AbpException($"Duplicate permission value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}");
}
return providers;
}
}

17
framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs

@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac.Core;
using Autofac.Extras.DynamicProxy;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Autofac;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Modularity;
namespace Autofac.Builder;
@ -75,11 +78,15 @@ public static class AbpRegistrationBuilderExtensions
if (serviceRegistredArgs.Interceptors.Any())
{
registrationBuilder = registrationBuilder.AddInterceptors(
registrationActionList,
serviceType,
serviceRegistredArgs.Interceptors
);
var disableAbpFeaturesAttribute = serviceRegistredArgs.ImplementationType.GetCustomAttribute<DisableAbpFeaturesAttribute>(true);
if (disableAbpFeaturesAttribute == null || !disableAbpFeaturesAttribute.DisableInterceptors)
{
registrationBuilder = registrationBuilder.AddInterceptors(
registrationActionList,
serviceType,
serviceRegistredArgs.Interceptors
);
}
}
return registrationBuilder;

2
framework/src/Volo.Abp.BlazoriseUI/Components/UiMessageAlert.razor

@ -22,7 +22,7 @@
<ModalFooter class="d-flex justify-content-center">
@if ( IsConfirmation )
{
<Button Color="Color.Danger" Padding="Padding.Is3.OnX" Margin="Margin.Is1.OnX" Clicked="@OnCancelClicked">
<Button Color="Color.Primary" Outline Padding="Padding.Is3.OnX" Margin="Margin.Is1.OnX" Clicked="@OnCancelClicked">
@if ( Options?.CancelButtonIcon != null )
{
<Icon Name="@Options.CancelButtonIcon" Margin="Margin.Is2.FromEnd" />

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs

@ -1,4 +1,4 @@
using System.Text;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Commands.Internal;

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

@ -31,7 +31,6 @@
<PackageReference Include="System.Linq.Dynamic.Core" />
<PackageReference Include="System.Linq.Queryable" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Nito.AsyncEx.Coordination" />
<PackageReference Include="Nito.AsyncEx.Context" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFrameworkIdentifier)' == '.NETStandard' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '2.1')) ">

25
framework/src/Volo.Abp.Core/Volo/Abp/DisableAbpFeaturesAttribute.cs

@ -0,0 +1,25 @@
using System;
namespace Volo.Abp;
[AttributeUsage(AttributeTargets.Class)]
public class DisableAbpFeaturesAttribute : Attribute
{
/// <summary>
/// The framework will not register any interceptors for the class.
/// This will cause the all features that depend on interceptors to not work.
/// </summary>
public bool DisableInterceptors { get; set; } = true;
/// <summary>
/// The framework middleware will skip the class.
/// This will cause the all features that depend on middleware to not work.
/// </summary>
public bool DisableMiddleware { get; set; } = true;
/// <summary>
/// The framework will not remove all built-in filters for the class.
/// This will cause the all features that depend on filters to not work.
/// </summary>
public bool DisableMvcFilters { get; set; } = true;
}

20
framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs

@ -12,34 +12,26 @@ public class FeatureChecker : FeatureCheckerBase
protected AbpFeatureOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
protected List<IFeatureValueProvider> Providers => _providers.Value;
private readonly Lazy<List<IFeatureValueProvider>> _providers;
protected IFeatureValueProviderManager FeatureValueProviderManager { get; }
public FeatureChecker(
IOptions<AbpFeatureOptions> options,
IServiceProvider serviceProvider,
IFeatureDefinitionManager featureDefinitionManager)
IFeatureDefinitionManager featureDefinitionManager,
IFeatureValueProviderManager featureValueProviderManager)
{
ServiceProvider = serviceProvider;
FeatureDefinitionManager = featureDefinitionManager;
FeatureValueProviderManager = featureValueProviderManager;
Options = options.Value;
_providers = new Lazy<List<IFeatureValueProvider>>(
() => Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IFeatureValueProvider)!)
.ToList(),
true
);
}
public override async Task<string?> GetOrNullAsync(string name)
{
var featureDefinition = await FeatureDefinitionManager.GetAsync(name);
var providers = Enumerable
.Reverse(Providers);
var providers = FeatureValueProviderManager.ValueProviders
.Reverse();
if (featureDefinition.AllowedProviders.Any())
{

43
framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProviderManager.cs

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Features;
public class FeatureValueProviderManager : IFeatureValueProviderManager, ISingletonDependency
{
public IReadOnlyList<IFeatureValueProvider> ValueProviders => _lazyProviders.Value;
private readonly Lazy<List<IFeatureValueProvider>> _lazyProviders;
protected AbpFeatureOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
public FeatureValueProviderManager(
IServiceProvider serviceProvider,
IOptions<AbpFeatureOptions> options)
{
Options = options.Value;
ServiceProvider = serviceProvider;
_lazyProviders = new Lazy<List<IFeatureValueProvider>>(GetProviders, true);
}
protected virtual List<IFeatureValueProvider> GetProviders()
{
var providers = Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IFeatureValueProvider)!)
.ToList();
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1);
if(multipleProviders != null)
{
throw new AbpException($"Duplicate feature value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}");
}
return providers;
}
}

8
framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureValueProviderManager.cs

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Volo.Abp.Features;
public interface IFeatureValueProviderManager
{
IReadOnlyList<IFeatureValueProvider> ValueProviders { get; }
}

6
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantNormalizer.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.MultiTenancy;
public interface ITenantNormalizer
{
string? NormalizeName(string? name);
}

4
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/ITenantStore.cs

@ -5,12 +5,12 @@ namespace Volo.Abp.MultiTenancy;
public interface ITenantStore
{
Task<TenantConfiguration?> FindAsync(string name);
Task<TenantConfiguration?> FindAsync(string normalizedName);
Task<TenantConfiguration?> FindAsync(Guid id);
[Obsolete("Use FindAsync method.")]
TenantConfiguration? Find(string name);
TenantConfiguration? Find(string normalizedName);
[Obsolete("Use FindAsync method.")]
TenantConfiguration? Find(Guid id);

10
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs

@ -11,6 +11,8 @@ public class TenantConfiguration
public string Name { get; set; } = default!;
public string NormalizedName { get; set; } = default!;
public ConnectionStrings? ConnectionStrings { get; set; }
public bool IsActive { get; set; }
@ -30,4 +32,12 @@ public class TenantConfiguration
ConnectionStrings = new ConnectionStrings();
}
public TenantConfiguration(Guid id, [NotNull] string name, [NotNull] string normalizedName)
: this(id, name)
{
Check.NotNull(normalizedName, nameof(normalizedName));
NormalizedName = normalizedName;
}
}

11
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/UpperInvariantTenantNormalizer.cs

@ -0,0 +1,11 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.MultiTenancy;
public class UpperInvariantTenantNormalizer : ITenantNormalizer, ITransientDependency
{
public virtual string? NormalizeName(string? name)
{
return name?.Normalize().ToUpperInvariant();
}
}

8
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ConfigurationStore/DefaultTenantStore.cs

@ -16,9 +16,9 @@ public class DefaultTenantStore : ITenantStore, ITransientDependency
_options = options.CurrentValue;
}
public Task<TenantConfiguration?> FindAsync(string name)
public Task<TenantConfiguration?> FindAsync(string normalizedName)
{
return Task.FromResult(Find(name));
return Task.FromResult(Find(normalizedName));
}
public Task<TenantConfiguration?> FindAsync(Guid id)
@ -26,9 +26,9 @@ public class DefaultTenantStore : ITenantStore, ITransientDependency
return Task.FromResult(Find(id));
}
public TenantConfiguration? Find(string name)
public TenantConfiguration? Find(string normalizedName)
{
return _options.Tenants?.FirstOrDefault(t => t.Name == name);
return _options.Tenants?.FirstOrDefault(t => t.NormalizedName == normalizedName);
}
public TenantConfiguration? Find(Guid id)

7
framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfigurationProvider.cs

@ -10,6 +10,7 @@ public class TenantConfigurationProvider : ITenantConfigurationProvider, ITransi
{
protected virtual ITenantResolver TenantResolver { get; }
protected virtual ITenantStore TenantStore { get; }
protected virtual ITenantNormalizer TenantNormalizer { get; }
protected virtual ITenantResolveResultAccessor TenantResolveResultAccessor { get; }
protected virtual IStringLocalizer<AbpMultiTenancyResource> StringLocalizer { get; }
@ -17,10 +18,12 @@ public class TenantConfigurationProvider : ITenantConfigurationProvider, ITransi
ITenantResolver tenantResolver,
ITenantStore tenantStore,
ITenantResolveResultAccessor tenantResolveResultAccessor,
IStringLocalizer<AbpMultiTenancyResource> stringLocalizer)
IStringLocalizer<AbpMultiTenancyResource> stringLocalizer,
ITenantNormalizer tenantNormalizer)
{
TenantResolver = tenantResolver;
TenantStore = tenantStore;
TenantNormalizer = tenantNormalizer;
TenantResolveResultAccessor = tenantResolveResultAccessor;
StringLocalizer = stringLocalizer;
}
@ -69,7 +72,7 @@ public class TenantConfigurationProvider : ITenantConfigurationProvider, ITransi
}
else
{
return await TenantStore.FindAsync(tenantIdOrName);
return await TenantStore.FindAsync(TenantNormalizer.NormalizeName(tenantIdOrName)!);
}
}
}

27
framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProviderManager.cs

@ -10,7 +10,9 @@ namespace Volo.Abp.Settings;
public class SettingValueProviderManager : ISettingValueProviderManager, ISingletonDependency
{
public List<ISettingValueProvider> Providers => _lazyProviders.Value;
protected AbpSettingOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
private readonly Lazy<List<ISettingValueProvider>> _lazyProviders;
public SettingValueProviderManager(
@ -19,13 +21,24 @@ public class SettingValueProviderManager : ISettingValueProviderManager, ISingle
{
Options = options.Value;
ServiceProvider = serviceProvider;
_lazyProviders = new Lazy<List<ISettingValueProvider>>(GetProviders, true);
}
protected virtual List<ISettingValueProvider> GetProviders()
{
var providers = Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as ISettingValueProvider)!)
.ToList();
var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1);
if(multipleProviders != null)
{
throw new AbpException($"Duplicate setting value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}");
}
_lazyProviders = new Lazy<List<ISettingValueProvider>>(
() => Options
.ValueProviders
.Select(type => serviceProvider.GetRequiredService(type) as ISettingValueProvider)
.ToList()!,
true
);
return providers;
}
}

3
framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs

@ -16,6 +16,7 @@ public class AspNetCoreMultiTenancy_WithDomainResolver_Tests : AspNetCoreMultiTe
{
private readonly Guid _testTenantId = Guid.NewGuid();
private readonly string _testTenantName = "acme";
private readonly string _testTenantNormalizedName = "ACME";
private readonly AbpAspNetCoreMultiTenancyOptions _options;
@ -30,7 +31,7 @@ public class AspNetCoreMultiTenancy_WithDomainResolver_Tests : AspNetCoreMultiTe
{
options.Tenants = new[]
{
new TenantConfiguration(_testTenantId, _testTenantName)
new TenantConfiguration(_testTenantId, _testTenantName, _testTenantNormalizedName)
};
});

3
framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs

@ -17,6 +17,7 @@ public class AspNetCoreMultiTenancy_Without_DomainResolver_Tests : AspNetCoreMul
{
private readonly Guid _testTenantId = Guid.NewGuid();
private readonly string _testTenantName = "acme";
private readonly string _testTenantNormalizedName = "ACME";
private readonly AbpAspNetCoreMultiTenancyOptions _options;
@ -31,7 +32,7 @@ public class AspNetCoreMultiTenancy_Without_DomainResolver_Tests : AspNetCoreMul
{
options.Tenants = new[]
{
new TenantConfiguration(_testTenantId, _testTenantName)
new TenantConfiguration(_testTenantId, _testTenantName, _testTenantNormalizedName)
};
});

5
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/FakeAuthenticationMiddleware.cs

@ -3,11 +3,12 @@ using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc;
public class FakeAuthenticationMiddleware : IMiddleware, ITransientDependency
public class FakeAuthenticationMiddleware : AbpMiddlewareBase, ITransientDependency
{
private readonly FakeUserClaims _fakeUserClaims;
@ -16,7 +17,7 @@ public class FakeAuthenticationMiddleware : IMiddleware, ITransientDependency
_fakeUserClaims = fakeUserClaims;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (_fakeUserClaims.Claims.Any())
{

74
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Filters/MvcDisableAbpFeaturesAttribute_Tests.cs

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Shouldly;
using Volo.Abp.AspNetCore.Mvc.Auditing;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.Features;
using Volo.Abp.AspNetCore.Mvc.GlobalFeatures;
using Volo.Abp.AspNetCore.Mvc.Response;
using Volo.Abp.AspNetCore.Mvc.Uow;
using Volo.Abp.AspNetCore.Mvc.Validation;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Filters;
[Route("api/enabled-features-test")]
public class EnabledAbpFeaturesController : AbpController, IRemoteService
{
[HttpGet]
public Task<List<string>> GetAsync()
{
var filters = HttpContext.GetEndpoint().Metadata.GetMetadata<ControllerActionDescriptor>()
.FilterDescriptors.Where(x => x.Filter is ServiceFilterAttribute)
.Select(x => x.Filter.As<ServiceFilterAttribute>().ServiceType.FullName).ToList();
return Task.FromResult(filters);
}
}
[Route("api/disabled-features-test")]
[DisableAbpFeatures]
public class DisabledAbpFeaturesController : AbpController, IRemoteService
{
[HttpGet]
public Task<List<string>> GetAsync()
{
var filters = HttpContext.GetEndpoint().Metadata.GetMetadata<ControllerActionDescriptor>()
.FilterDescriptors.Where(x => x.Filter is ServiceFilterAttribute)
.Select(x => x.Filter.As<ServiceFilterAttribute>().ServiceType.FullName).ToList();
return Task.FromResult(filters);
}
}
public class MvcDisableAbpFeaturesAttribute_Tests : AspNetCoreMvcTestBase
{
[Fact]
public async Task Should_Disable_MVC_Filters()
{
var filters = await GetResponseAsObjectAsync<List<string>>("/api/enabled-features-test");
filters.ShouldContain(typeof(GlobalFeatureActionFilter).FullName);
filters.ShouldContain(typeof(AbpAuditActionFilter).FullName);
filters.ShouldContain(typeof(AbpNoContentActionFilter).FullName);
filters.ShouldContain(typeof(AbpFeatureActionFilter).FullName);
filters.ShouldContain(typeof(AbpValidationActionFilter).FullName);
filters.ShouldContain(typeof(AbpUowActionFilter).FullName);
filters.ShouldContain(typeof(AbpExceptionFilter).FullName);
filters = await GetResponseAsObjectAsync<List<string>>("/api/disabled-features-test");
filters.ShouldNotContain(typeof(GlobalFeatureActionFilter).FullName);
filters.ShouldNotContain(typeof(AbpAuditActionFilter).FullName);
filters.ShouldNotContain(typeof(AbpNoContentActionFilter).FullName);
filters.ShouldNotContain(typeof(AbpFeatureActionFilter).FullName);
filters.ShouldNotContain(typeof(AbpValidationActionFilter).FullName);
filters.ShouldNotContain(typeof(AbpUowActionFilter).FullName);
filters.ShouldNotContain(typeof(AbpExceptionFilter).FullName);
}
}

3
framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs

@ -20,6 +20,7 @@ public class Serilog_Enrichers_Tests : AbpSerilogTestBase
private readonly Guid _testTenantId = Guid.NewGuid();
private readonly string _testTenantName = "acme";
private readonly string _testTenantNormalizedName = "ACME";
private readonly AbpAspNetCoreMultiTenancyOptions _tenancyOptions;
private readonly AbpAspNetCoreSerilogOptions _serilogOptions;
@ -39,7 +40,7 @@ public class Serilog_Enrichers_Tests : AbpSerilogTestBase
{
options.Tenants = new[]
{
new TenantConfiguration(_testTenantId, _testTenantName)
new TenantConfiguration(_testTenantId, _testTenantName, _testTenantNormalizedName)
};
});
base.ConfigureServices(services);

59
framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs

@ -0,0 +1,59 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Authorization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Authorization.TestServices;
using Xunit;
namespace Volo.Abp;
public class PermissionValueProviderManager_Tests: AuthorizationTestBase
{
private readonly IPermissionValueProviderManager _permissionValueProviderManager;
public PermissionValueProviderManager_Tests()
{
_permissionValueProviderManager = GetRequiredService<IPermissionValueProviderManager>();
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.Services.Configure<AbpPermissionOptions>(permissionOptions =>
{
permissionOptions.ValueProviders.Add<TestDuplicatePermissionValueProvider>();
});
}
[Fact]
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected()
{
var exception = Assert.Throws<AbpException>(() =>
{
var providers = _permissionValueProviderManager.ValueProviders;
});
exception.Message.ShouldBe($"Duplicate permission value provider name detected: TestPermissionValueProvider1. Providers:{Environment.NewLine}{typeof(TestDuplicatePermissionValueProvider).FullName}{Environment.NewLine}{typeof(TestPermissionValueProvider1).FullName}");
}
}
public class TestDuplicatePermissionValueProvider : PermissionValueProvider
{
public TestDuplicatePermissionValueProvider(IPermissionStore permissionStore) : base(permissionStore)
{
}
public override string Name => "TestPermissionValueProvider1";
public override Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
{
throw new NotImplementedException();
}
public override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
{
throw new NotImplementedException();
}
}

31
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs

@ -15,22 +15,34 @@ public abstract class AbpInterceptionTestBase<TStartupModule> : AbpAsyncIntegrat
services.AddTransient<SimpleAsyncInterceptor>();
services.AddTransient<SimpleAsyncInterceptor2>();
services.AddTransient<SimpleInterceptionTargetClass>();
services.AddTransient<DisableInterceptionTargetClass>();
services.AddTransient<SimpleResultCacheTestInterceptor>();
services.AddTransient<CachedTestObject>();
services.AddTransient<AlwaysExceptionAsyncInterceptor>();
services.OnRegistered(registration =>
{
if (typeof(SimpleInterceptionTargetClass) == registration.ImplementationType)
{
registration.Interceptors.Add<SimpleAsyncInterceptor>();
registration.Interceptors.Add<SimpleAsyncInterceptor2>();
registration.Interceptors.Add<SimpleResultCacheTestInterceptor>();
}
if (typeof(CachedTestObject) == registration.ImplementationType)
{
registration.Interceptors.Add<SimpleResultCacheTestInterceptor>();
}
if (typeof(DisableInterceptionTargetClass) == registration.ImplementationType)
{
registration.Interceptors.Add<SimpleAsyncInterceptor>();
registration.Interceptors.Add<SimpleAsyncInterceptor2>();
registration.Interceptors.Add<SimpleResultCacheTestInterceptor>();
registration.Interceptors.Add<AlwaysExceptionAsyncInterceptor>();
}
});
return Task.CompletedTask;
@ -96,4 +108,23 @@ public abstract class AbpInterceptionTestBase<TStartupModule> : AbpAsyncIntegrat
(await target.GetValueAsync(43)).ShouldBe(42); //First run, cached previous value
(await target.GetValueAsync(44)).ShouldBe(42); //First run, cached previous value
}
[Fact]
public async Task Should_Disable_Interceptors()
{
//Arrange
var target = ServiceProvider.GetService<DisableInterceptionTargetClass>();
//Act
await target.DoItAsync();
//Assert
target.Logs.Count.ShouldBe(3);
target.Logs[0].ShouldBe("EnterDoItAsync");
target.Logs[1].ShouldBe("MiddleDoItAsync");
target.Logs[2].ShouldBe("ExitDoItAsync");
}
}

11
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AlwaysExceptionAsyncInterceptor.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Volo.Abp.DynamicProxy;
public class AlwaysExceptionAsyncInterceptor : AbpInterceptor
{
public override Task InterceptAsync(IAbpMethodInvocation invocation)
{
throw new AbpException("This interceptor should not be executed!");
}
}

41
framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/DisableInterceptionTargetClass.cs

@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.TestBase.Logging;
namespace Volo.Abp.DynamicProxy;
[DisableAbpFeatures]
public class DisableInterceptionTargetClass : ICanLogOnObject
{
public List<string> Logs { get; } = new List<string>();
public virtual void DoIt()
{
Logs.Add("ExecutingDoIt");
}
public virtual int GetValue()
{
Logs.Add("ExecutingGetValue");
return 42;
}
public virtual async Task<int> GetValueAsync()
{
Logs.Add("EnterGetValueAsync");
await Task.Delay(5);
Logs.Add("MiddleGetValueAsync");
await Task.Delay(5);
Logs.Add("ExitGetValueAsync");
return 42;
}
public virtual async Task DoItAsync()
{
Logs.Add("EnterDoItAsync");
await Task.Delay(5);
Logs.Add("MiddleDoItAsync");
await Task.Delay(5);
Logs.Add("ExitDoItAsync");
}
}

54
framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureValueProviderManager_Tests.cs

@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace Volo.Abp.Features;
public class FeatureValueProviderManager_Tests : FeatureTestBase
{
private readonly IFeatureValueProviderManager _featureValueProviderManager;
public FeatureValueProviderManager_Tests()
{
_featureValueProviderManager = GetRequiredService<IFeatureValueProviderManager>();
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.Services.Configure<AbpFeatureOptions>(permissionOptions =>
{
permissionOptions.ValueProviders.Add<TestDuplicateFeatureValueProvider>();
});
}
[Fact]
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected()
{
var exception = Assert.Throws<AbpException>(() =>
{
var providers = _featureValueProviderManager.ValueProviders;
});
exception.Message.ShouldBe($"Duplicate feature value provider name detected: {TestDuplicateFeatureValueProvider.ProviderName}. Providers:{Environment.NewLine}{typeof(TestDuplicateFeatureValueProvider).FullName}{Environment.NewLine}{typeof(DefaultValueFeatureValueProvider).FullName}");
}
}
public class TestDuplicateFeatureValueProvider : FeatureValueProvider
{
public const string ProviderName = "D";
public override string Name => ProviderName;
public TestDuplicateFeatureValueProvider(IFeatureStore settingStore)
: base(settingStore)
{
}
public override Task<string> GetOrNullAsync(FeatureDefinition setting)
{
throw new NotImplementedException();
}
}

62
framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingValueProviderManager_Tests.cs

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Settings;
public class SettingValueProviderManager_Tests: AbpIntegratedTest<AbpSettingsTestModule>
{
private readonly ISettingValueProviderManager _settingValueProviderManager;
public SettingValueProviderManager_Tests()
{
_settingValueProviderManager = GetRequiredService<ISettingValueProviderManager>();
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
options.Services.Configure<AbpSettingOptions>(settingOptions =>
{
settingOptions.ValueProviders.Add<TestDuplicateSettingValueProvider>();
});
}
[Fact]
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected()
{
var exception = Assert.Throws<AbpException>(() =>
{
var providers = _settingValueProviderManager.Providers;
});
exception.Message.ShouldBe($"Duplicate setting value provider name detected: {TestDuplicateSettingValueProvider.ProviderName}. Providers:{Environment.NewLine}{typeof(TestDuplicateSettingValueProvider).FullName}{Environment.NewLine}{typeof(TestSettingValueProvider).FullName}");
}
}
public class TestDuplicateSettingValueProvider : ISettingValueProvider, ITransientDependency
{
public const string ProviderName = "Test";
public string Name => ProviderName;
public TestDuplicateSettingValueProvider()
{
}
public Task<string> GetOrNullAsync(SettingDefinition setting)
{
throw new NotImplementedException();
}
public Task<List<SettingValue>> GetAllAsync(SettingDefinition[] settings)
{
throw new NotImplementedException();
}
}

2
modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml

@ -132,7 +132,7 @@
</abp-card-body>
<abp-card-footer>
<abp-button button-type="Primary" type="button" text="@L["SaveAsDraft"].Value" id="button-blog-post-create" />
<abp-button button-type="Outline_Primary" type="button" text="@L["SaveAsDraft"].Value" id="button-blog-post-create" />
@if ((await AuthorizationService.AuthorizeAsync(CmsKitAdminPermissions.BlogPosts.Publish)).Succeeded)
{
<abp-button button-type="Primary" type="button" text="@L["Publish"].Value" id="button-blog-post-publish"/>

56
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml

@ -332,28 +332,46 @@
</abp-column>
</abp-row>
<abp-row class="gx-2">
@foreach (var parameter in Model.DocumentPreferences.Parameters)
{
<div class="col">
<div class="custom-input-group">
<span class="input-group-text" id="@("Section" + parameter.Name + "ComboboxAddonId")">@(parameter.DisplayName)</span>
<select class="doc-section-combobox form-select"
aria-describedby="@("Section" + parameter.Name + "ComboboxAddonId")"
id="@("Section" + parameter.Name + "ComboboxId")" data-key="@parameter.Name">
@foreach (var value in parameter.Values.OrderBy(p => p.Value))
{
@if (value.Key == (Model.UserPreferences.ContainsKey(parameter.Name) ? Model.UserPreferences[parameter.Name] : null))
{
<option value="@value.Key" selected="selected">@value.Value</option>
}
else
@{
const int maxCellCount = 3;
var count = Model.DocumentPreferences.Parameters.Count;
var rowCount = count / maxCellCount + (count % maxCellCount > 0 ? 1 : 0);
var cellSize = 12 / (count > maxCellCount ? maxCellCount : count);
var latestCellSize = 12 / count - (rowCount - 1) * maxCellCount;
string BuildParameterDivClass(int index)
{
var row = index / maxCellCount;
var isLastRow = row == rowCount - 1;
var currentCellSize = isLastRow ? latestCellSize : cellSize;
return $"col-12 col-lg-{currentCellSize} mb-lg-{(isLastRow ? "0" : "2")} {(index == count - 1 ? "" : "mb-2")}";
}
for (var i = 0; i < count; ++i)
{
var parameter = Model.DocumentPreferences.Parameters[i];
<div class="@BuildParameterDivClass(i)">
<div class="custom-input-group">
<span class="input-group-text" id="@("Section" + parameter.Name + "ComboboxAddonId")">@(parameter.DisplayName)</span>
<select class="doc-section-combobox form-select"
aria-describedby="@("Section" + parameter.Name + "ComboboxAddonId")"
id="@("Section" + parameter.Name + "ComboboxId")" data-key="@parameter.Name">
@foreach (var value in parameter.Values.OrderBy(p => p.Value))
{
<option value="@value.Key">@value.Value</option>
@if (value.Key == (Model.UserPreferences.ContainsKey(parameter.Name) ? Model.UserPreferences[parameter.Name] : null))
{
<option value="@value.Key" selected="selected">@value.Value</option>
}
else
{
<option value="@value.Key">@value.Value</option>
}
}
}
</select>
</select>
</div>
</div>
</div>
}
}
</abp-row>
</div>

2
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js

@ -283,7 +283,7 @@
initDocumentNodeBreadcrumb();
Element.prototype.querySelector = function (selector) {
var result = $(decodeURI(selector));
var result = $(this).find(decodeURI(selector));
if(result.length > 0){
return result[0];
}

4
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor

@ -95,8 +95,8 @@
</Tabs>
</ModalBody>
<ModalFooter>
<Button Color="Color.Primary" Clicked="@(async () => await DeleteAsync(ProviderName,ProviderKey))">@L["ResetToDefault"]</Button>
<Button Color="Color.Secondary" Clicked="CloseModal">@L["Cancel"]</Button>
<Button class="btn btn-link" Clicked="CloseModal">@L["Cancel"]</Button>
<Button Color="Color.Primary" Outline Clicked="@(async () => await DeleteAsync(ProviderName,ProviderKey))">@L["ResetToDefault"]</Button>
<Button Color="Color.Primary" Clicked="SaveAsync">@L["Save"]</Button>
</ModalFooter>
}

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs

@ -144,7 +144,7 @@ public class FeatureManager : IFeatureManager, ISingletonDependency
if (!providers.Any())
{
return;
throw new AbpException($"Unknown feature value provider: {providerName}");
}
if (providers.Count > 1 && !forceToSet && value != null)

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

Loading…
Cancel
Save