diff --git a/.github/labeler.yml b/.github/labeler.yml index 738b727317..cb0c9cddbd 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,4 +1,15 @@ ui-angular: + - npm/ng-packs/* - npm/ng-packs/**/* + - npm/ng-packs/**/**/* + - npm/ng-packs/**/**/**/* + - npm/ng-packs/**/**/**/**/* + - npm/ng-packs/**/**/**/**/**/* + - templates/app/angular/* - templates/app/angular/**/* + - templates/app/angular/**/**/* + - templates/app/angular/**/**/**/* + - templates/module/angular/* - templates/module/angular/**/* + - templates/module/angular/**/**/* + - templates/module/angular/**/**/**/* diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index e70e966d4a..f24ba57949 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -1,17 +1,12 @@ -name: "Pull Request Labeler" +name: Pull request labeler on: - pull_request: - paths: - - npm/ng-packs/**/* - - templates/app/angular/**/* - - templates/module/angular/**/* - branches: - - master - - dev + schedule: + - cron: '0 12 */1 * *' jobs: labeler: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - - uses: actions/labeler@v2 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" + - uses: paulfantom/periodic-labeler@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/README.md b/README.md index c22fe5ec4b..1b4d56dd26 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ Framework solution is located under the `framework` folder. It has no external d [Modules](modules/) and [Templates](templates/) have their own solutions and have **local references** to the framework and each other. +Visual Studio can not work properly with the local references out of the solution folder. When you open a module/sample solution in the Visual Studio, you may get some errors related to the dependencies. In this case, run the `dotnet restore` on the command prompt for the related solution's folder. You need to run it after you first open the solution or change a dependency. + ### Contribution ABP is an open source platform. Check [the contribution guide](docs/en/Contribution/Index.md) if you want to contribute to the project. diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj index 7c8af93c47..aaebfafe6f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj @@ -5,7 +5,7 @@ - + diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs index 19c707bfad..37541b4d4c 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs @@ -8,13 +8,14 @@ using AbpIoLocalization.Support.Localization; using AbpIoLocalization.Www; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace AbpIoLocalization { - [DependsOn(typeof(AbpLocalizationModule))] + [DependsOn(typeof(AbpValidationModule))] public class AbpIoLocalizationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..58d01109b5 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hant.json @@ -0,0 +1,13 @@ +{ + "culture": "zh-Hant", + "texts": { + "Account": "帳號", + "Welcome": "歡迎", + "UseOneOfTheFollowingLinksToContinue": "使用下面的連結繼續", + "FrameworkHomePage": "框架首頁", + "FrameworkDocumentation": "框架文件", + "OfficialBlog": "官方部落格", + "CommercialHomePage": "商業版首頁", + "CommercialSupportWebSite": "商業版支援網站" + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..4787d74b25 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json @@ -0,0 +1,60 @@ +{ + "culture": "zh-Hant", + "texts": { + "Permission:NpmPackages": "NPM套件", + "Permission:NugetPackages": "Nuget套件", + "Permission:Maintenance": "維護", + "Permission:Maintain": "維護", + "Permission:ClearCaches": "清除快取", + "Permission:Modules": "模組", + "Permission:Packages": "套件", + "Permission:Edit": "編輯", + "Permission:Delete": "刪除", + "Permission:Create": "建立", + "Menu:Packages": "套件", + "NpmPackageDeletionWarningMessage": "該NPM套件將會被刪除. 你確定嗎?", + "NugetPackageDeletionWarningMessage": "該Nuget套件將會被刪除. 你確定嗎?", + "ModuleDeletionWarningMessage": "該模組將會被刪除. 你確定嗎?", + "Name": "名稱", + "DisplayName": "顯示名稱", + "ShortDescription": "簡述", + "NameFilter": "名稱", + "CreationTime": "建立時間", + "IsPro": "是否為專業版", + "EfCoreConfigureMethodName": "設定方法", + "IsProFilter": "是否為專業版", + "ApplicationType": "應用程式類型", + "Target": "目標", + "TargetFilter": "目標", + "ModuleClass": "模組分類", + "NugetPackageTarget.DomainShared": "Domain Shared", + "NugetPackageTarget.Domain": "Domain", + "NugetPackageTarget.Application": "Application", + "NugetPackageTarget.ApplicationContracts": "Application Contracts", + "NugetPackageTarget.HttpApi": "Http Api", + "NugetPackageTarget.HttpApiClient": "Http Api Client", + "NugetPackageTarget.Web": "Web", + "NugetPackageTarget.EntityFrameworkCore": "EntityFramework Core", + "NugetPackageTarget.MongoDB": "MongoDB", + "Edit": "編輯", + "Delete": "刪除", + "Refresh": "刷新", + "NpmPackages": "NPM套件", + "NugetPackages": "Nuget套件", + "NpmPackageCount": "NPM套件數量", + "NugetPackageCount": "Nuget套件數量", + "Module": "模組", + "ModuleInfo": "模組信息", + "CreateANpmPackage": "建立NPM套件", + "CreateAModule": "建立模組", + "CreateANugetPackage": "建立Nuget套件", + "AddNew": "建立", + "PackageAlreadyExist{0}": "\"{0}\"已經被添加.", + "ClearCache": "清除快取", + "SuccessfullyCleared": "清除成功", + "Menu:NpmPackages": "NPM套件", + "Menu:Modules": "模組", + "Menu:Maintenance": "維護", + "Menu:NugetPackages": "Nuget套件" + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..fe97ac3a6c --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json @@ -0,0 +1,31 @@ +{ + "culture": "zh-Hant", + "texts": { + "Volo.AbpIo.Domain:010004": "超過最大成員數!", + "Volo.AbpIo.Domain:010005": "超過最大擁有者數!", + "Volo.AbpIo.Domain:010006": "使用者已經是該組織的擁有者!", + "Volo.AbpIo.Domain:010007": "該使用者已經是該組織的開發者!", + "Volo.AbpIo.Domain:010008": "允許的開發者數量不能低於當前開發者數量!", + "Volo.AbpIo.Domain:010009": "允許的開發者數量不能小於零!", + "Volo.AbpIo.Domain:010010": "超出了最大mac地址數!", + "Volo.AbpIo.Domain:010011": "個人許可不允許超過1個開發者!", + "Volo.AbpIo.Domain:010012": "許可過期後許可不可延長1個月!", + "Volo.AbpIo.Domain:020001": "不能刪除該NPM套件因為\"{NugetPackages}\"Nuget套件依賴此套件.", + "Volo.AbpIo.Domain:020002": "不能刪除該NPM套件因為\"{Modules}\"模組正在使用此套件.", + "Volo.AbpIo.Domain:020003": "不能刪除該NPM套件因為\"{Modules}\"模組正在使用此套件並且\"{NugetPackages}\"Nuget套件依賴此套件.", + "Volo.AbpIo.Domain:020004": "不能刪除該Nuget套件因為\"{Modules}\"模組正在使用此套件.", + "WantToLearn?": "想學習嗎?", + "ReadyToGetStarted?": "準備開始了嗎?", + "JoinOurCommunity": "加入我們的社群", + "GetStartedUpper": "開始", + "ForkMeOnGitHub": "Fork me on GitHub", + "Features": "功能", + "GetStarted": "開始", + "Documents": "文件", + "Community": "社群", + "ContributionGuide": "貢獻指南", + "Blog": "部落格", + "Commercial": "商業版", + "SeeDocuments": "查看文件" + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..7de3798218 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "culture": "zh-Hant", + "texts": { + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 3ca5aa1e97..c83e5aa6a9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -25,6 +25,7 @@ "Volo.AbpIo.Commercial:010004": "Can not find the specified user! The user must have already registered.", "MyOrganizations": "My organizations", "ApiKey": "API key", - "UserNameNotFound": "There is no user with username {0}" + "UserNameNotFound": "There is no user with username {0}", + "SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..e39eaba846 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json @@ -0,0 +1,30 @@ +{ + "culture": "zh-Hant", + "texts": { + "OrganizationManagement": "組織管理", + "OrganizationList": "組織列表", + "Volo.AbpIo.Commercial:010003": "您不是該組織的擁有者!", + "OrganizationNotFoundMessage": "找不到任何組織!", + "DeveloperCount": "開發者數量", + "Owners": "擁有者", + "AddMember": "加入成員", + "AddOwner": "加入擁有者", + "AddDeveloper": "加入開發者", + "UserName": "使用者名稱", + "Name": "名稱", + "EmailAddress": "電子信箱地址", + "Developers": "開發者", + "LicenseType": "許可證類型", + "Manage": "管理", + "StartDate": "開始日期", + "EndDate": "結束日期", + "Modules": "模組", + "LicenseExtendMessage": "您的許可已經延長至{0}", + "LicenseUpgradeMessage": "您的許可已升級為{0}", + "LicenseAddDeveloperMessage": "{0}個開發者已加入到您的許可", + "Volo.AbpIo.Commercial:010004": "不能找到指定的使用者! 使用者必須已經註冊.", + "MyOrganizations": "我的組織", + "ApiKey": "API key", + "UserNameNotFound": "沒有使用者名稱為{0}的使用者" + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..7de3798218 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "culture": "zh-Hant", + "texts": { + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..7de3798218 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "culture": "zh-Hant", + "texts": { + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..6c74dbcadd --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json @@ -0,0 +1,159 @@ +{ + "culture": "zh-Hant", + "texts": { + "GetStarted": "開始", + "Create": "建立", + "NewProject": "新專案", + "DirectDownload": "直接下載", + "ProjectName": "專案名稱", + "ProjectType": "專案類型", + "DatabaseProvider": "資料庫提供者", + "NTier": "N層", + "IncludeUserInterface": "包含使用者介面", + "CreateNow": "現在建立", + "TheStartupProject": "起始專案", + "Tutorial": "教學", + "UsingCLI": "使用CLI", + "SeeDetails": "看詳細", + "AbpShortDescription": "ABP是用於建立現代Web應用程式的完整架構和強大的基礎設施! 遵循最佳實作和約定,為您提供SOLID開發經驗.", + "SourceCodeUpper": "原始碼", + "LatestReleaseLogs": "最新發佈日誌", + "Infrastructure": "基礎設施", + "Architecture": "架構", + "Modular": "模組化", + "DontRepeatYourself": "不要重複工作", + "DeveloperFocused": "專注於開發者", + "FullStackApplicationInfrastructure": "全端應用程式基礎設施", + "DomainDrivenDesign": "領域驅動設計", + "DomainDrivenDesignExplanation": "依據DDD模式和準則進行設計和開發. 為您的應用程式提供分層模型.", + "Authorization": "授權", + "AuthorizationExplanation": "具有使用者,角色和細膩度權限系統的高級授權. 建立於Microsoft Identity套件上.", + "MultiTenancy": "多租戶", + "MultiTenancyExplanationShort": "SaaS應用程式變得簡單! 從資料庫到UI的多租戶整合.", + "CrossCuttingConcerns": "橫切關注點", + "CrossCuttingConcernsExplanationShort": "完整的基礎架構,用於授權,驗證,異常處理,快取,稽核日誌,交易管理等.", + "BuiltInBundlingMinification": "內建Bundling & Minification", + "BuiltInBundlingMinificationExplanation": "無須使用外部工具進行Bundling & Minification. ABP提供了一種更簡單,動態,功能強大,模組化和內建的方式!", + "VirtualFileSystem": "虛擬文件系統", + "VirtualFileSystemExplanation": "將檢視,腳本,樣式,圖片...嵌入到套件/類別庫中,並在不同的應用程式中重複使用.", + "Theming": "主題", + "ThemingExplanationShort": "使用和訂製基於bootstrap的標準UI主題,或建立自己的主題.", + "BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers和動態表單", + "BootstrapTagHelpersDynamicFormsExplanation": "內建的背景作業系統可以整合到Hangfire,RabbitMQ或您喜歡的任何工具中.", //TODO explanation doesn't match. + "HTTPAPIsDynamicProxies": "HTTP APIs和動態代理", + "HTTPAPIsDynamicProxiesExplanation": "自動將應用程式服務公開為REST樣式的HTTP API,並與動態JavaScript和C#代理一起使用.", + "CompleteArchitectureInfo": "現在架構用來建立可維護的軟體解決方案.", + "DomainDrivenDesignBasedLayeringModelExplanation": "幫助您實現基於DDD的分層架構並建構可維護的程式碼.", + "DomainDrivenDesignBasedLayeringModelExplanationCont": "提供啟動模板,抽象,基礎類別,服務,文件和指南以幫助您開發基於DDD模式和準則的應用程式.", + "MicroserviceCompatibleModelExplanation": "核心框架和預先建構模組在設計時就考慮了微服務架構.", + "MicroserviceCompatibleModelExplanationCont": "提供基礎結構,整合,範例和文件,以更輕鬆地實現微服務解決方案,而如果您要使用整體應用程式,也不會帶來額外的複雜性.", + "ModularInfo": "ABP提供了完整的模組化系統,使您能夠開發可重複使用的應用程式模組.", + "PreBuiltModulesThemes": "預先建構模組和主題", + "PreBuiltModulesThemesExplanation": "開源和商業模組和主題已準備好在您的業務應用程式中使用.", + "NuGetNPMPackages": "NuGet和NPM套件", + "NuGetNPMPackagesExplanation": "作為NuGet和NPM套件發佈.易於安裝和升級.", + "ExtensibleReplaceable": "可擴展/可替換", + "ExtensibleReplaceableExplanation": "所有服務和模組在設計時都考慮了可擴展性.您可以替換服務,頁面,樣式,組件...", + "CrossCuttingConcernsExplanation2": "保持原始碼整潔,專注於您自己的業務邏輯.", + "CrossCuttingConcernsExplanation3": "不要浪費時間一次又一次地實作共通用的應用程式需求.", + "AuthenticationAuthorization": "認證與授權", + "ExceptionHandling": "異常處理", + "Validation": "驗證", + "DatabaseConnection": "資料庫連接", + "TransactionManagement": "交易管理", + "AuditLogging": "稽核日誌", + "Caching": "快取", + "Multitenancy": "多租戶", + "DataFiltering": "資料過濾", + "ConventionOverConfiguration": "習慣優於設定", + "ConventionOverConfigurationExplanation": "預設情況下,ABP使用最小或零設定實現共通用的應用程式.", + "ConventionOverConfigurationExplanationList1": "自動註冊已知服務以進行依賴注入.", + "ConventionOverConfigurationExplanationList2": "通過命名習慣將應用程式服務公開為HTTP API.", + "ConventionOverConfigurationExplanationList3": "為C#和JavaScript建立動態HTTP客戶端代理.", + "ConventionOverConfigurationExplanationList4": "為您的實體提供預設Repository.", + "ConventionOverConfigurationExplanationList5": "根據Web請求或應用程式服務方法管理工作單元.", + "ConventionOverConfigurationExplanationList6": "為實體發佈建立,更新和刪除事件.", + "BaseClasses": "基礎類別", + "BaseClassesExplanation": "共通用應用程式模式的預先建構基礎類別.", + "DeveloperFocusedExplanation": "ABP是為了開發者", + "DeveloperFocusedExplanationCont": "它旨在簡化您的日常軟體開發,同時又不限制您在需要時進行底層工作。", + "SeeAllFeatures": "瀏覽所有功能", + "CLI_CommandLineInterface": "CLI (命令列介面)", + "CLI_CommandLineInterfaceExplanation": "CLI會自動建立新專案並將模組添加到您的應用程式.", + "StartupTemplates": "起始模板", + "StartupTemplatesExplanation": "各種起始模板為您提供了完整設定的解結方案,以快速啟動您的開發.", + "BasedOnFamiliarTools": "基於熟悉的工具", + "BasedOnFamiliarToolsExplanation": "建立在您已經知道的主流工具上並與其整合.學習曲線低,適應性強,舒適的開發.", + "ORMIndependent": "ORM獨立", + "ORMIndependentExplanation": "核心框架獨立於ORM/資料庫,並且可以與任何資料庫一起使用.Entity Framework Core和MongoDB提供者已經可用.", + "Features": "功能", + "ABPCLI": "ABP CLI", + "Modularity": "模組化", + "BootstrapTagHelpers": "Bootstrap Tag Helpers", + "DynamicForms": "動態表單", + "BundlingMinification": "Bundling & Minification", + "BackgroundJobs": "背景作業", + "DDDInfrastructure": "DDD基礎設施", + "DomainDrivenDesignInfrastructure": "Domain Driven Design基礎設施", + "AutoRESTAPIs": "自動REST APIs", + "DynamicClientProxies": "動態客戶端代理", + "DistributedEventBus": "分散式事件匯流排", + "DistributedEventBusWithRabbitMQIntegration": "具有RabbitMQ整合的分散式事件匯流排", + "TestInfrastructure": "測試基礎設施", + "AuditLoggingEntityHistories": "稽核日誌和實體歷史", + "ObjectToObjectMapping": "物件對應", + "EmailSMSAbstractions": "電子郵件和簡訊抽象", + "EmailSMSAbstractionsWithTemplatingSupport": "具有模板支援的電子郵件和簡訊抽象", + "Localization": "本地化", + "SettingManagement": "設定管理", + "ExtensionMethods": "擴充方法", + "ExtensionMethodsHelpers": "擴充方法和助手", + "AspectOrientedProgramming": "切面導向設計", + "DependencyInjection": "依賴注入", + "DependencyInjectionByConventions": "依照習慣的依賴注入", + "ABPCLIExplanation": "ABP CLI(命令列介面)是用於對ABP解決方案執行常見操作的命令列工具.", + "ModularityExplanation": "ABP提供了一個完整的基礎設施來建構您自己的應用程式模組,這些模組可能具有實體,服務,資料庫整合,API,UI組件等.", //TODO: strong "your own application modules",- + "MultiTenancyExplanation": "ABP框建不僅支援開發多租戶應用程式,而且使您的程式碼幾乎無須知道多租戶.", + "MultiTenancyExplanation2": "可以自動確定當前租戶,將不同租戶的資料互相隔離.", + "MultiTenancyExplanation3": "支援單一資料庫,或每個租戶單獨資料庫或者混合方式.", + "MultiTenancyExplanation4": "您專注於業務邏輯,並讓該框架為您處理多租戶.", + "BootstrapTagHelpersExplanation": "與其手動撰寫重複細節的bootstrap組件,不如使用ABP的tag helper來簡化它並利用自動完成.您當然也可以在需要時直接使用Bootstrap.", + "DynamicFormsExplanation": "動態表單和tag helpers可以利用C#類別做為模型來建立完整的表單.", + "AuthenticationAuthorizationExplanation": "整合到ASP.NET Core Identity和IdentityServer4的豐富身份驗證和授權選項.提供可擴展且詳細的權限系統.", + "CrossCuttingConcernsExplanation": "部要重複資幾一次又一次地實作所有這寫常見的東西.專注於您的業務邏輯,並讓ABP按照習慣自動執行.", + "DatabaseConnectionTransactionManagement": "資料庫連接和交易管理", + "CorrelationIdTracking": "關聯ID追蹤", + "BundlingMinificationExplanation": "ABP提供了一個簡單,動態,功能強大,模組化的內建Bundling & Minification系統.", + "VirtualFileSystemnExplanation": "虛擬文件系統使管理文件系統(硬碟)上不存在的文件成為可能.它主要用於將(js,css,image,cshtml...)文件嵌入到組件(Assembly)中,並在運行時像實體文件一樣使用他們.", + "ThemingExplanation": "主題系統允許通過基於最新的Bootstrap框架定義一組通用基礎類別庫和佈局來獨立開發應用程式和模組主題.", + "DomainDrivenDesignInfrastructureExplanation": "基於領域驅動設計模式和準則建構分層應用程式的完整基礎設施;", + "Specification": "規範", + "Repository": "倉儲", + "DomainService": "領域服務", + "ValueObject": "值對象", + "ApplicationService": "應用服務", + "DataTransferObject": "資料傳輸對象", + "AggregateRootEntity": "聚合根, 實體", + "AutoRESTAPIsExplanation": "ABP可以依照習慣自動將您的應用服務設定為API控制器.", + "DynamicClientProxiesExplanation": "從JavaScript和C#客戶端輕鬆使用您的API.", + "DistributedEventBusWithRabbitMQIntegrationExplanation": "使用帶有RabbitMQ整合的內建分散式事件匯流排,可以輕鬆發佈和使用分散式事件.", + "TestInfrastructureExplanation": "框架已經考慮了單元和整合測試.為您提供基礎類別,使其更容易.起始模板已預先設定用於測試.", + "AuditLoggingEntityHistoriesExplanation": "針對關鍵業務應用的內建稽核日誌紀錄.請求,服務,方法級別的稽核日誌紀錄以及具有屬性級別詳細資訊的實體歷史紀錄.", + "EmailSMSAbstractionsWithTemplatingSupportExplanation": "IEmailSender和ISmsSender抽象使您的應用程式邏輯與基礎設施解耦.先進的電子郵件模板系統允許建立和在地化電子郵件模板,並在需要實輕鬆使用.", + "LocalizationExplanation": "在地化系統允許在純JSON文件中建立資源,並使用它們來在地化UI.它支援繼承,擴展和JavaScript整合等高級方案,同時與AspNet Core的在地化系統完全兼容.", + "SettingManagementExplanation": "定義應用程式的設定,並根據當前設定,租戶和使用者在運行時獲取值.", + "ExtensionMethodsHelpersExplanation": "即使式瑣碎的程式碼部分,也不要重複.標準類型的擴展方法和助手使您的程式碼更加清晰和易於撰寫.", + "AspectOrientedProgrammingExplanation": "提供合適的基礎設施來建立動態代理並實現切面導向設計.攔截任何類別,並在每次方法執行之前和之後執行程式碼.", + "DependencyInjectionByConventionsExplanation": "無須手動註冊類別以進行依賴注入.按照習慣自動註冊常用服務類型.對於其他類型的服務,您可以使用介面和屬性來使其變得更輕鬆.", + "DataFilteringExplanation": "定義和使用資料過濾器,這些過濾器在您從資料庫中查詢實體時會自動應用.當您實現簡單的介面時,可立即使用軟刪除功能和多租戶過濾器.", + "PublishEvents": "發佈事件", + "HandleEvents": "處理事件", + "AndMore": "更多...", + "Code": "編碼", + "Result": "結果", + "SeeTheDocumentForMoreInformation": "查看{0} 文件獲得更多訊息", + "IndexPageHeroSection": "asp.net core的開源Web應用程式
框架
", + "UiFramework": "UI框架", + "EmailAddress": "電子信箱地址" + } +} \ No newline at end of file diff --git a/build-all-release.ps1 b/build-all-release.ps1 deleted file mode 100644 index e6555f8d6b..0000000000 --- a/build-all-release.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -# COMMON PATHS - -$rootFolder = (Get-Item -Path "./" -Verbose).FullName - -# List of solutions - -$solutionPaths = ( - "framework", - "modules/users", - "modules/permission-management", - "modules/setting-management", - "modules/feature-management", - "modules/identity", - "modules/identityserver", - "modules/tenant-management", - "modules/account", - "modules/docs", - "modules/blogging", - "modules/audit-logging", - "modules/background-jobs", - "modules/client-simulation", - "templates/module/aspnet-core", - "templates/app/aspnet-core", - "abp_io/AbpIoLocalization" -) - -# Build all solutions - -foreach ($solutionPath in $solutionPaths) { - $solutionAbsPath = (Join-Path $rootFolder $solutionPath) - Set-Location $solutionAbsPath - dotnet build --configuration Release - if (-Not $?) { - Write-Host ("Build failed for the solution: " + $solutionPath) - Set-Location $rootFolder - exit $LASTEXITCODE - } -} - -Set-Location $rootFolder diff --git a/build-all.ps1 b/build-all.ps1 deleted file mode 100644 index 649abc5f8c..0000000000 --- a/build-all.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -# COMMON PATHS - -$rootFolder = (Get-Item -Path "./" -Verbose).FullName - -# List of solutions - -$solutionPaths = ( - "framework", - "modules/users", - "modules/permission-management", - "modules/setting-management", - "modules/feature-management", - "modules/identity", - "modules/identityserver", - "modules/tenant-management", - "modules/account", - "modules/docs", - "modules/blogging", - "modules/audit-logging", - "modules/background-jobs", - "modules/client-simulation", - "templates/module/aspnet-core", - "templates/app/aspnet-core", - "abp_io/AbpIoLocalization" -) - -# Build all solutions - -foreach ($solutionPath in $solutionPaths) { - $solutionAbsPath = (Join-Path $rootFolder $solutionPath) - Set-Location $solutionAbsPath - dotnet build - if (-Not $?) { - Write-Host ("Build failed for the solution: " + $solutionPath) - Set-Location $rootFolder - exit $LASTEXITCODE - } -} - -Set-Location $rootFolder diff --git a/build/build-all-release.ps1 b/build/build-all-release.ps1 new file mode 100644 index 0000000000..1c86351379 --- /dev/null +++ b/build/build-all-release.ps1 @@ -0,0 +1,16 @@ +. ".\common.ps1" + +# Build all solutions + +foreach ($solutionPath in $solutionPaths) { + $solutionAbsPath = (Join-Path $rootFolder $solutionPath) + Set-Location $solutionAbsPath + dotnet build --configuration Release + if (-Not $?) { + Write-Host ("Build failed for the solution: " + $solutionPath) + Set-Location $rootFolder + exit $LASTEXITCODE + } +} + +Set-Location $rootFolder diff --git a/build/build-all.ps1 b/build/build-all.ps1 new file mode 100644 index 0000000000..ffaffa67a3 --- /dev/null +++ b/build/build-all.ps1 @@ -0,0 +1,16 @@ +. ".\common.ps1" + +# Build all solutions + +foreach ($solutionPath in $solutionPaths) { + $solutionAbsPath = (Join-Path $rootFolder $solutionPath) + Set-Location $solutionAbsPath + dotnet build + if (-Not $?) { + Write-Host ("Build failed for the solution: " + $solutionPath) + Set-Location $rootFolder + exit $LASTEXITCODE + } +} + +Set-Location $rootFolder diff --git a/build/common.ps1 b/build/common.ps1 new file mode 100644 index 0000000000..e4ba6a8adc --- /dev/null +++ b/build/common.ps1 @@ -0,0 +1,34 @@ +# COMMON PATHS + +$rootFolder = (Get-Item -Path "./" -Verbose).FullName + +# List of solutions + +$solutionPaths = ( + "../framework", + "../modules/users", + "../modules/permission-management", + "../modules/setting-management", + "../modules/feature-management", + "../modules/identity", + "../modules/identityserver", + "../modules/tenant-management", + "../modules/account", + "../modules/docs", + "../modules/blogging", + "../modules/audit-logging", + "../modules/background-jobs", + "../modules/client-simulation", + "../templates/module/aspnet-core", + "../templates/app/aspnet-core", + "../samples/BasicAspNetCoreApplication", + "../samples/BasicConsoleApplication", + "../samples/BookStore", + "../samples/BookStore-Angular-MongoDb/aspnet-core", + "../samples/BookStore-Modular/modules/book-management", + "../samples/BookStore-Modular/application", + "../samples/DashboardDemo", + "../samples/MicroserviceDemo", + "../samples/RabbitMqEventBus", + "../abp_io/AbpIoLocalization" +) \ No newline at end of file diff --git a/build/test-all.ps1 b/build/test-all.ps1 new file mode 100644 index 0000000000..1465bff6c3 --- /dev/null +++ b/build/test-all.ps1 @@ -0,0 +1,16 @@ +. ".\common.ps1" + +# Test all solutions + +foreach ($solutionPath in $solutionPaths) { + $solutionAbsPath = (Join-Path $rootFolder $solutionPath) + Set-Location $solutionAbsPath + dotnet test --no-build --no-restore + if (-Not $?) { + Write-Host ("Test failed for the solution: " + $solutionPath) + Set-Location $rootFolder + exit $LASTEXITCODE + } +} + +Set-Location $rootFolder diff --git a/common.props b/common.props index 228cdcfbe2..1cccebd015 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 1.1.1 + 2.1.0 $(NoWarn);CS1591 https://abp.io/assets/abp_nupkg.png https://abp.io diff --git a/docs/cs/Best-Practices/PostgreSQL-Integration.md b/docs/cs/Best-Practices/PostgreSQL-Integration.md deleted file mode 100644 index 6bf8224f1e..0000000000 --- a/docs/cs/Best-Practices/PostgreSQL-Integration.md +++ /dev/null @@ -1,35 +0,0 @@ -## Entity Framework Core PostgreSQL integrace - -> Podívejte se na [Entity Framework Core integrační dokument](../Entity-Framework-Core.md) pro základy integrace EF Core. - -### Aktualizace projektu EntityFrameworkCore - -- V projektu `Acme.BookStore.EntityFrameworkCore` nahraďte balík `Volo.Abp.EntityFrameworkCore.SqlServer` za `Volo.Abp.EntityFrameworkCore.PostgreSql` -- Aktualizace pro použití PostgreSQL v `BookStoreEntityFrameworkCoreModule` - - Nahraďte `AbpEntityFrameworkCoreSqlServerModule` za `AbpEntityFrameworkCorePostgreSqlModule` - - Nahraďte `options.UseSqlServer()` za `options.UsePostgreSql()` -- V jiných projektech aktualizujte PostgreSQL connection string v nezbytných `appsettings.json` souborech - -#### Odstranění stávajících migrací - -Smažte všechny stavající migrační soubory (včetně `DbContextModelSnapshot`) - -![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png) - -#### Znovu vygenerujte počáteční migraci & aktualizujte databázi - -Nastavte správný spouštěcí projekt (obvykle web projekt), -Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), zvolte `Acme.BookStore.EntityFrameworkCore.DbMigrations` jako **Default project** a proveďte následující příkaz: - -Proveďte příkaz `Add-Migration`: -```` -PM> Add-Migration Initial -```` - -Poté proveďte příkaz `Update-Database` k aktualizaci schématu databáze: - -```` -PM> Update-Database -```` - -![postgresql-update-database](images/postgresql-update-database.png) diff --git a/docs/cs/CLI.md b/docs/cs/CLI.md index cbf8006ad2..7d2ab4c479 100644 --- a/docs/cs/CLI.md +++ b/docs/cs/CLI.md @@ -46,11 +46,13 @@ abp new Acme.BookStore * `--tiered`: Vytvoří stupňovité řešení, kde jsou vrstvy Web a Http API fyzicky odděleny. Pokud není uvedeno, tak vytvoří vrstvené řešení, které je méně složité a vhodné pro většinu scénářů. * `angular`: Angular. Pro tuto šablonu jsou dostupné dodatečné možnosti: * `--separate-identity-server`: Oddělí identity server aplikaci od API host aplikace. Pokud není uvedeno, bude na straně serveru jediný koncový bod. + * `none`: Bez UI. Pro tuto šablonu jsou dostupné dodatečné možnosti: + * `--separate-identity-server`: Oddělí identity server aplikaci od API host aplikace. Pokud není uvedeno, bude na straně serveru jediný koncový bod. * `--database-provider` nebo `-d`: Určuje poskytovatele databáze. Výchozí poskytovatel je `ef`. Dostupní poskytovatelé: * `ef`: Entity Framework Core. * `mongodb`: MongoDB. * `module`: [Šablona modulu](Startup-Templates/Module.md). Dodatečné možnosti: - * `--no-ui`: Určuje nezahrnutí uživatelského rozhraní. Umožňuje vytvořit moduly pouze pro služby (a.k.a. mikroslužby - bez uživatelského rozhraní). + * `--no-ui`: Určuje nezahrnutí uživatelského rozhraní. Umožňuje vytvořit moduly pouze pro služby (a.k.a. mikroslužby - bez uživatelského rozhraní). * `--output-folder` nebo `-o`: Určuje výstupní složku. Výchozí hodnota je aktuální adresář. * `--version` nebo `-v`: Určuje verzi ABP & šablony. Může to být [štítek vydání](https://github.com/abpframework/abp/releases) nebo [název větve](https://github.com/abpframework/abp/branches). Pokud není uvedeno, používá nejnovější vydání. Většinou budete chtít použít nejnovější verzi. @@ -127,6 +129,24 @@ abp update [možnosti] * `--npm`: Aktualizuje pouze balíčky NPM. * `--nuget`: Aktualizuje pouze balíčky NuGet. +### login + +Některé funkce CLI vyžadují přihlášení k platformě abp.io. Chcete-li se přihlásit pomocí svého uživatelského jména, napište + +```bash +abp login +``` + +Všimněte si, že nové přihlášení s již aktivní relací ukončí předchozí relaci a vytvoří novou. + +### logout + +Odhlásí vás odebráním tokenu relace z počítače. + +``` +abp logout +``` + ### help Vypíše základní informace k používání CLI. diff --git a/docs/cs/Entity-Framework-Core-PostgreSQL.md b/docs/cs/Entity-Framework-Core-PostgreSQL.md new file mode 100644 index 0000000000..3a39c7485d --- /dev/null +++ b/docs/cs/Entity-Framework-Core-PostgreSQL.md @@ -0,0 +1,39 @@ +# Přepnutí na EF Core PostgreSQL providera + +Tento dokument vysvětluje, jak přepnout na poskytovatele databáze **PostgreSQL** pro **[spouštěcí šablonu aplikace](Startup-Templates/Application.md)**, která je dodávána s předem nakonfigurovaným SQL poskytovatelem. + +## Výměna balíku Volo.Abp.EntityFrameworkCore.SqlServer + +Projekt `.EntityFrameworkCore` v řešení závisí na NuGet balíku [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer). Odstraňte tento balík a přidejte stejnou verzi balíku [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql). + +## Nahrazení závislosti modulu + +Najděte třídu ***YourProjectName*EntityFrameworkCoreModule** v projektu `.EntityFrameworkCore`, odstraňte `typeof(AbpEntityFrameworkCoreSqlServerModule)` z atributu `DependsOn`, přidejte `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (také nahraďte `using Volo.Abp.EntityFrameworkCore.SqlServer;` za `using Volo.Abp.EntityFrameworkCore.PostgreSql;`). + +## UsePostgreSql() + +Najděte volání `UseSqlServer()` v *YourProjectName*EntityFrameworkCoreModule.cs uvnitř projektu `.EntityFrameworkCore` a nahraďte za `UsePostgreSql()`. + +Najděte volání `UseSqlServer()` v *YourProjectName*MigrationsDbContextFactory.cs uvnitř projektu `.EntityFrameworkCore.DbMigrations` a nahraďte za `UseNpgsql()`. + +> V závislosti na struktuře řešení můžete najít více volání `UseSqlServer()`, které je třeba změnit. + +## Změna connection stringů + +PostgreSql connection stringy se od těch pro SQL Server liší. Je proto potřeba zkontrolovat všechny soubory `appsettings.json` v řešení a connection stringy v nich nahradit. Podívejte se na [connectionstrings.com](https://www.connectionstrings.com/postgresql/) pro více detailů o možnostech PostgreSql connection stringů. + +Typicky je potřeba změnit `appsettings.json` v projektech `.DbMigrator` a `.Web` projects, ale to záleží na vaší struktuře řešení. + +## Regenerace migrací + +Startovací šablona používá [Entity Framework Core Code First migrace](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core migrace závisí na zvoleném DBMS poskytovateli. Tudíž změna DBMS poskytovatele způsobí selhání migrace. +* Smažte složku Migrations v projektu `.EntityFrameworkCore.DbMigrations` and znovu sestavte řešení. +* Spusťte `Add-Migration "Initial"` v Package Manager Console (je nutné zvolit `.DbMigrator` (nebo `.Web`) projekt jako startovací projekt v Solution Explorer a zvolit projekt `.EntityFrameworkCore.DbMigrations` jako výchozí v Package Manager Console). + +Tímto vytvoříte migraci databáze se všemi nakonfigurovanými databázovými objekty (tabulkami). + +Spusťte projekt `.DbMigrator` k vytvoření databáze a vložení počátečních dat. + +## Spuštění aplikace + +Vše je připraveno. Stačí už jen spustit aplikaci a užívat si kódování. diff --git a/docs/cs/Getting-Started-Angular-Template.md b/docs/cs/Getting-Started-Angular-Template.md index 5dfc65c7ec..ea5ef0a4bf 100644 --- a/docs/cs/Getting-Started-Angular-Template.md +++ b/docs/cs/Getting-Started-Angular-Template.md @@ -75,7 +75,7 @@ Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup by měl být pod #### Použití příkazu EF Core Update-Database -Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.Web` a zvolte **Set as StartUp Project**: +Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.HttpApi.Host` a zvolte **Set as StartUp Project**: ![set-as-startup-project](images/set-as-startup-project.png) diff --git a/docs/cs/Getting-Started-AspNetCore-Application.md b/docs/cs/Getting-Started-AspNetCore-Application.md index ffb2f556c6..0537b01579 100644 --- a/docs/cs/Getting-Started-AspNetCore-Application.md +++ b/docs/cs/Getting-Started-AspNetCore-Application.md @@ -4,15 +4,17 @@ Tento tutoriál vysvětluje jak začít s ABP z ničeho s minimem závislostí. ## Tvorba nového projektu -1. Vytvořte novou prázdnou AspNet Core Web aplikaci ve Visual Studio: +1. Vytvořte novou AspNet Core Web aplikaci ve Visual Studio 2019 (16.3.0+): -![](images/create-new-aspnet-core-application.png) +![](images/create-new-aspnet-core-application-v2.png) -2. Zvolte prázdnou šablonu +2. Nakonfigurujte váš nový projekt: -![](images/select-empty-web-application.png) +![](images/select-empty-web-application-v2.png) -Můžete zvolit i jinou šablonu, ale pro demonstraci je lepší čístý projekt. +3. Potvrďte kliknutím na tlačítko vytvořit + +![create-aspnet-core-application](images/create-aspnet-core-application.png) ## Instalace Volo.Abp.AspNetCore.Mvc balíku @@ -28,10 +30,8 @@ ABP je modulární framework a proto vyžaduje **spouštěcí (kořenový) modul ````C# using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Volo.Abp; -using Volo.Abp.AspNetCore.Modularity; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Modularity; @@ -40,7 +40,8 @@ namespace BasicAspNetCoreApplication [DependsOn(typeof(AbpAspNetCoreMvcModule))] public class AppModule : AbpModule { - public override void OnApplicationInitialization(ApplicationInitializationContext context) + public override void OnApplicationInitialization( + ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); @@ -49,8 +50,14 @@ namespace BasicAspNetCoreApplication { app.UseDeveloperExceptionPage(); } + else + { + app.UseExceptionHandler("/Error"); + } - app.UseMvcWithDefaultRoute(); + app.UseStaticFiles(); + app.UseRouting(); + app.UseMvcWithDefaultRouteAndArea(); } } } @@ -58,7 +65,7 @@ namespace BasicAspNetCoreApplication ``AppModule`` je dobrý název pro spouštěcí modul aplikace. -ABP balíky definují modulové třídy a modul může mít závislost na jiný modul. V kódu výše, náš ``AppModule`` má závislost na ``AbpAspNetCoreMvcModule`` (definován v balíku Volo.Abp.AspNetCore.Mvc). Je běžné přidat ``DependsOn`` atribute po instalaci nového ABP NuGet balíku. +ABP balíky definují modulové třídy a modul může mít závislost na jiném. V kódu výše, ``AppModule`` má závislost na ``AbpAspNetCoreMvcModule`` (definován v balíku [Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)). Je běžné přidat ``DependsOn`` atribute po instalaci nového ABP NuGet balíku. Místo třídy Startup, konfigurujeme ASP.NET Core pipeline v této modulové třídě. @@ -67,7 +74,6 @@ Místo třídy Startup, konfigurujeme ASP.NET Core pipeline v této modulové t V dalším kroku upravíme Startup třídu k integraci ABP modulového systému: ````C# -using System; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; @@ -75,11 +81,9 @@ namespace BasicAspNetCoreApplication { public class Startup { - public IServiceProvider ConfigureServices(IServiceCollection services) + public void ConfigureServices(IServiceCollection services) { services.AddApplication(); - - return services.BuildServiceProviderFromFactory(); } public void Configure(IApplicationBuilder app) @@ -88,41 +92,19 @@ namespace BasicAspNetCoreApplication } } } - ```` -Změnili jsme metodu ``ConfigureServices`` aby vracela ``IServiceProvider`` místo ``void``. Tato změna nám dovoluje nahradit AspNet Core vkládání závislostí za jiný framework (více v sekci Autofac integrace níže). ``services.AddApplication()`` přidává všechny služby definované ve všech modulech počínaje ``AppModule``. +``services.AddApplication()`` přidává všechny služby definované ve všech modulech počínaje od ``AppModule``. -Volání ``app.InitializeApplication()`` v metodě ``Configure`` inicializuje a spustí aplikaci. +``app.InitializeApplication()`` v metodě ``Configure`` inicializuje a spustí aplikaci. -## Ahoj světe! +## Spusťte aplikaci! -Aplikace výše zatím nic nedělá. Pojďme proto vytvořit MVC controller, který už něco dělá: - -````C# -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; - -namespace BasicAspNetCoreApplication.Controllers -{ - public class HomeController : AbpController - { - public IActionResult Index() - { - return Content("Hello World!"); - } - } -} - -```` - -Jakmile spustíte aplikaci, uvidíte na stránce zprávu "Hello World!". - -Odvození ``HomeController`` od ``AbpController`` místo standardní třídy ``Controller``. Toto není vyžadováno, ale třída ``AbpController`` má užitečné základní vlastnosti a metody, které usnadňují vývoj. +To je vše! Spusťte aplikaci, bude fungovat podle očekávání. ## Použití Autofac jako frameworku pro vkládání závislostí -Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) skvělý pro základní požadavky, Autofac poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku. +Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) dostatečný pro základní požadavky, [Autofac](https://autofac.org/) poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku. Nahrazení AspNet Core DI systému za Autofac a integrace s ABP je snadná. @@ -143,40 +125,29 @@ public class AppModule : AbpModule } ```` -3. Změníme řádek ``services.AddApplication();`` v třídě ``Startup`` následovně: - -````C# -services.AddApplication(options => -{ - options.UseAutofac(); // Integrace s Autofac -}); -```` - -4. Upravíme `Program.cs` aby nepoužíval metodu `WebHost.CreateDefaultBuilder()` jelikož ta používá výchozí DI kontejner: +3. Upravíme `Program.cs` aby používal Autofac: ````csharp -public class Program +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace BasicAspNetCoreApplication { - public static void Main(string[] args) + public class Program { - /* - https://github.com/aspnet/AspNetCore/issues/4206#issuecomment-445612167 - CurrentDirectoryHelpers exists in: \framework\src\Volo.Abp.AspNetCore.Mvc\Microsoft\AspNetCore\InProcess\CurrentDirectoryHelpers.cs - Will remove CurrentDirectoryHelpers.cs when upgrade to ASP.NET Core 3.0. - */ - CurrentDirectoryHelpers.SetCurrentDirectory(); - - BuildWebHostInternal(args).Run(); - } + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } - public static IWebHost BuildWebHostInternal(string[] args) => - new WebHostBuilder() - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIIS() - .UseIISIntegration() - .UseStartup() - .Build(); + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .UseAutofac(); // Přidejte tento řádek + } } ```` diff --git a/docs/cs/Index.md b/docs/cs/Index.md index ac13bcbdb6..0424c7120b 100644 --- a/docs/cs/Index.md +++ b/docs/cs/Index.md @@ -4,18 +4,12 @@ ABP je **open source aplikační framework** se zaměřením na vývoj webových K procházení dokumentace využijte navigační nabídky vlevo. -## Stav projektu - -ABP je **novou generací** open source frameworku [ASP.NET Boilerplate](https://aspnetboilerplate.com/). V současné době je v náhledové fázi a není připraven k ostrému nasazení. Na dokumentaci se stále pracuje a ještě zdaleka není dokončena. - -Pro aplikace na krátkodobé a ostré nasazení je doporučeno použít [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework, který je bohatý na funkce, vyspělý, aktivně udržovaný a aktuální. - ## Začínáme Nejsnazší cestou jak začít nový projekt s ABP je užití startovací šablony: -* [ASP.NET Core MVC (Razor Pages) UI Šablona](Getting-Started-AspNetCore-MVC-Template.md) -* [Angular UI Šablona](Getting-Started-Angular-Template.md) +* [ASP.NET Core MVC (Razor Pages) UI Počáteční Šablona](Getting-Started-AspNetCore-MVC-Template.md) +* [Angular UI Počáteční Šablona](Getting-Started-Angular-Template.md) Pokud chcete začít od nuly (s prázdným projektem) tak manuálně nainstalujte ABP Framework s pomocí následujících tutoriálů: diff --git a/docs/cs/docs-nav.json b/docs/cs/docs-nav.json index 91badc73e9..6c05d77dcf 100644 --- a/docs/cs/docs-nav.json +++ b/docs/cs/docs-nav.json @@ -56,6 +56,14 @@ { "text": "Základy", "items": [ + { + "text": "Konfigurace", + "path": "Configuration.md" + }, + { + "text": "Možnosti", + "path": "Options.md" + }, { "text": "Vkládání závislostí", "path": "Dependency-Injection.md", @@ -79,19 +87,29 @@ "path": "Exception-Handling.md" }, { - "text": "Validace" + "text": "Validace", + "path": "Validation.md", + "items": [ + { + "text": "FluentValidation integrace", + "path": "FluentValidation.md" + } + ] }, { - "text": "Autorizace" + "text": "Autorizace", + "path": "Authorization.md" }, { - "text": "Ukládání do mezipaměti" + "text": "Ukládání do mezipaměti", + "path": "Caching.md" }, { "text": "Audit" }, { - "text": "Správa nastavení" + "text": "Nastavení", + "path": "Settings.md" } ] }, @@ -114,6 +132,14 @@ { "text": "Služby", "items": [ + { + "text": "Současný uživatel", + "path": "CurrentUser.md" + }, + { + "text": "Mapování objekt na objekt", + "path": "Object-To-Object-Mapping.md" + }, { "text": "Serializace objektu" }, @@ -242,24 +268,46 @@ }, { "text": "Přístup k datům", + "path": "Data-Access.md", "items": [ { - "text": "Entity Framework Core integrace", - "path": "Entity-Framework-Core.md", + "text": "Connection stringy", + "path": "Connection-Strings.md" + }, + { + "text": "Poskytovatelé databází", "items": [ { - "text": "PostgreSQL integrace", - "path": "Best-Practices/PostgreSQL-Integration.md" + "text": "Entity Framework Core", + "path": "Entity-Framework-Core.md", + "items": [ + { + "text": "Přepnutí na MySQL", + "path": "Entity-Framework-Core-MySQL.md" + }, + { + "text": "Přepnutí na PostgreSQL", + "path": "Entity-Framework-Core-PostgreSQL.md" + }, + { + "text": "Přepnutí na SQLite", + "path": "Entity-Framework-Core-SQLite.md" + }, + { + "text": "Přepnutí na jiný DBMS", + "path": "Entity-Framework-Core-Other-DBMS.md" + } + ] + }, + { + "text": "MongoDB", + "path": "MongoDB.md" + }, + { + "text": "Dapper", + "path": "Dapper.md" } ] - }, - { - "text": "MongoDB integrace", - "path": "MongoDB.md" - }, - { - "text": "Dapper integrace", - "path": "Dapper.md" } ] }, diff --git a/docs/cs/images/authorization-new-permission-ui-hierarcy.png b/docs/cs/images/authorization-new-permission-ui-hierarcy.png new file mode 100644 index 0000000000..078d67d50f Binary files /dev/null and b/docs/cs/images/authorization-new-permission-ui-hierarcy.png differ diff --git a/docs/cs/images/authorization-new-permission-ui-localized.png b/docs/cs/images/authorization-new-permission-ui-localized.png new file mode 100644 index 0000000000..610ce39faf Binary files /dev/null and b/docs/cs/images/authorization-new-permission-ui-localized.png differ diff --git a/docs/cs/images/authorization-new-permission-ui.png b/docs/cs/images/authorization-new-permission-ui.png new file mode 100644 index 0000000000..554f27e78d Binary files /dev/null and b/docs/cs/images/authorization-new-permission-ui.png differ diff --git a/docs/cs/images/create-aspnet-core-application.png b/docs/cs/images/create-aspnet-core-application.png new file mode 100644 index 0000000000..5813cf38e9 Binary files /dev/null and b/docs/cs/images/create-aspnet-core-application.png differ diff --git a/docs/cs/images/create-new-aspnet-core-application-v2.png b/docs/cs/images/create-new-aspnet-core-application-v2.png new file mode 100644 index 0000000000..f8274ae2a4 Binary files /dev/null and b/docs/cs/images/create-new-aspnet-core-application-v2.png differ diff --git a/docs/cs/images/docs-section-ui.png b/docs/cs/images/docs-section-ui.png new file mode 100644 index 0000000000..7856454e5d Binary files /dev/null and b/docs/cs/images/docs-section-ui.png differ diff --git a/docs/cs/images/select-empty-web-application-v2.png b/docs/cs/images/select-empty-web-application-v2.png new file mode 100644 index 0000000000..da32f71857 Binary files /dev/null and b/docs/cs/images/select-empty-web-application-v2.png differ diff --git a/docs/en/Ambient-Context-Pattern.md b/docs/en/Ambient-Context-Pattern.md new file mode 100644 index 0000000000..d00a721ce2 --- /dev/null +++ b/docs/en/Ambient-Context-Pattern.md @@ -0,0 +1,3 @@ +## Ambient Context Pattern + +TODO \ No newline at end of file diff --git a/docs/en/Audit-Logging.md b/docs/en/Audit-Logging.md index f11a3f19e3..610efc0451 100644 --- a/docs/en/Audit-Logging.md +++ b/docs/en/Audit-Logging.md @@ -1,3 +1,372 @@ # Audit Logging -TODO \ No newline at end of file +[Wikipedia](https://en.wikipedia.org/wiki/Audit_trail): "*An audit trail (also called **audit log**) is a security-relevant chronological record, set of records, and/or destination and source of records that provide documentary evidence of the sequence of activities that have affected at any time a specific operation, procedure, or event*". + +ABP Framework provides an **extensible audit logging system** that automates the audit logging by **convention** and provides **configuration** points to control the level of the audit logs. + +An **audit log object** (see the Audit Log Object section below) is typically created & saved per web request. It includes; + +* **Request & response details** (like URL, Http method, Browser info, HTTP status code... etc.). +* **Performed actions** (controller actions and application service method calls with their parameters). +* **Entity changes** occurred in the web request. +* **Exception** information (if there was an error while executing the request). +* **Request duration** (to measure the performance of the application). + +> [Startup templates](Startup-Templates/Index.md) are configured for the audit logging system which is suitable for most of the applications. Use this document for a detailed control over the audit log system. + +### Database Provider Support + +* Fully supported by the [Entity Framework Core](Entity-Framework-Core.md) provider. +* Entity change logging is not supported by the [MongoDB](MongoDB.md) provider. Other features work as expected. + +## UseAuditing() + +`UseAuditing()` middleware should be added to the ASP.NET Core request pipeline in order to create and save the audit logs. If you've created your applications using [the startup templates](Startup-Templates/Index.md), it is already added. + +## AbpAuditingOptions + +`AbpAuditingOptions` is the main [options object](Options.md) to configure the audit log system. You can configure it in the `ConfigureServices` method of your [module](Module-Development-Basics.md): + +````csharp +Configure(options => +{ + options.IsEnabled = false; //Disables the auditing system +}); +```` + +Here, a list of the options you can configure: + +* `IsEnabled` (default: `true`): A root switch to enable or disable the auditing system. Other options is not used if this value is `false`. +* `HideErrors` (default: `true`): Audit log system hides and write regular [logs](Logging.md) if any error occurs while saving the audit log objects. If saving the audit logs is critical for your system, set this to `false` to throw exception in case of hiding the errors. +* `IsEnabledForAnonymousUsers` (default: `true`): If you want to write audit logs only for the authenticated users, set this to `false`. If you save audit logs for anonymous users, you will see `null` for `UserId` values for these users. +* `IsEnabledForGetRequests` (default: `false`): HTTP GET requests should not make any change in the database normally and audit log system doesn't save audit log objects for GET request. Set this to `true` to enable it also for the GET requests. +* `ApplicationName`: If multiple applications saving audit logs into a single database, set this property to your application name, so you can distinguish the logs of different applications. +* `IgnoredTypes`: A list of `Type`s to be ignored for audit logging. If this is an entity type, changes for this type of entities will not be saved. This list is also used while serializing the action parameters. +* `EntityHistorySelectors`: A list of selectors those are used to determine if an entity type is selected for saving the entity change. See the section below for details. +* `Contributors`: A list of `AuditLogContributor` implementations. A contributor is a way of extending the audit log system. See the "Audit Log Contributors" section below. + +### Entity History Selectors + +Saving all changes of all your entities would require a lot of database space. For this reason, **audit log system doesn't save any change for the entities unless you explicitly configure it**. + +To save all changes of all entities, simply use the `AddAllEntities()` extension method. + +````csharp +Configure(options => +{ + options.EntityHistorySelectors.AddAllEntities(); +}); +```` + +`options.EntityHistorySelectors` actually a list of type predicate. You can write a lambda expression to define your filter. + +The example selector below does the same of the `AddAllEntities()` extension method defined above: + +````csharp +Configure(options => +{ + options.EntityHistorySelectors.Add( + new NamedTypeSelector( + "MySelectorName", + type => + { + if (typeof(IEntity).IsAssignableFrom(type)) + { + return true; + } + else + { + return false; + } + } + ) + ); +}); +```` + +The condition `typeof(IEntity).IsAssignableFrom(type)` will be `true` for any class implements the `IEntity` interface (this is technically all the entities in your application). You can conditionally check and return `true` or `false` based on your preference. + +`options.EntityHistorySelectors` is a flexible and dynamic way of selecting the entities for audit logging. Another way is to use the `Audited` and `DisableAuditing` attributes per entity. + +## Enabling/Disabling Audit Logging for Services + +### Enable/Disable for Controllers & Actions + +All the controller actions are logged by default (see `IsEnabledForGetRequests` above for GET requests). + +You can use the `[DisableAuditing]` to disable it for a specific controller type: + +````csharp +[DisableAuditing] +public class HomeController : AbpController +{ + //... +} +```` + +Use `[DisableAuditing]` for any action to control it in the action level: + +````csharp +public class HomeController : AbpController +{ + [DisableAuditing] + public async Task Home() + { + //... + } + + public async Task OtherActionLogged() + { + //... + } +} +```` + +### Enable/Disable for Application Services & Methods + +[Application service](Application-Services.md) method calls also included into the audit log by default. You can use the `[DisableAuditing]` in service or method level. + +#### Enable/Disable for Other Services + +Action audit logging can be enabled for any type of class (registered to and resolved from the [dependency injection](Dependency-Injection.md)) while it is only enabled for the controllers and the application services by default. + +Use `[Audited]` and `[DisableAuditing]` for any class or method that need to be audit logged. In addition, your class can (directly or inherently) implement the `IAuditingEnabled` interface to enable the audit logging for that class by default. + +### Enable/Disable for Entities & Properties + +An entity is ignored on entity change audit logging in the following cases; + +* If you add an entity type to the `AbpAuditingOptions.IgnoredTypes` (as explained before), it is completely ignored in the audit logging system. +* If the object is not an [entity](Entities.md) (not implements `IEntity` directly or inherently - All entities implement this interface by default). +* If entity type is not public. + +Otherwise, you can use `Audited` to enable entity change audit logging for an entity: + +````csharp +[Audited] +public class MyEntity : Entity +{ + //... +} +```` + +Or disable it for an entity: + +````csharp +[DisableAuditing] +public class MyEntity : Entity +{ + //... +} +```` + +Disabling audit logging can be necessary only if the entity is being selected by the `AbpAuditingOptions.EntityHistorySelectors` that explained before. + +You can disable auditing only some properties of your entities for a detailed control over the audit logging: + +````csharp +[Audited] +public class MyUser : Entity +{ + public string Name { get; set; } + + public string Email { get; set; } + + [DisableAuditing] //Ignore the Passoword on audit logging + public string Password { get; set; } +} +```` + +Audit log system will save changes for the `MyUser` entity while it ignores the `Password` property which can be dangerous to save for security purposes. + +In some cases, you may want to save a few properties but ignore all others. Writing `[DisableAuditing]` for all the other properties would be tedious. In such cases, use `[Audited]` only for the desired properties and mark the entity with the `[DisableAuditing]` attribute: + +````csharp +[DisableAuditing] +public class MyUser : Entity +{ + [Audited] //Only log the Name change + public string Name { get; set; } + + public string Email { get; set; } + + public string Password { get; set; } +} +```` + +## IAuditingStore + +`IAuditingStore` is an interface that is used to save the audit log objects (explained below) by the ABP Framework. If you need to save the audit log objects to a custom data store, you can implement the `IAuditingStore` in your own application and replace using the [dependency injection system](Dependency-Injection.md). + +`SimpleLogAuditingStore` is used if no audit store was registered. It simply writes the audit object to the standard [logging system](Logging.md). + +[The Audit Logging Module](Modules/Audit-Logging.md) has been configured in [the startup templates](Startup-Templates/Index.md) saves audit log objects to a database (it supports multiple database providers). So, most of the times you don't care about how `IAuditingStore` was implemented and used. + +## Audit Log Object + +An **audit log object** is created for each **web request** by default. An audit log object can be represented by the following relation diagram: + +![**auditlog-object-diagram**](images/auditlog-object-diagram.png) + +* **AuditLogInfo**: The root object with the following properties: + * `ApplicationName`: When you save audit logs of different applications to the same database, this property is used to distinguish the logs of the applications. + * `UserId`: Id of the current user, if the user has logged in. + * `UserName`: User name of the current user, if the user has logged in (this value is here to not depend on the identity module/system for lookup). + * `TenantId`: Id of the current tenant, for a multi-tenant application. + * `TenantName`: Name of the current tenant, for a multi-tenant application. + * `ExecutionTime`: The time when this audit log object has been created. + * `ExecutionDuration`: Total execution duration of the request, in milliseconds. This can be used to observe the performance of the application. + * `ClientId`: Id of the current client, if the client has been authenticated. A client is generally a 3rd-party application using the system over an HTTP API. + * `ClientName`: Name of the current client, if available. + * `ClientIpAddress`: IP address of the client/user device. + * `CorrelationId`: Current [Correlation Id](CorrelationId.md). Correlation Id is used to relate the audit logs written by different applications (or microservices) in a single logical operation. + * `BrowserInfo`: Browser name/version info of the current user, if available. + * `HttpMethod`: HTTP method of the current request (GET, POST, PUT, DELETE... etc.). + * `HttpStatusCode`: HTTP response status code for this request. + * `Url`: URL of the request. +* **AuditLogActionInfo**: An audit log action is typically a controller action or an [application service](Application-Services.md) method call during the web request. One audit log may contain multiple actions. An action object has the following properties: + * `ServiceName`: Name of the executed controller/service. + * `MethodName`: Name of the executed method of the controller/service. + * `Parameters`: A JSON formatted text representing the parameters passed to the method. + * `ExecutionTime`: The time when this method was executed. + * `ExecutionDuration`: Duration of the method execution, in milliseconds. This can be used to observe the performance of the method. +* **EntityChangeInfo**: Represents a change of an entity in this web request. An audit log may contain zero or more entity changes. An entity change has the following properties: + * `ChangeTime`: The time when the entity was changed. + * `ChangeType`: An enum with the following fields: `Created` (0), `Updated` (1) and `Deleted` (2). + * `EntityId`: Id of the entity that was changed. + * `EntityTenantId`: Id of the tenant this entity belongs to. + * `EntityTypeFullName`: Type (class) name of the entity with full namespace (like *Acme.BookStore.Book* for the Book entity). +* **EntityPropertyChangeInfo**: Represents a change of a property of an entity. An entity change info (explained above) may contain one or more property change with the following properties: + * `NewValue`: New value of the property. It is `null` if the entity was deleted. + * `OriginalValue`: Old/original value before the change. It is `null` if the entity was newly created. + * `PropertyName`: The name of the property on the entity class. + * `PropertyTypeFullName`: Type (class) name of the property with full namespace. +* **Exception**: An audit log object may contain zero or more exception. In this way, you can get a report of the failed requests. +* **Comment**: An arbitrary string value to add custom messages to the audit log entry. An audit log object may contain zero or more comments. + +In addition to the standard properties explained above, `AuditLogInfo`, `AuditLogActionInfo` and `EntityChangeInfo` objects implement the `IHasExtraProperties` interface, so you can add custom properties to these objects. + +## Audit Log Contributors + +You can extend the auditing system by creating a class that is derived from the `AuditLogContributor` class which defines the `PreContribute` and the `PostContribute` methods. + +The only pre-built contributor is the `AspNetCoreAuditLogContributor` class which sets the related properties for an HTTP request. + +A contributor can set properties and collections of the `AuditLogInfo` class to add more information. + +Example: + +````csharp +public class MyAuditLogContributor : AuditLogContributor +{ + public override void PreContribute(AuditLogContributionContext context) + { + var currentUser = context.ServiceProvider.GetRequiredService(); + context.AuditInfo.SetProperty( + "MyCustomClaimValue", + currentUser.FindClaimValue("MyCustomClaim") + ); + } + + public override void PostContribute(AuditLogContributionContext context) + { + context.AuditInfo.Comments.Add("Some comment..."); + } +} +```` + +* `context.ServiceProvider` can be used to resolve services from the [dependency injection](Dependency-Injection.md). +* `context.AuditInfo` can be used to access to the current audit log object to manipulate it. + +After creating such a contributor, you must add it to the `AbpAuditingOptions.Contributors` list: + +````csharp +Configure(options => +{ + options.Contributors.Add(new MyAuditLogContributor()); +}); +```` + +## IAuditLogScope & IAuditingManager + +This section explains the `IAuditLogScope` & `IAuditingManager` services for advanced use cases. + +An **audit log scope** is an [ambient scope](Ambient-Context-Pattern.md) that **builds** and **saves** an audit log object (explained before). By default, an audit log scope is created for a web request by the Audit Log Middleware (see `UseAuditing()` section above). + +### Access to the Current Audit Log Scope + +Audit log contributors, was explained above, is a global way of manipulating the audit log object. It is good if you can get a value from a service. + +If you need to manipulate the audit log object in an arbitrary point of your application, you can access to the current audit log scope and get the current audit log object (independent of how the scope is managed). Example: + +````csharp +public class MyService : ITransientDependency +{ + private readonly IAuditingManager _auditingManager; + + public MyService(IAuditingManager auditingManager) + { + _auditingManager = auditingManager; + } + + public async Task DoItAsync() + { + var currentAuditLogScope = _auditingManager.Current; + if (currentAuditLogScope != null) + { + currentAuditLogScope.Log.Comments.Add( + "Executed the MyService.DoItAsync method :)" + ); + + currentAuditLogScope.Log.SetProperty("MyCustomProperty", 42); + } + } +} +```` + +Always check if `_auditingManager.Current` is null or not, because it is controlled in an outer scope and you can't know if an audit log scope was created before calling your method. + +### Manually Create an Audit Log Scope + +You rarely need to create a manual audit log scope, but if you need, you can create an audit log scope using the `IAuditingManager` as like in the following example: + +````csharp +public class MyService : ITransientDependency +{ + private readonly IAuditingManager _auditingManager; + + public MyService(IAuditingManager auditingManager) + { + _auditingManager = auditingManager; + } + + public async Task DoItAsync() + { + using (var auditingScope = _auditingManager.BeginScope()) + { + try + { + //Call other services... + } + catch (Exception ex) + { + //Add exceptions + _auditingManager.Current.Log.Exceptions.Add(ex); + } + finally + { + //Always save the log + await auditingScope.SaveAsync(); + } + } + } +} +```` + +You can call other services, they may call others, they may change entities and so on. All these interactions are saved as a single audit log object in the finally block. + +## The Audit Logging Module + +The Audit Logging Module basically implements the `IAuditingStore` to save the audit log objects to a database. It supports multiple database providers. This module is added to the startup templates by default. + +See [the Audit Logging Module document](Modules/Audit-Logging.md) for more about it. \ No newline at end of file diff --git a/docs/en/Background-Jobs-Hangfire.md b/docs/en/Background-Jobs-Hangfire.md index 031ae28589..588fcace9e 100644 --- a/docs/en/Background-Jobs-Hangfire.md +++ b/docs/en/Background-Jobs-Hangfire.md @@ -1,3 +1,43 @@ # Hangfire Background Job Manager -TODO \ No newline at end of file +[Hangfire](https://www.hangfire.io/) is an advanced background job manager. You can integrate Hangfire with the ABP Framework to use it instead of the [default background job manager](Background-Jobs.md). In this way, you can use the same background job API for Hangfire and your code will be independent of Hangfire. If you like, you can directly use Hangfire's API, too. + +> See the [background jobs document](Background-Jobs.md) to learn how to use the background job system. This document only shows how to install and configure the Hangfire integration. + +## Installation + +It is suggested to use the [ABP CLI](CLI.md) to install this package. + +### Using the ABP CLI + +Open a command line window in the folder of the project (.csproj file) and type the following command: + +````bash +abp add-package Volo.Abp.BackgroundJobs.HangFire +```` + +### Manual Installation + +If you want to manually install; + +1. Add the [Volo.Abp.BackgroundJobs.HangFire](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.HangFire) NuGet package to your project: + + ```` + Install-Package Volo.Abp.BackgroundJobs.HangFire + ```` + +2. Add the `AbpBackgroundJobsHangfireModule` to the dependency list of your module: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpBackgroundJobsHangfireModule) //Add the new module dependency + )] +public class YourModule : AbpModule +{ +} +```` + +## Configuration + +TODO... \ No newline at end of file diff --git a/docs/en/Best-Practices/Entity-Framework-Core-Integration.md b/docs/en/Best-Practices/Entity-Framework-Core-Integration.md index f150bd6f66..4f7e20dd70 100644 --- a/docs/en/Best-Practices/Entity-Framework-Core-Integration.md +++ b/docs/en/Best-Practices/Entity-Framework-Core-Integration.md @@ -174,12 +174,12 @@ public static IQueryable IncludeDetails( * **Do** use the `IncludeDetails` extension method in the repository methods just like used in the example code above (see FindByNormalizedUserNameAsync). -- **Do** override `IncludeDetails` method of the repository for aggregates root which have **sub collections**. Example: +- **Do** override `WithDetails` method of the repository for aggregates root which have **sub collections**. Example: ````C# -protected override IQueryable IncludeDetails(IQueryable queryable) +public override IQueryable WithDetails() { - return queryable.IncludeDetails(); //uses the extension method defined above + return GetQueryable().IncludeDetails(); // Uses the extension method defined above } ```` @@ -206,4 +206,3 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule } } ```` - diff --git a/docs/en/Best-Practices/Index.md b/docs/en/Best-Practices/Index.md index 1a48c6b46b..f3f626ca63 100644 --- a/docs/en/Best-Practices/Index.md +++ b/docs/en/Best-Practices/Index.md @@ -23,5 +23,5 @@ Also, this guide is mostly usable for general **application development**. * [Data Transfer Objects](Data-Transfer-Objects.md) * Data Access * [Entity Framework Core Integration](Entity-Framework-Core-Integration.md) - * [MongoDB Integration](MongoDB-Integration.md) + * [MongoDB Integration](MongoDB-Integration.md) diff --git a/docs/en/Best-Practices/PostgreSQL-Integration.md b/docs/en/Best-Practices/PostgreSQL-Integration.md deleted file mode 100644 index 2f6dd03be7..0000000000 --- a/docs/en/Best-Practices/PostgreSQL-Integration.md +++ /dev/null @@ -1,73 +0,0 @@ -## Entity Framework Core PostgreSQL Integration - -> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration. - -### EntityFrameworkCore Project Update - -- In `Acme.BookStore.EntityFrameworkCore` project replace package `Volo.Abp.EntityFrameworkCore.SqlServer` with `Volo.Abp.EntityFrameworkCore.PostgreSql` -- Update to use PostgreSQL in `BookStoreEntityFrameworkCoreModule` - - Replace the `AbpEntityFrameworkCoreSqlServerModule` with the `AbpEntityFrameworkCorePostgreSqlModule` - - Replace the `options.UseSqlServer()` with the `options.UsePostgreSql()` -- In other projects update the PostgreSQL connection string in necessary `appsettings.json` files - - more info of [PostgreSQL connection strings](https://www.connectionstrings.com/postgresql/),You need to pay attention to `Npgsql` in this document - -### EntityFrameworkCore.DbMigrations Project Update -- Update to use PostgreSQL in `XXXMigrationsDbContextFactory` - - Replace the `new DbContextOptionsBuilder().UseSqlServer()` with the `new DbContextOptionsBuilder().UseNpgsql()` - -### Delete Existing Migrations - -Delete all existing migration files (including `DbContextModelSnapshot`) - -![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png) - -### Regenerate Initial Migration - -Set the correct startup project (usually a web project) - -![set-as-startup-project](../images/set-as-startup-project.png) - -Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command: - -Run `Add-Migration` command. -```` -PM> Add-Migration Initial -```` - -### Update the Database - -You have two options to create the database. - -#### Using the DbMigrator Application - -The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment. - -> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one. - -Right click to the `.DbMigrator` project and select **Set as StartUp Project**: - -![set-as-startup-project](../images/set-as-startup-project.png) - -Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below: - -![set-as-startup-project](../images/db-migrator-app.png) - -#### Using EF Core Update-Database Command - -Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations. - -Set the correct startup project (usually a web project) - -![set-as-startup-project](../images/set-as-startup-project.png) - -Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command: - -```` -PM> Update-Database -```` - -This will create a new database based on the configured connection string. - -![postgresql-update-database](images/postgresql-update-database.png) - -> Using the `.DbMigrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application. diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md new file mode 100644 index 0000000000..d3a525c63f --- /dev/null +++ b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md @@ -0,0 +1,164 @@ +# ABP Framework v2.0 and the ABP Commercial + +ABP Framework v2.0 has been released in this week. This post explains why we have released an **early major version** and what is changed with version 2.0. + +In addition to the v2.0 release, we are excited to announce the **ABP Commercial**, which is a set of professional modules, tools, themes, and services built on top of the open-source ABP framework. + +## ABP Framework v2.0 + +### Why 2.0 instead of 1.2? + +It was planned to release v1.2 after the [v1.1.2](https://github.com/abpframework/abp/releases/tag/1.1.2) release. However, [it is reported](https://github.com/abpframework/abp/issues/2026) that v1.x has some **performance** and **stability** issues on Linux, especially when you deploy your application to **Linux** containers with **low CPU and memory** resources. + +We have investigated the problem deeply and have seen that the root cause of the problem was related to the implementation of **intercepting `async` methods**. Besides, there were some **`async` over `sync`** usages that effected the thread pool optimization. + +Finally, we **solved all the problems** with the great help of the **community**. But we also had some important **design decisions** which cause some **breaking changes** and we had to change the major version number of the framework because of the [semantic versioning](https://semver.org/). + +Most of the applications won't be affected by [the breaking changes](https://github.com/abpframework/abp/releases), or it will be trivial to make these necessary changes. + +### Breaking Changes + +#### Removed Some Sync APIs + +Some of the interceptors are required to use `async` APIs. When they intercept `sync` methods, they need to call `async` over `sync`. This eventually ends up with `async` over `sync` problem. That's why we have [removed some sync APIs](https://github.com/abpframework/abp/pull/2464). + +**`Async` over `sync`** pattern is a classical problem of `C#` when you need to **call an `async` method inside a `sync` method**. While there are some workarounds to this problem, they all have **disadvantages** and it is suggested to **not write** such code at all. You can find many documents related to this topic on the web. + +To avoid this problem, we have removed: + +- `sync` [repository](https://docs.abp.io/en/abp/latest/Repositories) methods (like `insert`, `update`, etc...), +- `sync` APIs of the [unit of work](https://docs.abp.io/en/abp/latest/Unit-Of-Work), +- `sync` APIs of the [background jobs](https://docs.abp.io/en/abp/latest/Background-Jobs), +- `sync` APIs of the [audit logging](https://docs.abp.io/en/abp/latest/Audit-Logging), +- some other rarely used `sync` APIs. + +If you get any compile error, just use the `async` versions of these APIs. + +#### Always Async! + +Beginning from the v2.0, the ABP framework assumes that you are writing your application code `async` first. Otherwise, some framework functionalities may not properly work. + +It is suggested to write `async` to all your [application services](https://docs.abp.io/en/abp/latest/Application-Services), [repository methods](https://docs.abp.io/en/abp/latest/Repositories), controller actions, page handlers. + +Even if your application service method doesn't need to be `async` , set it as `async` , because interceptors perform `async` operations (for authorization, unit of work, etc...). You can return `Task.Completed` from a method that doesn't make an `async` call. + +Example: + +````csharp +public Task GetValueAsync() +{ + //this method doesn't make any async call. + return Task.CompletedTask(42); +} +```` + +The example above normally doesn't need to be `async` because it doesn't perform an `async` call. However, making it `async` helps the ABP framework to run interceptors without `async` over sync calls. + +This rule doesn't force you to write every method `async` . This would not be good and would be tedious. It is only needed for the intercepted services (especially for [application services](https://docs.abp.io/en/abp/latest/Application-Services) and [repository methods](https://docs.abp.io/en/abp/latest/Repositories)) + +#### Other Breaking Changes + +See [the release notes](https://github.com/abpframework/abp/releases/tag/2.0.0) for the other breaking changes. Most of them will not affect your application code. + +### New Features + +This release also contains some new features and tens of enhancements: + +- [#2597](https://github.com/abpframework/abp/pull/2597) New `Volo.Abp.AspNetCore.Serilog` package. +- [#2526](https://github.com/abpframework/abp/issues/2526) Client-side validation for the dynamic `C#` client proxies. +- [#2374](https://github.com/abpframework/abp/issues/2374) `Async` background jobs. +- [#265](https://github.com/abpframework/abp/issues/265) Managing the application shutdown. +- [#2472](https://github.com/abpframework/abp/issues/2472) Implemented `DeviceFlowCodes` and `TokenCleanupService` for the `IdentityServer` module. + +See [the release notes](https://github.com/abpframework/abp/releases/tag/2.0.0) for the complete list of features, enhancements and bug fixes. + +### Documentation + +We have completed some missing documentation with the v2.0 release. In the following weeks, we will mostly focus on the documentation and tutorials. + +## ABP Commercial + +[ABP Commercial](https://commercial.abp.io/) is a set of professional **modules, tools, themes, and services** built on top of the open-source ABP framework. + +- It provides [professional modules](https://commercial.abp.io/modules) in addition to the ABP Framework's free & [open source modules](https://docs.abp.io/en/abp/latest/Modules/Index). +- It includes a beautiful a [UI theme](https://commercial.abp.io/themes) with 5 different styles. +- It provides the [ABP Suite](https://commercial.abp.io/tools/suite); A tool to assist your development to make you more productive. It currently can create full-stack CRUD pages in a few seconds by configuring your entity properties. More functionalities will be added over time. +- [Premium support](https://commercial.abp.io/support) for enterprise companies. + +In addition to these standard set of features, we will provide customer basis services. See the [commercial.abp.io](https://commercial.abp.io/) web site for other details. + +### ABP Framework vs the ABP Commercial + +The ABP Commercial **is not a paid version** of the ABP Framework. You can consider it as **set of additional benefits** for professional companies. You can use it to save your time and develop your product faster. + +ABP Framework is **open source & free** and will always be like that! + +As a principle, we build the main infrastructure as open-source and sell additional pre-built application features, themes, and tools. The main idea similar to the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) & the [ASP.NET Zero](https://aspnetzero.com/) products. + +Buying a commercial license saves your significant time and effort and you can focus on your own business, besides you get dedicated and high priority support. Also, you will be supporting the ABP core team since we are spending most of our time to develop, maintain and support the open-source ABP Framework. + +With the introduction of the ABP Commercial, now ABP becomes a platform. We call it as the **ABP.IO Platform** which consists of the open source ABP Framework and the ABP Commercial. + +### Demo + +If you are wondering how exactly looks like the ABP Commercial application startup template, you can easily [create a demo](https://commercial.abp.io/demo) and see it in action. The demo includes all the pre-built modules and the theme. + +Here, a screenshot from the IdentityServer management module UI: + +![abp-commercial-demo](abp-commercial-demo.png) + +This is another screenshot from a demo application using the material design style of the theme: + +![lepton-theme-material](lepton-theme-material.png) + +### Pricing + +You can build **unlimited projects/products**, sell to **unlimited customers**, host **unlimited servers** without any restriction. Pricing is mostly based on the **developer count**, **support level** and **source code** requirement. There are three main packages; + +- **Team license**: Includes all the modules, themes and tools. Allows developing your product with up to 3 developers. You can buy additional developer licenses. +- **Business license**: Allows downloading the source code of all the modules and the themes. Also, it includes 5 developer licenses by default. You can buy additional developer licenses. +- **Enterprise license**: Provides unlimited and private support in addition to the benefits of the business license. + +See the [pricing page](https://commercial.abp.io/pricing) for details. In addition to the standard packages, we are also providing custom services and custom licensing. [Contact us](https://commercial.abp.io/contact) if you have any questions. + +#### License Comparison + +The license price changes based on your developer count, support level and source-code access. + +##### The Source-Code + +Team license doesn't include the source-code of the pre-built modules & themes. It uses all these modules as **NuGet & NPM packages**. In this way, you can easily **get new features and bug fixes** by just updating the package dependencies. But you can't access their source-code. So you don't have the possibility to embed a module's source code into your application and freely change the source-code. + +Pre-built modules provide some level of **customization** and **extensibility** and allow you to override services, UI parts and so on. We are working on to make them much more customizable and extensible. If you don't need to make major changes in the pre-built modules, the team license will be ideal for you, because it is cheaper and allows you to easily get new features and bug fixes. + +Business and Enterprise licenses allow you to **download the source-code** of any module or the theme when you need it. They also use the same startup template with the team license, so all modules are used as `NuGet` & `NPM` packages by default. But in case of need, you can remove the package dependencies for a module and embed its source-code into your own solution to completely customize it. In this case, upgrading the module will not be as easy as before when a new version is available. You don't have to upgrade it, surely! But if you want, you should do it yourself using some merge tool or Git branch system. + +#### License Lifetime + +ABP Commercial license is **perpetual**, which means you can **use it forever** and continue to develop your applications. + +However, the following services are covered for one year: + +- Premium **support** ends after one year. You can continue to get community support. +- You can not get **updates** of the modules & the themes after one year. You can continue to use the last obtained version. You can even get bug fixes and enhancements for your current major version. +- You can use the **ABP Suite** tool for one year. + +If you want to continue to get these benefits, you can extend your license period. Renewing price is 20% less than the regular price. + +## NDC London 2020 + +Just like the [previous year](https://medium.com/volosoft/impressions-of-ndc-london-2019-f8f391bb7a9c), we are a partner of the famous software development conference: [NDC London](https://ndc-london.com/)! In the previous year, we were there with the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) & [ASP.NET Zero](https://aspnetzero.com/) theme: + +![ndc-london-volosoft](ndc-london-volosoft.png) + +This year, we will be focusing on the **ABP.IO Platform** (The Open Source ABP Framework and the ABP Commercial). Our booth wall will be like that: + +![ndc-london-volosoft](ndc-2020-volosoft-booth-wall.png) + +If you attend to the conference, remember to visit our booth. We would be glad to talk about the ABP platform features, goals and software development in general. + +### Would you like to meet the ABP Team? + +If you are in London and want to have a coffee with us, we will be available at February 1st afternoon. [@hibrahimkalkan](https://twitter.com/hibrahimkalkan) and [@ismcagdas](https://twitter.com/ismcagdas) will be there. + +Just write to info@abp.io if you want to meet :) \ No newline at end of file diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png new file mode 100644 index 0000000000..caddce27ab Binary files /dev/null and b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png differ diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-io-abpcommercial-release.png b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-io-abpcommercial-release.png new file mode 100644 index 0000000000..4366ceb986 Binary files /dev/null and b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-io-abpcommercial-release.png differ diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png new file mode 100644 index 0000000000..72cb5c0639 Binary files /dev/null and b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png differ diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png new file mode 100644 index 0000000000..70fb9d54f7 Binary files /dev/null and b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png differ diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png new file mode 100644 index 0000000000..afaed37a7a Binary files /dev/null and b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png differ diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 57bda25004..a1d3d51138 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -128,6 +128,24 @@ abp update [options] * `--npm`: Only updates NPM packages. * `--nuget`: Only updates NuGet packages. +### login + +Some features of the CLI requires to be logged in to abp.io platform. To login with your username write + +```bash +abp login +``` + +Notice that, a new login with an already active session, will kill the previous session and creates a new one. + +### logout + +Logs you out by removing the session token from your computer. + +``` +abp logout +``` + ### help Writes basic usage information of the CLI. diff --git a/docs/en/Connection-Strings.md b/docs/en/Connection-Strings.md index 36103011e1..eb7aae3a21 100644 --- a/docs/en/Connection-Strings.md +++ b/docs/en/Connection-Strings.md @@ -1,11 +1,88 @@ -# Data Access +# Connection Strings -ABP framework was designed as database agnostic, it can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions. +ABP Framework is designed to be [modular](Module-Development-Basics.md), [microservice compatible](Microservice-Architecture.md) and [multi-tenancy](Multi-Tenancy.md) aware. Connection string management is also designed to support these scenarios; -However, currently the following providers are implements: +* Allows to set separate connection strings for every module, so every module can have its own physical database. Modules even might be configured to use different DBMSs. +* Allows to set separate connection string and use a separate database per tenant (in a SaaS application). -* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli).) -* [MongoDB](MongoDB.md) -* [Dapper](Dapper.md) +It also supports hybrid scenarios; -More providers might be added in the next releases. \ No newline at end of file +* Allows to group modules into databases (all modules into a single shared database, 2 modules to database A, 3 modules to database B, 1 module to database C and rest of the modules to database D... etc.) +* Allows to group tenants into databases, just like the modules. +* Allows to separate databases per tenant per module (which might be harder to maintain for you because of too many databases, but the ABP framework supports it). + +All the [pre-built application modules](Modules/Index.md) are designed to be compatible these scenarios. + +## Configure the Connection Strings + +See the following configuration: + +````json +"ConnectionStrings": { + "Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;", + "AbpIdentityServer": "Server=localhost;Database=MyIdsDb;Trusted_Connection=True;", + "AbpPermissionManagement": "Server=localhost;Database=MyPermissionDb;Trusted_Connection=True;" +} +```` + +> ABP uses the `IConfiguration` service to get the application configuration. While the simplest way to write configuration into the `appsettings.json` file, it is not limited to this file. You can use environment variables, user secrets, Azure Key Vault... etc. See the [configuration](Configuration.md) document for more. + +This configuration defines three different connection strings: + +* `MyMainDb` (the `Default` connection string) is the main connection string of the application. If you don't specify a connection string for a module, it fallbacks to the `Default` connection string. The [application startup template](Startup-Templates/Application.md) is configured to use a single connection string, so all the modules uses a single shared database. +* `MyIdsDb` is used by the [IdentityServer](Modules/IdentityServer.md) module. +* `MyPermissionDb` is used by the [Permission Management](Modules/Permission-Management.md) module. + +[Pre-built application modules](Modules/Index.md) define constants for the connection string names. For example, the IdentityServer module defines a ` ConnectionStringName ` constant in the ` AbpIdentityServerDbProperties ` class (located in the ` Volo.Abp.IdentityServer ` namespace). Other modules similarly define constants, so you can investigate the connection string name. + +### AbpDbConnectionOptions + +ABP actually uses the `AbpDbConnectionOptions` to get the connection strings. If you set the connection strings as explained above, `AbpDbConnectionOptions` is automatically filled. However, you can set or override the connection strings using [the options pattern](Options.md). You can configure the `AbpDbConnectionOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) as shown below: + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + Configure(options => + { + options.ConnectionStrings.Default = "..."; + options.ConnectionStrings["AbpPermissionManagement"] = "..."; + }); +} +```` + +## Set the Connection String Name + +A module typically has a unique connection string name associated to its `DbContext` class using the `ConnectionStringName` attribute. Example: + +````csharp +[ConnectionStringName("AbpIdentityServer")] +public class IdentityServerDbContext + : AbpDbContext, IIdentityServerDbContext +{ +} +```` + +For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), write this to your `DbContext` class (and the interface if it has). + +> If you are developing a reusable, database provider independent module see also [the best practices guide](Best-Practices/Index.md). + +## Database Migrations for the Entity Framework Core + +Relational databases require to create the database and the database schema (tables, views... etc.) before using it. + +The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore.DbMigrations` project that contains the migration files for that database. This project mainly defines a *YourProjectName*MigrationsDbContext that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`. + +Once you want to separate a module's database, you typically will need to create a second migration path. The easiest way to create a copy of the `.EntityFrameworkCore.DbMigrations` project with the `DbContext` inside it, change its content to only call the `Configure...()` methods of the modules needs to be stored in the second database and re-create the initial migration. In this case, you also need to change the `.DbMigrator` application to be able to work with these second database too. In this way, you will have a separate migrations DbContext per database. + +## Multi-Tenancy + +See [the multi-tenancy document](Multi-Tenancy.md) to learn how to use separate databases for tenants. + +## Replace the Connection String Resolver + +ABP defines the `IConnectionStringResolver` and uses it whenever it needs a connection string. It has two pre-built implementations: + +* `DefaultConnectionStringResolver` uses the `AbpDbConnectionOptions` to select the connection string based on the rules defined in the "Configure the Connection Strings" section above. +* `MultiTenantConnectionStringResolver` used for multi-tenant applications and tries to get the configured connection string for the current tenant if available. It uses the `ITenantStore` to find the connection strings. It inherits from the `DefaultConnectionStringResolver` and fallbacks to the base logic if no connection string specified for the current tenant. + +If you need a custom logic to determine the connection string, implement the `IConnectionStringResolver` interface (optionally derive from the existing implementations) and replace the existing implementation using the [dependency injection](Dependency-Injection.md) system. \ No newline at end of file diff --git a/docs/en/Contribution/Localization-Text-Files.md b/docs/en/Contribution/Localization-Text-Files.md index 3932800575..2a8e5ee468 100644 --- a/docs/en/Contribution/Localization-Text-Files.md +++ b/docs/en/Contribution/Localization-Text-Files.md @@ -3,7 +3,7 @@ Here, a list of localization text files for anyone wants to contribute to localization of the texts coming from the framework. We will keep this list up to date: * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json -* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json +* https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json * https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json * https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json @@ -12,29 +12,20 @@ Here, a list of localization text files for anyone wants to contribute to locali * https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json * https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json * https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json -* https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json +* https://github.com/abpframework/abp/blob/master/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json * https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json +* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json * https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json * https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Web/Localization/Resources/Docs/Web/en.json * https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Localization/Resources/FeatureManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json -* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json -* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Localization/Resources/AbpSettingManagement/en.json -* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json +* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json +* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json +* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json +* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json +* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json * https://github.com/abpframework/abp/tree/master/samples/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json -* https://github.com/abpframework/abp/tree/master/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json +* https://github.com/abpframework/abp/tree/master/samples/DashboardDemo/src/DashboardDemo.Domain.Shared/Localization/DashboardDemo/en.json * https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json * https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json * https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Application.Contracts/Localization/MyProjectName/ApplicationContracts/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/DomainShared/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Web/Localization/MyProjectName/Web/en.json -* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json +* https://github.com/abpframework/abp/tree/master/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json diff --git a/docs/en/Data-Access.md b/docs/en/Data-Access.md index 36103011e1..a37f77eb65 100644 --- a/docs/en/Data-Access.md +++ b/docs/en/Data-Access.md @@ -1,11 +1,15 @@ # Data Access -ABP framework was designed as database agnostic, it can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions. +## Database Providers -However, currently the following providers are implements: +ABP framework was designed as database agnostic. It can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions. However, currently the following providers are implemented: -* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli).) +* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/).) * [MongoDB](MongoDB.md) * [Dapper](Dapper.md) -More providers might be added in the next releases. \ No newline at end of file +More providers will be added in the future. + +## See Also + +* [Connection Strings](Connection-Strings.md) \ No newline at end of file diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index eb0da4a0e4..335e829461 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -166,6 +166,24 @@ public class BlogModule : AbpModule } ```` +### Replace a Service + +If you need to replace an existing service (defined by the ABP framework or another module dependency), you have two options; + +1. Use the `Dependency` attribute of the ABP framework as explained above. +2. Use the `IServiceCollection.Replace` method of the Microsoft Dependency Injection library. Example: + +````csharp +public class MyModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + //Replacing the IConnectionStringResolver service + context.Services.Replace(ServiceDescriptor.Transient()); + } +} +```` + ## Injecting Dependencies There are three common ways of using a service that has already been registered. diff --git a/docs/en/Entities.md b/docs/en/Entities.md index 8ae7cdf235..b5d196cccb 100644 --- a/docs/en/Entities.md +++ b/docs/en/Entities.md @@ -1,34 +1,87 @@ -## Entities +# Entities Entities are one of the core concepts of DDD (Domain Driven Design). Eric Evans describe it as "*An object that is not fundamentally defined by its attributes, but rather by a thread of continuity and identity*". An entity is generally mapped to a table in a relational database. -### Entity Class +## Entity Class -Entities are derived from `Entity` class as shown below: +Entities are derived from the `Entity` class as shown below: ```C# -public class Person : Entity +public class Book : Entity { public string Name { get; set; } - public DateTime CreationTime { get; set; } + public float Price { get; set; } +} +``` + +> If you do not want to derive your entity from the base `Entity` class, you can directly implement `IEntity` interface. + +`Entity` class just defines an `Id` property with the given primary **key type**, which is `Guid` in the example above. It can be other types like `string`, `int`, `long` or whatever you need. + +### Entities with GUID Keys + +If your entity's Id type is `Guid`, there are some good practices to implement: + +* Create a constructor that gets the Id as a parameter and passes to the base class. + * If you don't set a GUID Id, ABP Framework sets it on save, but it is good to have a valid Id on the entity even before saving it to the database. +* If you create an entity with a constructor that takes parameters, also create a `protected` empty constructor. This is used while your database provider reads your entity from the database (on deserialization). +* Don't use the `Guid.NewGuid()` to set the Id! Use [the `IGuidGenerator` service](Guid-Generation.md) while passing the Id from the code that creates the entity. `IGuidGenerator` optimized to generate sequential GUIDs, which is critical for clustered indexes in the relational databases. + +An example entity: - public Person() +````csharp +public class Book : Entity +{ + public string Name { get; set; } + + public float Price { get; set; } + + protected Book() { - CreationTime = DateTime.Now; + + } + + public Book(Guid id) + : base(id) + { + } } -``` +```` -> If you do not want to derive your entity from the base `Entity` class, you can directly implement `IEntity` interface. +Example usage in an [application service](Application-Services.md): -`Entity` class just defines an `Id` property with the given primary **key type**, which is `int` in the sample above. It can be other types like `string`, `Guid`, `long` or whatever you need. +````csharp +public class BookAppService : ApplicationService, IBookAppService +{ + private readonly IRepository _bookRepository; -Entity class also overrides the **equality** operator (==) to easily check if two entities are equal (they are equals if they are same entity type and their Ids are equals). + public BookAppService(IRepository bookRepository) + { + _bookRepository = bookRepository; + } -#### Entities with Composite Keys + public async Task CreateAsync(CreateBookDto input) + { + await _bookRepository.InsertAsync( + new Book(GuidGenerator.Create()) + { + Name = input.Name, + Price = input.Price + } + ); + } +} +```` + +* `BookAppService` injects the default [repository](Repositories.md) for the book entity and uses its `InsertAsync` method to insert a `Book` to the database. +* `GuidGenerator` is type of `IGuidGenerator` which is a property defined in the `ApplicationService` base class. ABP defines such frequently used base properties as pre-injected for you, so you don't need to manually [inject](Dependency-Injection.md) them. +* If you want to follow the DDD best practices, see the *Aggregate Example* section below. + +### Entities with Composite Keys Some entities may need to have **composite keys**. In that case, you can derive your entity from the non-generic `Entity` class. Example: @@ -53,31 +106,31 @@ public class UserRole : Entity } ```` -For the example above, the composite key is composed of `UserId` and `RoleId`. For a relational database, it is the composite primary key of the related table. - -Entities with composite keys should implement the `GetKeys()` method as shown above. +For the example above, the composite key is composed of `UserId` and `RoleId`. For a relational database, it is the composite primary key of the related table. Entities with composite keys should implement the `GetKeys()` method as shown above. -Notice that you also need to define keys of the entity in your **object-relational mapping** (ORM) configuration. +> Notice that you also need to define keys of the entity in your **object-relational mapping** (ORM) configuration. See the [Entity Framework Core](Entity-Framework-Core.md) integration document for example. -> Also note that Entities with Composite Primary Keys cannot utilize the `IRepository` interface since it requires a single unique Id property. However, you can always use `IRepository`. See [repositories documentation](Repositories.md) for more. +> Also note that Entities with Composite Primary Keys cannot utilize the `IRepository` interface since it requires a single Id property. However, you can always use `IRepository`. See [repositories documentation](Repositories.md) for more. -### AggregateRoot Class +## AggregateRoot Class "*Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.*" (see the [full description](http://martinfowler.com/bliki/DDD_Aggregate.html)) -`AggregateRoot` class extends the `Entity` class. So, it also has an `Id` property by default. +`AggregateRoot` class extends the `Entity` class. So, it also has an `Id` property by default. -> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See [repositories documentation](Repositories.md) for more. +> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See the [repositories documentation](Repositories.md) for more. -ABP does not force you to use aggregate roots, you can in fact use the `Entity` class as defined before. However, if you want to implement DDD and want to create aggregate root classes, there are some best practices you may want to consider: +ABP does not force you to use aggregate roots, you can in fact use the `Entity` class as defined before. However, if you want to implement the [Domain Driven Design](Domain-Driven-Design.md) and want to create aggregate root classes, there are some best practices you may want to consider: * An aggregate root is responsible to preserve it's own integrity. This is also true for all entities, but aggregate root has responsibility for it's sub entities too. So, the aggregate root must always be in a valid state. * An aggregate root can be referenced by it's Id. Do not reference it by it's navigation property. * An aggregate root is treated as a single unit. It's retrieved and updated as a single unit. It's generally considered as a transaction boundary. * Work with sub-entities over the aggregate root- do not modify them independently. -#### Aggregate Example +See the [entity design best practice guide](Best-Practices/Entities.md) if you want to implement DDD in your application. + +### Aggregate Example This is a full sample of an aggregate root with a related sub-entity collection: @@ -156,6 +209,11 @@ public class OrderLine : Entity { Count = newCount; } + + public override object[] GetKeys() + { + return new Object[] {OrderId, ProductId}; + } } ```` @@ -163,15 +221,80 @@ public class OrderLine : Entity `Order` is an **aggregate root** with `Guid` type `Id` property. It has a collection of `OrderLine` entities. `OrderLine` is another entity with a composite primary key (`OrderId` and ` ProductId`). -While this example may not implement all the best practices of an aggregate root, it still follows good practices: +While this example may not implement all the best practices of an aggregate root, it still follows some good practices: * `Order` has a public constructor that takes **minimal requirements** to construct an `Order` instance. So, it's not possible to create an order without an id and reference number. The **protected/private** constructor is only necessary to **deserialize** the object while reading from a data source. * `OrderLine` constructor is internal, so it is only allowed to be created by the domain layer. It's used inside of the `Order.AddProduct` method. * `Order.AddProduct` implements the business rule to add a product to an order. * All properties have `protected` setters. This is to prevent the entity from arbitrary changes from outside of the entity. For exmple, it would be dangerous to set `TotalItemCount` without adding a new product to the order. It's value is maintained by the `AddProduct` method. -ABP does not force you to apply any DDD rule or patterns. However, it tries to make it possible and easier when you do want to apply them. The documentation also follows the same principle. +ABP Framework does not force you to apply any DDD rule or patterns. However, it tries to make it possible and easier when you do want to apply them. The documentation also follows the same principle. -#### Aggregate Roots with Composite Keys +### Aggregate Roots with Composite Keys While it's not common (and not suggested) for aggregate roots, it is in fact possible to define composite keys in the same way as defined for the mentioned entities above. Use non-generic `AggregateRoot` base class in that case. + +## Base Classes & Interfaces for Audit Properties + +There are some properties like `CreationTime`, `CreatorId`, `LastModificationTime`... which are very common in all applications. ABP Framework provides some interfaces and base classes to **standardize** these properties and also **sets their values automatically**. + +### Auditing Interfaces + +There are a lot of auditing interfaces, so you can implement the one that you need. + +> While you can manually implement these interfaces, you can use **the base classes** defined in the next section to simplify it. + +* `IHasCreationTime` defines the following properties: + * `CreationTime` +* `IMayHaveCreator` defines the following properties: + * `CreatorId` +* `ICreationAuditedObject` inherits from the `IHasCreationTime` and the `IMayHaveCreator`, so it defines the following properties: + * `CreationTime` + * `CreatorId` +* `IHasModificationTime` defines the following properties: + * `LastModificationTime` +* `IModificationAuditedObject` extends the `IHasModificationTime` and adds the `LastModifierId` property. So, it defines the following properties: + * `LastModificationTime` + * `LastModifierId` +* `IAuditedObject` extends the `ICreationAuditedObject` and the `IModificationAuditedObject`, so it defines the following properties: + * `CreationTime` + * `CreatorId` + * `LastModificationTime` + * `LastModifierId` +* `ISoftDelete` (see the [data filtering document](Data-Filtering.md)) defines the following properties: + * `IsDeleted` +* `IHasDeletionTime` extends the `ISoftDelete` and adds the `DeletionTime` property. So, it defines the following properties: + * `IsDeleted` + * `DeletionTime` +* `IDeletionAuditedObject` extends the `IHasDeletionTime` and adds the `DeleterId` property. So, it defines the following properties: + * `IsDeleted` + * `DeletionTime` + * `DeleterId` +* `IFullAuditedObject` inherits from the `IAuditedObject` and the `IDeletionAuditedObject`, so it defines the following properties: + * `CreationTime` + * `CreatorId` + * `LastModificationTime` + * `LastModifierId` + * `IsDeleted` + * `DeletionTime` + * `DeleterId` + +Once you implement any of the interfaces, or derive from a class defined in the next section, ABP Framework automatically manages these properties wherever possible. + +> Implementing `ISoftDelete`, `IDeletionAuditedObject` or `IFullAuditedObject` makes your entity **soft-delete**. See the [data filtering document](Data-Filtering.md) to learn about the soft-delete pattern. + +### Auditing Base Classes + +While you can manually implement any of the interfaces defined above, it is suggested to inherit from the base classes defined here: + +* `CreationAuditedEntity` and `CreationAuditedAggregateRoot` implement the `ICreationAuditedObject` interface. +* `AuditedEntity` and `AuditedAggregateRoot` implement the `IAuditedObject` interface. +* `FullAuditedEntity` and `FullAuditedAggregateRoot` implement the `IFullAuditedObject` interface. + +All these base classes also have non-generic versions to take `AuditedEntity` and `FullAuditedAggregateRoot` to support the composite primary keys. + +All these base classes also have `...WithUser` pairs, like `FullAuditedAggregateRootWithUser` and`FullAuditedAggregateRootWithUser`. This makes possible to add a navigation property to your user entity. However, it is not a good practice to add navigation properties between aggregate roots, so this usage is not suggested (unless you are using an ORM, like EF Core, that well supports this scenario and you really need it - otherwise remember that this approach doesn't work for NoSQL databases like MongoDB where you must truly implement the aggregate pattern). + +## See Also + +* [Best practice guide to design the entities](Best-Practices/Entities.md) \ No newline at end of file diff --git a/docs/en/Entity-Framework-Core-MySQL.md b/docs/en/Entity-Framework-Core-MySQL.md new file mode 100644 index 0000000000..d1fa66e1a4 --- /dev/null +++ b/docs/en/Entity-Framework-Core-MySQL.md @@ -0,0 +1,58 @@ +# Switch to EF Core MySQL Provider + +This document explains how to switch to the **MySQL** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured. + +## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package + +`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.MySQL](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.MySQL) package. + +## Replace the Module Dependency + +Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreMySQLModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.MySQL;`). + +## UseMySQL() + +Find `UseSqlServer()` calls in your solution, replace with `UseMySQL()`. Check the following files: + +* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. +* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. + +> Depending on your solution structure, you may find more code files need to be changed. + +## Change the Connection Strings + +MySQL connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/mysql/ ) for details of MySQL connection string options. + +You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. + +## Change the Migrations DbContext + +MySQL DBMS has some slight differences than the SQL Server. Some module database mapping configuration (especially the field lengths) causes problems with MySQL. For example, some of the the [IdentityServer module](Modules/IdentityServer.md) tables has such problems and it provides an option to configure the fields based on your DBMS. + +The startup template contains a *YourProjectName*MigrationsDbContext which is responsible to maintain and migrate the database schema. This DbContext basically calls extension methods of the depended modules to configure their database tables. + +Open the *YourProjectName*MigrationsDbContext and change the `builder.ConfigureIdentityServer();` line as shown below: + +````csharp +builder.ConfigureIdentityServer(options => +{ + options.DatabaseProvider = EfCoreDatabaseProvider.MySql; +}); +```` + +Then `ConfigureIdentityServer()` method will set the field lengths to not exceed the MySQL limits. Refer to related module documentation if you have any problem while creating or executing the database migrations. + +## Re-Generate the Migrations + +The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. + +* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). + +This will create a database migration with all database objects (tables) configured. + +Run the `.DbMigrator` project to create the database and seed the initial data. + +## Run the Application + +It is ready. Just run the application and enjoy coding. \ No newline at end of file diff --git a/docs/en/Entity-Framework-Core-Other-DBMS.md b/docs/en/Entity-Framework-Core-Other-DBMS.md new file mode 100644 index 0000000000..854309d070 --- /dev/null +++ b/docs/en/Entity-Framework-Core-Other-DBMS.md @@ -0,0 +1,90 @@ +# Switch to another DBMS for Entity Framework Core + +**[The application startup template](Startup-Templates/Application.md)** comes with SQL Server provider pre-configured for the Entity Framework Core. Entity Framework Core supports [many other DBMSs](https://docs.microsoft.com/en-us/ef/core/providers/) and you can use any of them with your ABP based applications. + +ABP framework provides integration packages for some common DBMSs to make the configuration a bit easier (see the [entity framework core document](Entity-Framework-Core.md) for a list of available integration packages). However, you can configure your DBMS provider without these integration packages. + +While using the integration package is always recommended (it also makes standard for the depended version across different modules), you can do it manually if there is no integration package for your DBMS provider. + +This document explains how to switch to MySQL without using [the MySQL integration package](Entity-Framework-Core-MySQL.md). + +## Replace the SQL Server Dependency + +* Remove the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package dependency from the `.EntityFrameworkCore` project. +* Add the [Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/) NuGet package dependency to your `.EntityFrameworkCore` project. + +## Remove the Module Dependency + +Remove the `AbpEntityFrameworkCoreSqlServerModule` from the dependency list of your ***YourProjectName*EntityFrameworkCoreModule** class. + +## Change the UseSqlServer() Calls + +Find the following code part inside the *YourProjectName*EntityFrameworkCoreModule class: + +````csharp +Configure(options => +{ + options.UseSqlServer(); +}); +```` + +Replace it with the following code part: + +````csharp +Configure(options => +{ + options.Configure(ctx => + { + if (ctx.ExistingConnection != null) + { + ctx.DbContextOptions.UseMySql(ctx.ExistingConnection); + } + else + { + ctx.DbContextOptions.UseMySql(ctx.ConnectionString); + } + }); +}); +```` + +* `UseMySql` calls in this code is defined by the Pomelo.EntityFrameworkCore.MySql package and you can use its additional options if you need. +* This code first checks if there is an existing (active) connection to the same database in the current request and reuses it if possible. This allows to share a single transaction among different DbContext types. ABP handles the rest of the things. +* It uses `ctx.ConnectionString` and passes to the `UseMySql` if there is no active connection (which will cause to create a new database connection). Using the `ctx.ConnectionString` is important here. Don't pass a static connection string (or a connection string from a configuration). Because ABP [dynamically determines the correct connection string](Connection-Strings.md) in a multi-database or [multi-tenant](Multi-Tenancy.md) environment. + +## Change the Connection Strings + +MySQL connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/mysql/ ) for details of MySQL connection string options. + +You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. + +## Change the Migrations DbContext + +MySQL DBMS has some slight differences than the SQL Server. Some module database mapping configuration (especially the field lengths) causes problems with MySQL. For example, some of the the [IdentityServer module](Modules/IdentityServer.md) tables has such problems and it provides an option to configure the fields based on your DBMS. + +The startup template contains a *YourProjectName*MigrationsDbContext which is responsible to maintain and migrate the database schema. This DbContext basically calls extension methods of the depended modules to configure their database tables. + +Open the *YourProjectName*MigrationsDbContext and change the `builder.ConfigureIdentityServer();` line as shown below: + +````csharp +builder.ConfigureIdentityServer(options => +{ + options.DatabaseProvider = EfCoreDatabaseProvider.MySql; +}); +```` + +Then `ConfigureIdentityServer()` method will set the field lengths to not exceed the MySQL limits. Refer to related module documentation if you have any problem while creating or executing the database migrations. + +## Re-Generate the Migrations + +The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. + +* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). + +This will create a database migration with all database objects (tables) configured. + +Run the `.DbMigrator` project to create the database and seed the initial data. + +## Run the Application + +It is ready. Just run the application and enjoy coding. \ No newline at end of file diff --git a/docs/en/Entity-Framework-Core-PostgreSQL.md b/docs/en/Entity-Framework-Core-PostgreSQL.md new file mode 100644 index 0000000000..328ca4d416 --- /dev/null +++ b/docs/en/Entity-Framework-Core-PostgreSQL.md @@ -0,0 +1,41 @@ +# Switch to EF Core PostgreSQL Provider + +This document explains how to switch to the **PostgreSQL** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured. + +## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package + +`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql) package. + +## Replace the Module Dependency + +Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.PostgreSql;`). + +## UsePostgreSql() + +Find `UseSqlServer()` call in *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project and replace with `UsePostgreSql()`. + + +Find `UseSqlServer()` call in *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project and replace with `UseNpgsql()`. + +> Depending on your solution structure, you may find more `UseSqlServer()` calls that needs to be changed. + +## Change the Connection Strings + +PostgreSql connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/postgresql/ ) for details of PostgreSql connection string options. + +You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. + +## Re-Generate the Migrations + +The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. + +* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). + +This will create a database migration with all database objects (tables) configured. + +Run the `.DbMigrator` project to create the database and seed the initial data. + +## Run the Application + +It is ready. Just run the application and enjoy coding. diff --git a/docs/en/Entity-Framework-Core-SQLite.md b/docs/en/Entity-Framework-Core-SQLite.md new file mode 100644 index 0000000000..62a8ef815d --- /dev/null +++ b/docs/en/Entity-Framework-Core-SQLite.md @@ -0,0 +1,41 @@ +# Switch to EF Core SQLite Provider + +This document explains how to switch to the **SQLite** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured. + +## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package + +`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.Sqlite](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Sqlite) package. + +## Replace the Module Dependency + +Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreSqliteModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.Sqlite;`). + +## UseSqlite() + +Find `UseSqlServer()` calls in your solution, replace with `UseSqlite()`. Check the following files: + +* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. +* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project. + +> Depending on your solution structure, you may find more code files need to be changed. + +## Change the Connection Strings + +SQLite connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/sqlite/ ) for details of SQLite connection string options. + +You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure. + +## Re-Generate the Migrations + +The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails. + +* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution. +* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console). + +This will create a database migration with all database objects (tables) configured. + +Run the `.DbMigrator` project to create the database and seed the initial data. + +## Run the Application + +It is ready. Just run the application and enjoy coding. \ No newline at end of file diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index e608736bcd..9d29f58fd2 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -28,6 +28,19 @@ namespace MyCompany.MyProject > Note: Instead, you can directly download a [startup template](https://abp.io/Templates) with EF Core pre-installed. +### Database Management System Selection + +Entity Framework Core supports various database management systems ([see all](https://docs.microsoft.com/en-us/ef/core/providers/)). ABP framework and this document doesn't depend on any specific DBMS. + +If you are creating a reusable library, avoid to depend on a specific DBMS package. However, in a final application you eventually will select a DBMS. + +ABP framework provides integration packages for some common DBMSs to make the configuration a bit easier. [The startup templates](Startup-Templates/Index.md) come with **SQL Server (localdb) pre-configured**. See the following documents to learn how to configure for the other DBMS providers: + +* [MySQL](Entity-Framework-Core-MySQL.md) +* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md) +* [SQLite](Entity-Framework-Core-SQLite.md) +* [Others](Entity-Framework-Core-Other-DBMS.md) + ## Creating DbContext You can create your DbContext as you normally do. It should be derived from `AbpDbContext` as shown below: @@ -62,7 +75,7 @@ public class MyDbContext : AbpDbContext } ``` -If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string. +If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string (see [the connection strings document](Connection-Strings.md) for more information). ## Registering DbContext To Dependency Injection @@ -126,7 +139,8 @@ public class BookManager : DomainService { private readonly IRepository _bookRepository; - public BookManager(IRepository bookRepository) //inject default repository + //inject default repository to the constructor + public BookManager(IRepository bookRepository) { _bookRepository = bookRepository; } @@ -142,7 +156,8 @@ public class BookManager : DomainService Type = type }; - await _bookRepository.InsertAsync(book); //Use a standard repository method + //Use a standard repository method + await _bookRepository.InsertAsync(book); return book; } @@ -153,9 +168,9 @@ This sample uses `InsertAsync` method to insert a new entity to the database. ### Add Custom Repositories -Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods. +Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods. Assume that you want to delete all books by type. -Assume that you want to delete all books by type. It's suggested to define an interface for your custom repository: +It's suggested to define an interface for your custom repository: ````csharp public interface IBookRepository : IRepository @@ -187,21 +202,23 @@ public class BookRepository : EfCoreRepository, Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed. -#### Override Default Generic Repository +#### Override the Default Generic Repository Even if you create a custom repository, you can still inject the default generic repository (`IRepository` for this example). Default repository implementation will not use the class you have created. -If you want to replace default repository implementation with your custom repository, do it inside `AddAbpDbContext` options: +If you want to replace default repository implementation with your custom repository, do it inside the `AddAbpDbContext` options: ````csharp context.Services.AddAbpDbContext(options => { options.AddDefaultRepositories(); - options.AddRepository(); //Replaces IRepository + + //Replaces IRepository + options.AddRepository(); }); ```` -This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete an entity in a more efficient way: +This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete a specific entity in a more efficient way: ````csharp public override async Task DeleteAsync( @@ -215,7 +232,7 @@ public override async Task DeleteAsync( ### Access to the EF Core API -In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository). However, if you want to access the DbContext instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example: +In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository pattern). However, if you want to access the `DbContext` instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example: ````csharp public class BookService @@ -243,9 +260,9 @@ public class BookService #### Set Default Repository Classes -Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for default repository implementation. +Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for all the default repository implementations. -First, define your repository classes like that: +First, define your default repository classes like that: ```csharp public class MyRepositoryBase @@ -271,7 +288,7 @@ public class MyRepositoryBase First one is for [entities with composite keys](Entities.md), second one is for entities with single primary key. -It's suggested to inherit from the `EfCoreRepository` class and override methods if needed. Otherwise, you will have to implement all standard repository methods manually. +It's suggested to inherit from the `EfCoreRepository` class and override methods if needed. Otherwise, you will have to implement all the standard repository methods manually. Now, you can use `SetDefaultRepositoryClasses` option: @@ -282,6 +299,7 @@ context.Services.AddAbpDbContext(options => typeof(MyRepositoryBase<,>), typeof(MyRepositoryBase<>) ); + //... }); ``` @@ -316,7 +334,7 @@ public class BookRepository : EfCoreRepository, } ```` -One advantage of using interface for a DbContext is then it becomes replaceable by another implementation. +One advantage of using an interface for a DbContext is then it will be replaceable by another implementation. #### Replace Other DbContextes diff --git a/docs/en/FluentValidation.md b/docs/en/FluentValidation.md new file mode 100644 index 0000000000..c087f8a185 --- /dev/null +++ b/docs/en/FluentValidation.md @@ -0,0 +1,58 @@ +# FluentValidation Integration + +ABP [Validation](Validation.md) infrastructure is extensible. [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet package extends the validation system to work with the [FluentValidation](https://fluentvalidation.net/) library. + +## Installation + +It is suggested to use the [ABP CLI](CLI.md) to install this package. + +### Using the ABP CLI + +Open a command line window in the folder of the project (.csproj file) and type the following command: + +````bash +abp add-package Volo.Abp.FluentValidation +```` + +### Manual Installation + +If you want to manually install; + +1. Add the [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet package to your project: + + ```` + Install-Package Volo.Abp.FluentValidation + ```` + +2. Add the `AbpFluentValidationModule` to the dependency list of your module: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpFluentValidationModule) //Add the FluentValidation module + )] +public class YourModule : AbpModule +{ +} +```` + +## Using the FluentValidation + +Follow [the FluentValidation documentation](https://fluentvalidation.net/) to create validator classes. Example: + +````csharp +public class CreateUpdateBookDtoValidator : AbstractValidator +{ + public CreateUpdateBookDtoValidator() + { + RuleFor(x => x.Name).Length(3, 10); + RuleFor(x => x.Price).ExclusiveBetween(0.0f, 999.0f); + } +} +```` + +ABP will automatically find this class and associate with the `CreateUpdateBookDto` on object validation. + +## See Also + +* [Validation System](Validation.md) \ No newline at end of file diff --git a/docs/en/Logging.md b/docs/en/Logging.md new file mode 100644 index 0000000000..9b9c604bed --- /dev/null +++ b/docs/en/Logging.md @@ -0,0 +1,5 @@ +# Logging + +ABP Framework doesn't implement any logging infrastructure. It uses the [ASP.NET Core's logging system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging). + +> .NET Core's logging system is actually independent from the ASP.NET Core. It is usable in any type of application. \ No newline at end of file diff --git a/docs/en/Modules/Audit-Logging.md b/docs/en/Modules/Audit-Logging.md new file mode 100644 index 0000000000..922f99284b --- /dev/null +++ b/docs/en/Modules/Audit-Logging.md @@ -0,0 +1,7 @@ +# Audit Logging Module + +The Audit Logging Module basically implements the `IAuditingStore` to save the audit log objects to a database. + +> Audit Logging module is already installed and configured for [the startup templates](../Startup-Templates/Index.md). So, most of the times you don't need to manually add this module to your application. + +See [the audit logging system](../Audit-Logging.md) document for more about the audit logging. \ No newline at end of file diff --git a/docs/en/Modules/Blogging.md b/docs/en/Modules/Blogging.md new file mode 100644 index 0000000000..0d2ab35c21 --- /dev/null +++ b/docs/en/Modules/Blogging.md @@ -0,0 +1,3 @@ +# IdentityServer Module + +TODO \ No newline at end of file diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md index ac85978740..c42a3c2bcc 100644 --- a/docs/en/Modules/Docs.md +++ b/docs/en/Modules/Docs.md @@ -16,7 +16,7 @@ Docs module is an application module and does not offer any hosting solution. Yo When you use GitHub to store your docs, Docs Module supports versioning. If you have multiple versions for your docs, there will be a combo-box on the UI to switch between versions. If you choose file system to store your docs, it does not support multiple versions. -[The documents](https://abp.io/documents/) for ABP framework is also using this module. +[The documents](docs.abp.io) for ABP framework is also using this module. > Docs module follows the [module architecture best practices](../Best-Practices/Module-Architecture.md) guide. @@ -316,7 +316,7 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen - ExtraProperties: ```json - {"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"} + {"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"} ``` Note that `GitHubAccessToken` is masked with `***`. It's a private token that you must get it from GitHub. See https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/ @@ -328,7 +328,7 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table: ```mssql -INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}', N'/', N'master') +INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"}', N'/', N'master') ``` Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string. @@ -354,10 +354,10 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen - ExtraProperties: ```json - {"Path":"C:\\Github\\abp\\docs\\en"} + {"Path":"C:\\Github\\abp\\docs"} ``` - Note that `Path` must be replaced with your local docs directory. You can fetch the ABP Framework's documents from https://github.com/abpframework/abp/tree/master/docs/en and copy to the directory `C:\\Github\\abp\\docs\\en` to get it work. + Note that `Path` must be replaced with your local docs directory. You can fetch the ABP Framework's documents from https://github.com/abpframework/abp/tree/master/docs and copy to the directory `C:\\Github\\abp\\docs` to get it work. - MainWebsiteUrl: `/` @@ -366,11 +366,9 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table: ```mssql -INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs\\en"}', N'/', NULL) +INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL) ``` - - Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page. So far, we have created a new application from abp.io website and made it up and ready for Docs module. @@ -408,12 +406,105 @@ public class Person ``` ~~~ - - As an example you can see ABP Framework documentation: [https://github.com/abpframework/abp/blob/master/docs/en/](https://github.com/abpframework/abp/blob/master/docs/en/) +#### Conditional sections feature (Using Scriban) + +Docs module uses [Scriban]( ) for conditionally show or hide some parts of a document. In order to use that feature, you have to create a JSON file as **Parameter document** per every language. It will contain all the key-values, as well as their display names. + +For example, [en/docs-params.json](https://github.com/abpio/abp-commercial-docs/blob/master/en/docs-params.json): + +```json +{ + "parameters": [{ + "name": "UI", + "displayName": "UI", + "values": { + "MVC": "MVC / Razor Pages", + "NG": "Angular" + } + }, + { + "name": "DB", + "displayName": "Database", + "values": { + "EF": "Entity Framework Core", + "Mongo": "MongoDB" + } + }, + { + "name": "Tiered", + "displayName": "Tiered", + "values": { + "No": "Not Tiered", + "Yes": "Tiered" + } + }] +} +``` + +Since not every single document in your projects may not have sections or may not need all of those parameters, you have to declare which of those parameters will be used for sectioning the document, as a JSON block anywhere on the document. + +For example [Getting-Started.md](https://github.com/abpio/abp-commercial-docs/blob/master/en/getting-started.md): + +``` +..... + +​````json +//[doc-params] +{ + "UI": ["MVC","NG"], + "DB": ["EF", "Mongo"], + "Tiered": ["Yes", "No"] +} +​```` + +........ +``` + +This section will be automatically deleted during render. And f course, those key values must match with the ones in **Parameter document**. + +![Interface](../images/docs-section-ui.png) + +Now you can use **Scriban** syntax to create sections in your document. + +For example: + +```` +{{ if UI == "NG" }} + +* `-u` argument specifies the UI framework, `angular` in this case. + +{{ end }} + +{{ if DB == "Mongo" }} + +* `-d` argument specifies the database provider, `mongodb` in this case. + +{{ end }} + +{{ if Tiered == "Yes" }} + +* `--tiered` argument is used to create N-tiered solution where authentication server, UI and API layers are physically separated. + +{{ end }} + +```` + +You can also use variables in a text, adding **_Value** postfix to its key: + +```` +This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. +```` + +Also, **Document_Language_Code** and **Document_Version** keys are pre-defined if you want to get the language code or the version of the current document (This may be useful for creating links that redirects to another documentation system in another domain). + +------ + +**IMPORTANT NOTICE**: Scriban uses "{{" and "}}" for syntax. Therefore, you must use escape blocks if you are going to use those in your document (an Angular document, for example). See [Scriban docs]( ) for more information. + ### 8- Creating the Navigation Document Navigation document is the main menu of the documents page. It is located on the left side of the page. It is a `JSON` file. Take a look at the below sample navigation document to understand the structure. diff --git a/docs/en/Modules/IdentityServer.md b/docs/en/Modules/IdentityServer.md new file mode 100644 index 0000000000..0d2ab35c21 --- /dev/null +++ b/docs/en/Modules/IdentityServer.md @@ -0,0 +1,3 @@ +# IdentityServer Module + +TODO \ No newline at end of file diff --git a/docs/en/Modules/Index.md b/docs/en/Modules/Index.md index 9d1c1d301f..812f22e8dd 100644 --- a/docs/en/Modules/Index.md +++ b/docs/en/Modules/Index.md @@ -11,16 +11,20 @@ There are **two types of modules.** They don't have any structural difference bu There are some **free and open source** application modules developed and maintained by the ABP community: -* **Account**: Used to make user login/register to the application. -* **Audit Logging**: Used to persist audit logs to a database. -* **Background Jobs**: Used to persist background jobs when using default background job manager. -* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://abp.io/blog/abp/) already using this module. +* **Account**: Provides UI for the account management and allows user to login/register to the application. +* [**Audit Logging**](Audit-Logging.md): Persists audit logs to a database. +* **Background Jobs**: Persist background jobs when using the default background job manager. +* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://blog.abp.io/) already using this module. * [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://docs.abp.io) already using this module. -* **Identity**: Used to manage roles, users and their permissions. -* **Identity Server**: Integrates to IdentityServer4. +* **Identity**: Manages roles, users and their permissions, based on the Microsoft Identity library. +* **IdentityServer**: Integrates to IdentityServer4. * **Permission Management**: Used to persist permissions. * **[Setting Management](Setting-Management.md)**: Used to persist and manage the [settings](../Settings.md). -* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application. -* **Users**: Used to abstract users, so other modules can depend on this instead of the Identity module. +* **Tenant Management**: Manages tenants for a [multi-tenant](../Multi-Tenancy.md) application. +* **Users**: Abstract users, so other modules can depend on this module instead of the Identity module. -Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules. +See [the GitHub repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules. + +## Commercial Application Modules + +[ABP Commercial](https://commercial.abp.io/) license provides additional pre-built application modules on top of the ABP framework. See the [module list](https://commercial.abp.io/modules) provided by the ABP Commercial. \ No newline at end of file diff --git a/docs/en/Modules/Setting-Management.md b/docs/en/Modules/Setting-Management.md index 39e8f8a0df..134e24aed2 100644 --- a/docs/en/Modules/Setting-Management.md +++ b/docs/en/Modules/Setting-Management.md @@ -67,6 +67,8 @@ namespace Demo So, you can get or set a setting value for different setting value providers (Default, Global, User, Tenant... etc). +> Use the `ISettingProvider` instead of the `ISettingManager` if you only need to read the setting values, because it implements caching and supports all deployment scenarios. You can use the `ISettingManager` if you are creating a setting management UI. + ### Setting Cache Setting values are cached using the [distributed cache](../Caching.md) system. Always use the `ISettingManager` to change the setting values which manages the cache for you. @@ -76,7 +78,7 @@ Setting values are cached using the [distributed cache](../Caching.md) system. A Setting Management module is extensible, just like the [setting system](../Settings.md). You can extend it by defining setting management providers. There are 5 pre-built setting management providers registered by the order below: * `DefaultValueSettingManagementProvider`: Gets the value from the default value of the setting definition. It can not set the default value since default values are hard-coded on the setting definition. -* `ConfigurationSettingManagementProvider`: Gets the value from the [IConfiguration service](Configuration.md). It can not set the configuration value because it is not possible to change the configuration values on runtime. +* `ConfigurationSettingManagementProvider`: Gets the value from the [IConfiguration service](../Configuration.md). It can not set the configuration value because it is not possible to change the configuration values on runtime. * `GlobalSettingManagementProvider`: Gets or sets the global (system-wide) value for a setting. * `TenantSettingManagementProvider`: Gets or sets the setting value for a tenant. * `UserSettingManagementProvider`: Gets the setting value for a user. diff --git a/docs/en/Options.md b/docs/en/Options.md index cead1aea61..20168bdbe3 100644 --- a/docs/en/Options.md +++ b/docs/en/Options.md @@ -1,4 +1,118 @@ # Options -TODO! +Microsoft has introduced [the options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) that is used to configure a group of settings used by the framework services. This pattern is implemented by the [Microsoft.Extensions.Options](https://www.nuget.org/packages/Microsoft.Extensions.Options) NuGet package, so it is usable by any type of applications in addition to ASP.NET Core based applications. + +ABP framework follows this option pattern and defines options classes to configure the framework and the modules (they are explained in the documents of the related feature). + +Since [the Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) explains the pattern in detail, no reason to repeat all. However, ABP adds a few more features and they will be explained here. + +## Configure Options + +You typically configure options in the `ConfigureServices` of the `Startup` class. However, since ABP framework provides a modular infrastructure, you configure options in the `ConfigureServices` of your [module](Module-Development-Basics.md). Example: + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + context.Services.Configure(options => + { + options.IsEnabled = false; + }); +} +```` + +* `AbpAuditingOptions` is a simple class defines some properties like `IsEnabled` used here. +* `AbpModule` base class defines `Configure` method to make the code simpler. So, instead of `context.Services.Configure<...>`, you can directly use the `Configure<...>` shortcut method. + +If you are developing a reusable module, you may need to define an options class to allow developers to configure your module. In this case, define a plain options class as shown below: + +````csharp +public class MyOptions +{ + public int Value1 { get; set; } + public bool Value2 { get; set; } +} +```` + +Then developers can configure your options just like the `AbpAuditingOptions` example above: + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + Configure(options => + { + options.Value1 = 42; + options.Value2 = true; + }); +} +```` + +* In this example, used the shortcut `Configure<...>` method. + +### Get the Option Value + +Whenever you need to get the value of an option, [inject](Dependency-Injection.md) the `IOptions` service into your class and use its `.Value` property. Example: + +````csharp +public class MyService : ITransientDependency +{ + private readonly MyOptions _options; + + public MyService(IOptions options) + { + _options = options.Value; //Notice the options.Value usage! + } + + public void DoIt() + { + var v1 = _options.Value1; + var v2 = _options.Value2; + } +} +```` + +Read [the Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) for all details of the options pattern. + +## Pre Configure + +One restriction of the options pattern is that you can only resolve (inject) the `IOptions` and get the option values when the dependency injection configuration completes (that means the `ConfigureServices` methods of all modules complete). + +If you are developing a module, you may need to allow developers to set some options and use these options in the dependency injection registration phase. You may need to configure other services or change the dependency injection registration code based on these option values. + +For such cases, ABP introduces the `PreConfigure` and the `ExecutePreConfiguredActions` extension methods for the `IServiceCollection`. The pattern works as explained below. + +1. Define a plan option class in your module. Example: + +````csharp +public class MyPreOptions +{ + public bool MyValue { get; set; } +} +```` + +Then any [module class](Module-Development-Basics.md) depends on your module can use the `PreConfigure` method in its `PreConfigureServices` method. Example: + +````csharp +public override void PreConfigureServices(ServiceConfigurationContext context) +{ + PreConfigure(options => + { + options.MyValue = true; + }); +} +```` + +> Multiple modules can pre-configure the options and override the option values based on their dependency order. + +Finally, your module can execute the `ExecutePreConfiguredActions` method in its `ConfigureServices` method to get the configured option values. Example: + +````csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + var options = context.Services.ExecutePreConfiguredActions(); + if (options.MyValue) + { + //... + } +} +```` diff --git a/docs/en/Settings.md b/docs/en/Settings.md index 35c5e2112f..32761ff201 100644 --- a/docs/en/Settings.md +++ b/docs/en/Settings.md @@ -40,6 +40,33 @@ ABP automatically discovers this class and registers the setting definitions. * **Providers**: Can be used to restrict providers available for a particular setting (see the setting value providers section for more). * **Properties**: A name/value collection to set custom properties about this setting those can be used later in the application code. +### Change Setting Definitions of a Depended Module + +In some cases, you may want to change some properties of a settings defined in some other module that your application/module depends on. A setting definition provider can query and update setting definitions. + +The following example gets a setting defined by the [Volo.Abp.Emailing](Emailing.md) package and changes its properties: + +````csharp +public class MySettingDefinitionProvider : SettingDefinitionProvider +{ + public override void Define(ISettingDefinitionContext context) + { + var smtpHost = context.GetOrNull("Abp.Mailing.Smtp.Host"); + if (smtpHost != null) + { + smtpHost.DefaultValue = "mail.mydomain.com"; + smtpHost.DisplayName = + new LocalizableString( + typeof(MyLocalizationResource), + "SmtpServer_DisplayName" + ); + } + } +} +```` + +> Using constants for the setting names is a good practice and ABP packages do it. `Abp.Mailing.Smtp.Host` setting name is a constant defined by the `EmailSettingNames` class (in the `Volo.Abp.Emailing` namespace). + ## Reading Setting Values ### ISettingProvider @@ -118,6 +145,30 @@ There are 5 pre-built setting value providers registered by the order below: Global, Tenant and User setting value providers use the `ISettingStore` to read the value from the data source (see the section below). +### Setting Values in the Application Configuration + +As mentioned in the previous section, `ConfigurationSettingValueProvider` reads the settings from the `IConfiguration` service, which can read values from the `appsettings.json` by default. So, the easiest way to configure setting values to define them in the `appsettings.json` file. + +For example, you can configure [IEmailSender](Emailing.md) settings as shown below: + +````json +{ + "Settings": { + "Abp.Mailing.DefaultFromAddress": "noreply@mydomain.com", + "Abp.Mailing.DefaultFromDisplayName": "My Application", + "Abp.Mailing.Smtp.Host": "mail.mydomain.com", + "Abp.Mailing.Smtp.Port": "547", + "Abp.Mailing.Smtp.UserName": "myusername", + "Abp.Mailing.Smtp.Password": "mySecretPassW00rd", + "Abp.Mailing.Smtp.EnableSsl": "True" + } +} +```` + +Setting values should be configured under the `Settings` section as like in this example. + +> `IConfiguration` is an .NET Core service and it can read values not only from the `appsettings.json`, but also from the environment, user secrets... etc. See [Microsoft's documentation]( https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/ ) for more. + ### Custom Setting Value Providers If you need to extend the setting system, you can define a class derived from the `SettingValueProvider` class. Example: @@ -165,7 +216,7 @@ This example adds it as the last item, so it will be the first value provider us ### ISettingStore -While a setting value provider is free to use any source to get the setting value, the`ISettingStore` service is the default source of the setting values. Global, Tenant and User setting value providers use it. +While a setting value provider is free to use any source to get the setting value, the `ISettingStore` service is the default source of the setting values. Global, Tenant and User setting value providers use it. ## ISettingEncryptionService diff --git a/docs/en/Tutorials/Angular/Part-I.md b/docs/en/Tutorials/Angular/Part-I.md index 46368eeecb..6d5f91bce7 100644 --- a/docs/en/Tutorials/Angular/Part-I.md +++ b/docs/en/Tutorials/Angular/Part-I.md @@ -343,7 +343,7 @@ Run `yarn start`, wait Angular to run the application and open `http://localhost Open the `app-routing.module.ts` and replace `books` as shown below: ```js -import { ApplicationLayoutComponent } from '@abp/ng.theme.basic';- +import { ApplicationLayoutComponent } from '@abp/ng.theme.basic'; //... { diff --git a/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md index d113442af9..669bd8c9ec 100644 --- a/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/en/Tutorials/AspNetCore-Mvc/Part-I.md @@ -345,7 +345,7 @@ Open the `Index.cshtml` and change the content as shown below: ```` * This code changes the default inheritance of the Razor View Page Model so it **inherits** from the `BookStorePage` class (instead of `PageModel`). The `BookStorePage` class which comes with the startup template and provides some shared properties/methods used by all pages. -* Ensure that the `IndexModel` (*Index.cshtml.cs)* has the `Acme.BookStore.Pages.Books` namespace, or update it in the `Index.cshtml`. +* Ensure that the `IndexModel` (*Index.cshtml.cs)* has the `Acme.BookStore.Web.Pages.Books` namespace, or update it in the `Index.cshtml`. #### Add Books Page to the Main Menu @@ -422,7 +422,7 @@ Change the `Pages/Books/Index.cshtml` as following: ```` * `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to standard `script` tag. It handles **minification** and **versioning** for example. See the [bundling & minification document](../../AspNetCore/Bundling-Minification.md) for details. -* `abp-card` and `abp-table` are **tag helpers** for Twitter Bootstrap's [card component](http://getbootstrap.com/docs/4.1/components/card/). There are many tag helpers in ABP to easily use most of the [bootstrap](https://getbootstrap.com/) components. You can also use regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help of the intellisense and compile time type checking. See the [tag helpers document](../../AspNetCore/Tag-Helpers.md). +* `abp-card` and `abp-table` are **tag helpers** for Twitter Bootstrap's [card component](http://getbootstrap.com/docs/4.1/components/card/). There are many tag helpers in ABP to easily use most of the [bootstrap](https://getbootstrap.com/) components. You can also use regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help of the intellisense and compile time type checking. See the [tag helpers document](../../AspNetCore/Tag-Helpers/Index.md). * You can **localize** the column names in the localization file as you did for the menu items above. ##### Add a Script File diff --git a/docs/en/Tutorials/AspNetCore-Mvc/Part-II.md b/docs/en/Tutorials/AspNetCore-Mvc/Part-II.md index 1e3ec1f539..505de55adc 100644 --- a/docs/en/Tutorials/AspNetCore-Mvc/Part-II.md +++ b/docs/en/Tutorials/AspNetCore-Mvc/Part-II.md @@ -421,7 +421,8 @@ $(function () { Open the `en.json` in the `Acme.BookStore.Domain.Shared` project and add the following line: ````json -"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?" +"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?", +"SuccessfullyDeleted": "Successfully deleted" ```` Run the application and try to delete a book. diff --git a/docs/en/Validation.md b/docs/en/Validation.md index a4b829c97d..15c3f13412 100644 --- a/docs/en/Validation.md +++ b/docs/en/Validation.md @@ -1,3 +1,158 @@ -## Validation +# Validation -TODO \ No newline at end of file +Validation system is used to validate the user input or client request for a particular controller action or service method. + +ABP is compatible with the ASP.NET Core Model Validation system and everything written in [its documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation) is already valid for ABP based applications. So, this document mostly focuses on the ABP features rather than repeating the Microsoft documentation. + +In addition, ABP adds the following benefits: + +* Defines `IValidationEnabled` to add automatic validation to an arbitrary class. Since all the [application services](Application-Services.md) inherently implements it, they are also validated automatically. +* Automatically localize the validation errors for the data annotation attributes. +* Provides extensible services to validate a method call or an object state. +* Provides [FluentValidation](https://fluentvalidation.net/) integration. + +## Validating DTOs + +This section briefly introduces the validation system. For details, see the [ASP.NET Core validation documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation). + +### Data Annotation Attributes + +Using data annotations is a simple way to implement the formal validation for a [DTO](Data-Transfer-Objects.md) in a declarative way. Example: + +````csharp +public class CreateBookDto +{ + [Required] + [StringLength(100)] + public string Name { get; set; } + + [Required] + [StringLength(1000)] + public string Description { get; set; } + + [Range(0, 999.99)] + public decimal Price { get; set; } +} +```` + +When you use this class as a parameter to an [application service](Application-Services.md) or a controller, it is automatically validated and a localized validation exception is thrown ([and handled](Exception-Handling.md) by the ABP framework). + +### IValidatableObject + +`IValidatableObject` can be implemented by a DTO to perform custom validation logic. `CreateBookDto` in the following example implements this interface and checks if the `Name` is equals to the `Description` and returns a validation error in this case. + +````csharp +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Acme.BookStore +{ + public class CreateBookDto : IValidatableObject + { + [Required] + [StringLength(100)] + public string Name { get; set; } + + [Required] + [StringLength(1000)] + public string Description { get; set; } + + [Range(0, 999.99)] + public decimal Price { get; set; } + + public IEnumerable Validate( + ValidationContext validationContext) + { + if (Name == Description) + { + yield return new ValidationResult( + "Name and Description can not be the same!", + new[] { "Name", "Description" } + ); + } + } + } +} +```` + +#### Resolving a Service + +If you need to resolve a service from the [dependency injection system](Dependency-Injection.md), you can use the `ValidationContext` object. Example: + +````csharp +var myService = validationContext.GetRequiredService(); +```` + +> While resolving services in the `Validate` method allows any possibility, it is not a good practice to implement your domain validation logic in DTOs. Keep DTOs simple. Their purpose is to transfer data (DTO: Data Transfer Object). + +## Validation Infrastructure + +This section explains a few additional services provided by the ABP framework. + +### IValidationEnabled Interface + +`IValidationEnabled` is an empty marker interface that can be implemented by any class (registered to and resolved from the [DI](Dependency-Injection.md)) to let the ABP framework perform the validation system for the methods of the class. Example: + +````csharp +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Validation; + +namespace Acme.BookStore +{ + public class MyService : ITransientDependency, IValidationEnabled + { + public virtual async Task DoItAsync(MyInput input) + { + //... + } + } +} +```` + +> ABP framework uses the [dynamic proxying / interception](Dynamic-Proxying-Interceptors.md) system to perform the validation. In order to make it working, your method should be **virtual** or your service should be injected and used over an **interface** (like `IMyService`). + +### AbpValidationException + +Once ABP determines a validation error, it throws an exception of type `AbpValidationException`. Your application code can throw `AbpValidationException`, but most of the times it is not needed. + +* `ValidationErrors` property of the `AbpValidationException` contains the validation error list. +* Log level of the `AbpValidationException` is set to `Warning`. It logs all the validation errors to the [logging system](Logging.md). +* `AbpValidationException` is automatically caught by the ABP framework and converted to a usable error into with HTTP 400 status code. See the [exception handling](Exception-Handling.md) document for more. + +## Advanced Topics + +### IObjectValidator + +In addition to the automatic validation, you may want to manually validate an object. In this case, [inject](Dependency-Injection.md) and use the `IObjectValidator` service: + +* `Validate` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state. +* `GetErrors` doesn't throw an exception, but only returns the validation errors. + +`IObjectValidator` is implemented by the `ObjectValidator` by default. `ObjectValidator` is extensible; you can implement `IObjectValidationContributor` interface to contribute a custom logic. Example: + +````csharp +public class MyObjectValidationContributor + : IObjectValidationContributor, ITransientDependency +{ + public void AddErrors(ObjectValidationContext context) + { + //Get the validating object + var obj = context.ValidatingObject; + + //Add the validation errors if available + context.Errors.Add(...); + } +} +```` + +* Remember to register your class to the [DI](Dependency-Injection.md) (implementing `ITransientDependency` does it just like in this example) +* ABP will automatically discover your class and use on any type of object validation (including automatic method call validation). + +### IMethodInvocationValidator + +`IMethodInvocationValidator` is used to validate a method call. It internally uses the `IObjectValidator` to validate objects passes to the method call. You normally don't need to this service since it is automatically used by the framework, but you may want to reuse or replace it on your application in rare cases. + +## FluentValidation Integration + +Volo.Abp.FluentValidation package integrates the FluentValidation library to the validation system (by implementing the `IObjectValidationContributor`). See the [FluentValidation Integration document](FluentValidation.md) for more. \ No newline at end of file diff --git a/docs/en/Virtual-File-System.md b/docs/en/Virtual-File-System.md index d13bbf491b..f2f85049bd 100644 --- a/docs/en/Virtual-File-System.md +++ b/docs/en/Virtual-File-System.md @@ -38,7 +38,8 @@ If you want to add multiple files, this can be tedious. Alternatively, you can d ````C# - + + ```` diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 863290126a..6657ac629a 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -60,6 +60,10 @@ "text": "Configuration", "path": "Configuration.md" }, + { + "text": "Options", + "path": "Options.md" + }, { "text": "Dependency Injection", "path": "Dependency-Injection.md", @@ -83,7 +87,14 @@ "path": "Exception-Handling.md" }, { - "text": "Validation" + "text": "Validation", + "path": "Validation.md", + "items": [ + { + "text": "FluentValidation Integration", + "path": "FluentValidation.md" + } + ] }, { "text": "Authorization", @@ -94,7 +105,8 @@ "path": "Caching.md" }, { - "text": "Auditing" + "text": "Audit Logging", + "path": "Audit-Logging.md" }, { "text": "Settings", @@ -257,25 +269,46 @@ }, { "text": "Data Access", - "path": "Data-Access.md", + "path": "Data-Access.md", "items": [ { - "text": "Entity Framework Core Integration", - "path": "Entity-Framework-Core.md", - "items": [ + "text": "Connection Strings", + "path": "Connection-Strings.md" + }, + { + "text": "Database Providers", + "items": [ + { + "text": "Entity Framework Core", + "path": "Entity-Framework-Core.md", + "items": [ + { + "text": "Switch to MySQL", + "path": "Entity-Framework-Core-MySQL.md" + }, + { + "text": "Switch to PostgreSQL", + "path": "Entity-Framework-Core-PostgreSQL.md" + }, + { + "text": "Switch to SQLite", + "path": "Entity-Framework-Core-SQLite.md" + }, + { + "text": "Switch to another DBMS", + "path": "Entity-Framework-Core-Other-DBMS.md" + } + ] + }, + { + "text": "MongoDB", + "path": "MongoDB.md" + }, { - "text": "PostgreSQL Integration", - "path": "Best-Practices/PostgreSQL-Integration.md" + "text": "Dapper", + "path": "Dapper.md" } ] - }, - { - "text": "MongoDB Integration", - "path": "MongoDB.md" - }, - { - "text": "Dapper Integration", - "path": "Dapper.md" } ] }, diff --git a/docs/en/images/auditlog-object-diagram.png b/docs/en/images/auditlog-object-diagram.png new file mode 100644 index 0000000000..a7e86a2bb2 Binary files /dev/null and b/docs/en/images/auditlog-object-diagram.png differ diff --git a/docs/en/images/docs-section-ui.png b/docs/en/images/docs-section-ui.png new file mode 100644 index 0000000000..7856454e5d Binary files /dev/null and b/docs/en/images/docs-section-ui.png differ diff --git a/docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md b/docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md index 7e6471d3ed..ef2c28f1f1 100644 --- a/docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md +++ b/docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md @@ -454,7 +454,8 @@ $(function () { Abra o `en.json`no `Acme.BookStore.Domain.Shared`projeto e adicione a seguinte linha: ```json -"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?" +"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?", +"SuccessfullyDeleted": "Successfully deleted" ``` diff --git a/docs/pt-BR/docs-nav.json b/docs/pt-BR/docs-nav.json index 90b29626b8..a189b83c09 100644 --- a/docs/pt-BR/docs-nav.json +++ b/docs/pt-BR/docs-nav.json @@ -249,7 +249,7 @@ "items": [ { "text": "Integração do PostgreSQL", - "path": "Best-Practices/PostgreSQL-Integration.md" + "path": "Entity-Framework-Core-PostgreSQL.md" } ] }, diff --git a/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md b/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md index 3dd687be53..4d98c6cbc5 100644 --- a/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md +++ b/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md @@ -173,12 +173,12 @@ public static IQueryable IncludeDetails( * **推荐** 推荐在仓储其他方法中使用 `IncludeDetails` 扩展方法, 就像上面的示例代码一样(参阅 FindByNormalizedUserNameAsync). -- **推荐** 覆盖具有 **子集合** 的聚合根仓储中的`IncludeDetails` 方法. 例如: +- **推荐** 覆盖具有 **子集合** 的聚合根仓储中的 `WithDetails` 方法. 例如: ````C# -protected override IQueryable IncludeDetails(IQueryable queryable) +public override IQueryable WithDetails() { - return queryable.IncludeDetails(); //uses the extension method defined above + return GetQueryable().IncludeDetails(); // Uses the extension method defined above } ```` @@ -205,4 +205,3 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule } } ```` - diff --git a/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/Post.md b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/Post.md new file mode 100644 index 0000000000..b996bf23d3 --- /dev/null +++ b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/Post.md @@ -0,0 +1,164 @@ +# ABP框架v2.0 和 ABP商业版 + +ABP框架2.0版已经在本周公布.这篇文章解释了为什么我们发布了一个**抢先主版本**,和2.0版本中的变化. + +除了v2.0版本,我们很高兴地宣布**ABP商业版**,这是建立在开源ABP框架的之上的一套专业的模块,工具,主题和服务. + +## ABP框架V2.0 + +### 为什么2.0,而不是1.2? + +本来在[V1.1.2](https://github.com/abpframework/abp/releases/tag/1.1.2)发布后计划发布1.2版.然而,[有报告](https://github.com/abpframework/abp/issues/2026)称1.x版在Linux上有一些**性能**和**稳定性**问题,尤其是当应用程序部署在**低配CPU和内存**的**Linux**容器上. + +我们深入研究了这一问题,并已查明问题的根本原因与**拦截`async`方法**的实现有关.此外,也有一些 **`async`套`sync`** 的用法影响了线程池的优化. + +最后,在**社区**在大力协助下我们**解决了所有的问题**.但是,我们也有一些重要的**设计决策**导致了一些**破坏性变更**,因为[语义版本](https://semver.org/),我们不得不改变框架的主版号. + +大多数的应用程序不会受到[破坏性变更](https://github.com/abpframework/abp/releases)的影响,或者只需要做一些微小的修改. + +### 破坏性变更 + +#### 删除了一些同步的API + +一些拦截器需要使用`async`的API.当他们拦截`sync`方法时,他们需要调用`async`套`sync`.这最终导致了`async`套`sync`的问题.这就是为什么我们[删除了一些同步的API](https://github.com/abpframework/abp/pull/2464). + +当你需要**在`async`方法中调用`sync`方法**时, **`async`套`sync`** 这种模式是`C#`一个经典问题.虽然有一些解决方法,但是都有相应的**缺点**,并建议**不要写**这样的代码.你可以在网上找到关于这一话题的许多文档. + +为了避免这个问题,我们已经移除: + +- `sync`[仓储](https://docs.abp.io/en/abp/latest/Repositories)方法 (如`insert`, `update`, 等...), +- `sync`[工作单元](https://docs.abp.io/en/abp/latest/Unit-Of-Work)API, +- `sync`[后台作业](https://docs.abp.io/en/abp/latest/Background-Jobs)API, +- `sync`[审计日志](https://docs.abp.io/en/abp/latest/Audit-Logging)API, + - 其他一些很少使用的`sync`API. + +如果你遇到了编译错误,只需使用这些API的`async`版本. + +#### 始终async! + +从v2.0开始,ABP框架假设你以`async`方式编写你的应用程序代码.否则,一些框架的功能可能无法正常工作. + +建议你的所有[应用服务](https://docs.abp.io/en/abp/latest/Application-Services), [仓储方法](https://docs.abp.io/en/abp/latest/Repositories), 控制器动作(ontroller actions), 页面处理器(page handlers)都是`async`. + +即使你的应用服务方法并不需要是`async`,也将其设置为`async`,因为拦截器需要执行`async`操作(授权,工作单元等).你可以在不调用`async`的方法中返回`Task.Completed`. + +示例: + +````csharp +public Task GetValueAsync() +{ + //这个方法没有任何async调用 + return Task.CompletedTask(42); +} +```` + +上述例子通常并不需要是`async`因为它不执行`async`调用.然而,将它设置为`async`,这样可以帮助ABP框架运行拦截器时避免出现`async`套sync的调用. + +此规则不强制你写的每一个方法都是`async`.这样并不好而且很乏味.只在拦截的服务上需要(特别是[应用服务](https://docs.abp.io/en/abp/latest/Application-Services)和[仓库方法](https://docs.abp.io/en/abp/latest/Repositories)) + +#### 其他破坏性变更 + +查看[发行说明](https://github.com/abpframework/abp/releases/tag/2.0.0)中的破坏性变更.他们中的大多数都不会影响你的应用程序代码. + +### 新功能 + +本次发布还包含一些新的功能和一堆改进: + +- [#2597](https://github.com/abpframework/abp/pull/2597) 新的`Volo.Abp.AspNetCore.Serilog`包. +- [#2526](https://github.com/abpframework/abp/issues/2526) `C#`客户端代理的客户端验证. +- [#2374](https://github.com/abpframework/abp/issues/2374) `async`后台作业. +- [#265](https://github.com/abpframework/abp/issues/265) 管理应用程序关闭. +- [#2472](https://github.com/abpframework/abp/issues/2472) `IdentityServer`模块实现`DeviceFlowCodes`和`TokenCleanupService`. + +功能,改进和BUG修复的完整列表, 请查看[发布说明](https://github.com/abpframework/abp/releases/tag/2.0.0). + +### 文档 + +随着v2.0的发布,我们也完成了一些缺少的文档.在接下来的几周内,我们将主要关注文档和教程. + +## ABP商业版 + +[ABP商业版](https://commercial.abp.io/)是建立在开源ABP框架之上的一套专业的**模块,工具,主题和服务**. + + - 除了ABP框架免费和[开源模块](https://docs.abp.io/en/abp/latest/Modules/Index)之外, 提供[专业模块](https://commercial.abp.io/modules). +- 包含一个漂亮的[UI主题](https://commercial.abp.io/themes), 具有5种不同的样式. +- 提供[ABP套件](https://commercial.abp.io/tools/suite); 一个让开发更具有生产力的工具. 通过配置实体属性, 它可以在几秒内创建全栈的CRUD页面. 更多的功能陆续开发中. +- 为企业提供[高级支持](ttps://commercial.abp.io/support). + +除了这些标准的功能,我们会将提供定制服务.更多细节请参见[commercial.abp.io](https://commercial.abp.io/)网站. + +### ABP框架 vs ABP商业版 + +ABP商业版**不是付费版本**的ABP框架.可以把它当作为专业公司提供的**附加套餐**.你可以用它来节省时间和更快地开发产品. + +ABP框架将永远是**开源免费**的! + +一个原则是,我们创建的主要基础设施作为开源产品, 然后销售额外的预制应用程序功能,主题和工具.类似于[ASP.NET Boilerplate](https://aspnetboilerplate.com/)和[ASP.NET Zero](https://aspnetzero.com/)产品. + +购买商业版许可极大地节省你的时间和精力,你可以专注于自己的业务,此外也可获得专门的和优先的支持.同时,你也在支持ABP核心团队,因为我们花了大部分时间来开发,维护和支持开源的ABP框架. + +有了ABP商业版,ABP现在变为一个平台.我们称之为**ABP.IO平台**, 其中包括开源ABP框架和ABP商业版. + +### 演示 + +如果你想知道ABP商业版应用程序的启动模板是什么样,你可以很容易地[创建一个演示](https://commercial.abp.io/demo),并看到它的实际效果.该演示包括所有的预制模块和主题. + +下面是一张IdentityServer管理模块UI的截图: + +![abp-commercial-demo](abp-commercial-demo.png) + +这是一张来自使用material设计风格主题的演示应用程序的截图: + +![lepton-theme-material](lepton-theme-material.png) + +### 价格 + +你可以创建**无限个工程/产品**, 销售给**无限个客户**, 部署在**无限台服务器上**, 不受任何限制. 定价主要是基于**开发人员个数**,**支持等级**和**源代码**需求上.有三个标准包; + +- **团队许可**: 包括所有的模块,主题和工具.允许最多3个开发者开发产品.可购买额外的开发者许可. +- **商业许可**: 允许下载所有的模块和主题的源代码.此外,默认包含了5个开发者许可.可购买额外的开发者许可. +- **企业许可**: 在商业许可上, 提供无限的专属支持. + +请查看[价格页面](https://commercial.abp.io/pricing)了解详细信息.除了标准包以外,我们也提供定制服务和定制许可.如有任何问题,请[联系我们](https://commercial.abp.io/contact). + +#### 许可比较 + +许可价格是根据开发者数量,支持等级和源代码访问而变化的. + +##### 源代码 + +团队许可证不包括预制模块和主题的源代码.以**NuGet和NPM包**的方式使用所有这些模块.通过这种方式,你可以很容易地通过更新包的依赖得到**新功能和bug修复**仅.但是不能访问其源代码.所以不能嵌入模块的源代码到你的应用程序里,和随意修改源代码. + +预制模块提供一定等级的**定制**和**扩展**,并允许你覆盖服务,UI部分等.我们正在努力使他们更加可定制和可扩展.如果你无需在预制模块中做很大修改的话,团队许可是你理想的选择,因为它更便宜,并且可轻松获得新的功能和bug修复. + +商业和企业许可允许你在需要时**下载任何模块和主题的源代码**.它们使用与团队许可相同的启动模板,所以所有的模块都默认使用`NuGet`和`NPM`包.但是,在需要的情况下,你可以从一个模块中删除包的依赖,并嵌入它的源代码到你自己的解决方案中,然后完全定制它.在这种情况下,当一个新版本可用时, 升级模块将不会那么容易.当然, 你不必升级!但是,如果你愿意,你也可以使用一些合并工具或Git的分支系统来做到这一点. + +#### 许可周期 + +ABP商业版许可是**永久的**,这意味着你可以**永远使用**它继续开发应用程序. + +但是,下面的服务周期为一年: + +- 高级**支持**一年后结束.你可以继续得到社区支持. +- 一年后将不会得到模块和主题的**更新**.你可以继续使用最后获得的版本.甚至可以在主版本内得到BUG修复和改进. +- 你可使用**ABP套件**一年. + +如果想继续获得这些好处,可延长许可期限.续订价格比正常价格低20%. + +## NDC London 2020 + +与[去年](https://medium.com/volosoft/impressions-of-ndc-london-2019-f8f391bb7a9c)一样, 我们是著名的软件开发会议[NDC London](https://ndc-london.com/)的合作伙伴! 去年, 我们开展了[ASP.NET Boilerplate](https://aspnetboilerplate.com/)和[ASP.NET Zero](https://aspnetzero.com/)主题: + +![ndc-london-volosoft](ndc-london-volosoft.png) + +今年,我们将着重于**ABP.IO平台**(开源ABP框架和ABP商业版).我们的展位会是这样的: + +![ndc-london-volosoft](ndc-2020-volosoft-booth-wall.png) + +如果你参加会议,记得要参观我们的展位.我们将很高兴来谈一谈ABP平台的功能,目标和软件开发. + +### 你想见ABP团队吗? + +如果你在伦敦, 而且想和我们喝杯咖啡的话, 在2月1日的下午[@hibrahimkalkan](https://twitter.com/hibrahimkalkan)和[@ismcagdas](https://twitter.com/ismcagdas)会在那. + +想见面就给info@abp.io写个邮件 :) \ No newline at end of file diff --git a/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png new file mode 100644 index 0000000000..caddce27ab Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png new file mode 100644 index 0000000000..72cb5c0639 Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png new file mode 100644 index 0000000000..70fb9d54f7 Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png differ diff --git a/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png new file mode 100644 index 0000000000..afaed37a7a Binary files /dev/null and b/docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png differ diff --git a/docs/zh-Hans/Connection-Strings.md b/docs/zh-Hans/Connection-Strings.md new file mode 100644 index 0000000000..2df4137b2b --- /dev/null +++ b/docs/zh-Hans/Connection-Strings.md @@ -0,0 +1,64 @@ +# 连接字符串 + +ABP框架的设计是[模块化](Module-Development-Basics.md), [微服务兼容](Microservice-Architecture.md) 和 [多租户](Multi-Tenancy.md). 同时设计了连接字符串管理来支持这些场景; + +* 允许为每个模块设置单独的连接字符串,这样每个模块都可以有自己的物理数据库. 甚至可以将模块配置为使用不同的DBMS. +* 允许为每个租户设置单独的连接字符串使用单独的数据库(在SaaS应用程序中). + +它还支持混合场景; + +* 允许将模块分组到数据库 (所有的模块分组到一个共享数据库, 两个模块使用数据库A, 3个模块使用数据库B, 一个数据库使用数据库C其余的数据库使用数据库D...等.) +* 允许将租户分组到数据库中,像模块一样. +* 允许为每个租户每个模块分离数据库 (数据库过多会增加维护成本,但ABP框架支持这种需求). + +所有[预构建应用模块](Modules/Index.md)已设计为与以上场景兼容. + +## 配置连接字符串 + +参见以下配置: + +````json +"ConnectionStrings": { + "Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;", + "AbpIdentityServer": "Server=localhost;Database=MyIdsDb;Trusted_Connection=True;", + "AbpPermissionManagement": "Server=localhost;Database=MyPermissionDb;Trusted_Connection=True;" +} +```` + +> ABP使用 `IConfiguration` 服务获取应用程序配置. 虽然在 `appsettings.json` 文件中写入配置是最简单的方法, 但它不仅限于此文件. 你可以使用环境变量, user secrets, Azure Key Vault... 等. 更多信息参阅 [配置](Configuration.md) 文档. + +以上配置定义了三个不同的连接字符串: + +* `MyMainDb` (`Default` 连接字符串)是应用程序的主连接字符串. 如果没有为模块指定连接字符串,则回退到 `Default` 连接字符串. [应用程序启动模板](Startup-Templates/Application.md) 配置为使用单个字符串, 所以所有的模块都使用单个数据库. +* `MyIdsDb` 由 [IdentityServer](Modules/IdentityServer.md) 模块使用. +* `MyPermissionDb` 由 [权限管理](Modules/Permission-Management.md) 模块使用. + +[预构建的应用程序模块](Modules/Index.md) 为连接字符串名称定义常量. 例如IdentityServer模块在 `AbpIdentityServerDbProperties` 类(位于 `Volo.Abp.IdentityServer` 命名空间)定义了 `ConnectionStringName` 常量 . 其他的模块类似的定义常量,你可以查看连接字符串的名称. + +## 设置连接字符串名称 + +模块通常使用 `ConnectionStringName` attribute 为 `DbContext` 类关联一个唯一的连接字符串名称. 示例: + +````csharp +[ConnectionStringName("AbpIdentityServer")] +public class IdentityServerDbContext + : AbpDbContext, IIdentityServerDbContext +{ +} +```` + +对于 [Entity Framework Core](Entity-Framework-Core.md) 和 [MongoDB](MongoDB.md), 写入到 `DbContext` 类 (和接口,如果有的话). + +> 如果你开发的是与数据库提供程序无关的可重用模块, 请参见 [最佳实践指南](Best-Practices/Index.md). + +## Entity Framework Core的数据库迁移 + +关系数据库需要在使用数据库之前创建数据库和数据库架构 (表, 视图...等). + +启动模板(使用 EF Core ORM) 带有一个数据库和一个 `.EntityFrameworkCore.DbMigrations` 项目,其中包含数据库的迁移文件. 该项目主要定义了一个*YourProjectName*MigrationsDbContext,它调用所有模块的 `Configure...()` 方法,例如 `builder.ConfigurePermissionManagement()`. + +一旦要分离模块的数据库,通常需要创建第二个迁移路径. 最简单的方法是创建一个带有 `DbContext` 的 `.EntityFrameworkCore.DbMigrations` 项目副本, 更改为只调用需要存储在第二个数据库中的模块的 `Configure...()` 方法并重新创建迁移. 这时你还需要更改 `.DbMigrator` 应用程序使其兼容第二个数据库,这样每个数据库将有一个单独的迁移DbContext. + +## 多租户 + +参阅 [多租户文档](Multi-Tenancy.md)了解如何为租户使用单独的数据库. \ No newline at end of file diff --git a/docs/zh-Hans/Best-Practices/PostgreSQL-Integration.md b/docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md similarity index 100% rename from docs/zh-Hans/Best-Practices/PostgreSQL-Integration.md rename to docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md diff --git a/docs/zh-Hans/FluentValidation.md b/docs/zh-Hans/FluentValidation.md new file mode 100644 index 0000000000..265a2cc2ca --- /dev/null +++ b/docs/zh-Hans/FluentValidation.md @@ -0,0 +1,59 @@ +# FluentValidation 集成 + +ABP[验证](Validation.md)基础设施是可扩展的. [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet 包扩展了验证系统使其与[FluentValidation](https://fluentvalidation.net/)库一起工作. + +## 安装 + +建议使用[ABP CLI](CLI.md)安装包. + +### 使用ABP CLI + +在项目(.csproj文件)的文件夹中打开命令行窗口并输入以下命令: + +````bash +abp add-package Volo.Abp.FluentValidation +```` + +### 手动安装 + +如果你想手动安装; + +1. 添加 [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet包到你的项目: + + ```` + Install-Package Volo.Abp.FluentValidation + ```` + +2. 添加 `AbpFluentValidationModule` 到你的模块的依赖列表: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpFluentValidationModule) //Add the FluentValidation module + )] +public class YourModule : AbpModule +{ +} +```` + +## 使用 FluentValidation + +按照 [FluentValidation文档](https://fluentvalidation.net/) 创建验证器类. +例如: + +````csharp +public class CreateUpdateBookDtoValidator : AbstractValidator +{ + public CreateUpdateBookDtoValidator() + { + RuleFor(x => x.Name).Length(3, 10); + RuleFor(x => x.Price).ExclusiveBetween(0.0f, 999.0f); + } +} +```` + +ABP会自动找到这个类并在对象验证时与 `CreateUpdateBookDto` 关联. + +## 另请参阅 + +* [验证系统](Validation.md) \ No newline at end of file diff --git a/docs/zh-Hans/Logging.md b/docs/zh-Hans/Logging.md new file mode 100644 index 0000000000..247609fb41 --- /dev/null +++ b/docs/zh-Hans/Logging.md @@ -0,0 +1,5 @@ +# 日志 + +ABP框架没有实现任何日志基础设施. 它使用[ASP.NET Core日志系统](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/logging). + +> .NET Core 的日志系统是独立于ASP.NET Core的,它可以在任何类型的应用程序中使用. \ No newline at end of file diff --git a/docs/zh-Hans/Modules/Setting-Management.md b/docs/zh-Hans/Modules/Setting-Management.md index 97e8c2f3e1..31ea2505ea 100644 --- a/docs/zh-Hans/Modules/Setting-Management.md +++ b/docs/zh-Hans/Modules/Setting-Management.md @@ -1,3 +1,84 @@ -# Setting Management Module +# 设置管理模块 -TODO \ No newline at end of file +设置管理模块实现了 `ISettingStore` (参阅 [设置系统](../Settings.md)) 将设置值存储在数据库中, 并提供 `ISettingManager` 管理 (更改) 数据库中设置值的功能. + +> [启动模板](../Startup-Templates/Index.md)默认安装并配置了设置管理模块. 大部分情况下你不需要手动的添加该到模块到应用程序中. + +## ISettingManager + +`ISettingManager` 用于获取和设定设置值. 示例: + +````csharp +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SettingManagement; + +namespace Demo +{ + public class MyService : ITransientDependency + { + private readonly ISettingManager _settingManager; + + //Inject ISettingManager service + public MyService(ISettingManager settingManager) + { + _settingManager = settingManager; + } + + public async Task FooAsync() + { + Guid user1Id = ...; + Guid tenant1Id = ...; + + //Get/set a setting value for the current user or the specified user + + string layoutType1 = + await _settingManager.GetOrNullForCurrentUserAsync("App.UI.LayoutType"); + string layoutType2 = + await _settingManager.GetOrNullForUserAsync("App.UI.LayoutType", user1Id); + + await _settingManager.SetForCurrentUserAsync("App.UI.LayoutType", "LeftMenu"); + await _settingManager.SetForUserAsync(user1Id, "App.UI.LayoutType", "LeftMenu"); + + //Get/set a setting value for the current tenant or the specified tenant + + string layoutType3 = + await _settingManager.GetOrNullForCurrentTenantAsync("App.UI.LayoutType"); + string layoutType4 = + await _settingManager.GetOrNullForTenantAsync("App.UI.LayoutType", tenant1Id); + + await _settingManager.SetForCurrentTenantAsync("App.UI.LayoutType", "LeftMenu"); + await _settingManager.SetForTenantAsync(tenant1Id, "App.UI.LayoutType", "LeftMenu"); + + //Get/set a global and default setting value + + string layoutType5 = + await _settingManager.GetOrNullGlobalAsync("App.UI.LayoutType"); + string layoutType6 = + await _settingManager.GetOrNullDefaultAsync("App.UI.LayoutType"); + + await _settingManager.SetGlobalAsync("App.UI.LayoutType", "TopMenu"); + } + } +} + +```` + +你可以从不同的设置值提供程序中(默认,全局,用户,租户...等)中获取或设定设置值. + +### Setting Cache + +设置值缓存在 [分布式缓存](../Caching.md) 系统中. 建议始终使用 `ISettingManager` 更改设置值. + +## Setting Management Providers + +设置管理模块是可扩展的,像[设置系统](../Settings.md)一样. 你可以通过自定义设置管理提供程序进行扩展. 有5个预构建的设置管理程序程序按以下顺序注册: + +* `DefaultValueSettingManagementProvider`: 从设置定义的默认值中获取值,由于默认值是硬编码在设置定义上的,所以无法更改默认值. +* `ConfigurationSettingManagementProvider`:从 [IConfiguration 服务](../Configuration.md)中获取值. 由于无法在运行时更改配置值,所以无法更改配置值. +* `GlobalSettingManagementProvider`: 获取或设定设置的全局 (系统范围)值. +* `TenantSettingManagementProvider`: 获取或设定租户的设置值. +* `UserSettingManagementProvider`: 获取或设定用户的设置值. + +`ISettingManager` 在 `get/set` 方法中使用设置管理提供程序. 通常每个设置程序提供程序都在 `ISettingManagement` 服务上定义了模块方法 (比如用户设置管理程序提供定义了 `SetForUserAsync` 方法). \ No newline at end of file diff --git a/docs/zh-Hans/Settings.md b/docs/zh-Hans/Settings.md index 7b5d7fbd35..25559082f2 100644 --- a/docs/zh-Hans/Settings.md +++ b/docs/zh-Hans/Settings.md @@ -40,6 +40,33 @@ ABP会自动发现并注册设置的定义. * **Providers**: 限制可用于特定的设置值提供程序(参阅设置值提供程序部分了解更多). * **Properties**: 设置此值的自定义属性 名称/值 集合,可以在之后的应用程序代码中使用. +### 更改依赖模块的设置定义 + +在某些情况下,你可能希望更改应用程序/模块所依赖的其他模块中定义的设置的某些属性. 设置定义提供程序可以查询和更新设置定义. + +下面的示例中获取了由 [Volo.Abp.Emailing](Emailing.md) 包定义的设置并将其更改: + +````csharp +public class MySettingDefinitionProvider : SettingDefinitionProvider +{ + public override void Define(ISettingDefinitionContext context) + { + var smtpHost = context.GetOrNull("Abp.Mailing.Smtp.Host"); + if (smtpHost != null) + { + smtpHost.DefaultValue = "mail.mydomain.com"; + smtpHost.DisplayName = + new LocalizableString( + typeof(MyLocalizationResource), + "SmtpServer_DisplayName" + ); + } + } +} +```` + +> 使用常量作为设置名称是一种好习惯,ABP的包就是这样做的. `Abp.Mailing.Smtp`设置名称是在`EmailSettingNames`类(在Volo.Abp.Emailing名称空间中)定义的常量. + ## 读取设置值 ### ISettingProvider @@ -118,6 +145,30 @@ var requireDigit = abp.setting.getBoolean('Abp.Identity.Password.RequireDigit'); 全局,租户和用户设置值提供程序使用 `ISettingStore` 从数据源读取值(参见下面的小节). +### 在应用程序配置中设置值 + +上一节提到 `ConfigurationSettingValueProvider` 从 `IConfiguration` 服务中读取设置, 该服务默认从 `appsettings.json` 中读取值. 所以在 `appsettings.json` 文件中配置设置值是最简单的方式. + +例如你可以像以下方式一样配置 [IEmailSender](Emailing.md) 设置: + +````json +{ + "Settings": { + "Abp.Mailing.DefaultFromAddress": "noreply@mydomain.com", + "Abp.Mailing.DefaultFromDisplayName": "My Application", + "Abp.Mailing.Smtp.Host": "mail.mydomain.com", + "Abp.Mailing.Smtp.Port": "547", + "Abp.Mailing.Smtp.UserName": "myusername", + "Abp.Mailing.Smtp.Password": "mySecretPassW00rd", + "Abp.Mailing.Smtp.EnableSsl": "True" + } +} +```` + +设置值应该在 `Settings` 部分配置,如本例所示. + +> `IConfiguration`是.NET Core的服务,它不仅可以从 `appsettings.json` 中读取值,还可以从环境,用户机密...等中读取值. 有关更多信息请参阅[微软文档](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/). + ### 自定义设置值提供程序 扩展设置系统的方式是定义一个派生自 `SettingValueProvider` 的类. 示例: diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md index c9a56447ba..f9314e5030 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md @@ -225,7 +225,7 @@ using Volo.Abp.Application.Services; namespace Acme.BookStore { public interface IBookAppService : - IAsyncCrudAppService< //定义了CRUD方法 + ICrudAppService< //定义了CRUD方法 BookDto, //用来展示书籍 Guid, //Book实体的主键 PagedAndSortedResultRequestDto, //获取书籍的时候用于分页和排序 @@ -238,8 +238,8 @@ namespace Acme.BookStore ```` * 框架定义应用程序服务的接口不是必需的. 但是,它被建议作为最佳实践. -* `IAsyncCrudAppService`定义了常见的**CRUD**方法:`GetAsync`,`GetListAsync`,`CreateAsync`,`UpdateAsync`和`DeleteAsync`. 你可以从空的`IApplicationService`接口继承并手动定义自己的方法. -* `IAsyncCrudAppService`有一些变体, 你可以在每个方法中使用单独的DTO,也可以分别单独指定. +* `ICrudAppService`定义了常见的**CRUD**方法:`GetAsync`,`GetListAsync`,`CreateAsync`,`UpdateAsync`和`DeleteAsync`. 你可以从空的`IApplicationService`接口继承并手动定义自己的方法. +* `ICrudAppService`有一些变体, 你可以在每个方法中使用单独的DTO,也可以分别单独指定. #### BookAppService @@ -255,7 +255,7 @@ using Volo.Abp.Domain.Repositories; namespace Acme.BookStore { public class BookAppService : - AsyncCrudAppService, IBookAppService { @@ -268,7 +268,7 @@ namespace Acme.BookStore } ```` -* `BookAppService`继承了`AsyncCrudAppService<...>`.`AsyncCrudAppService<...>`实现了上面定义的CRUD方法. +* `BookAppService`继承了`CrudAppService<...>`.它实现了上面定义的CRUD方法. * `BookAppService`注入`IRepository `,这是`Book`实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅[仓储文档](../../Repositories.md) * `BookAppService`使用`IObjectMapper`将`Book`对象转换为`BookDto`对象, 将`CreateUpdateBookDto`对象转换为`Book`对象. 启动模板使用[AutoMapper](http://automapper.org/)库作为对象映射提供程序. 你之前定义了映射, 因此它将按预期工作. diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md index dd86b5e119..2d4b344afa 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md @@ -421,7 +421,8 @@ $(function () { 打开`Acme.BookStore.Domain.Shared`项目中的`en.json`并添加以下行: ````json -"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?" +"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?", +"SuccessfullyDeleted": "Successfully deleted" ```` 运行程序并尝试删除一个book实体. diff --git a/docs/zh-Hans/Validation.md b/docs/zh-Hans/Validation.md index c2b128f0bc..8aa81351ec 100644 --- a/docs/zh-Hans/Validation.md +++ b/docs/zh-Hans/Validation.md @@ -1,3 +1,163 @@ -## Validation +# 验证 -待添加 +验证系统用于验证对于特定的控制器操作或服务的方法的用户输入或客户端请求. + +ABP与ASP.NET Core模型验证系统系统兼容,[模型验证文档](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation)中的内容对于基于ABP应用程序同样有效.所以本文主要集中在ABP特征,而不是重复微软文档. + +ABP增加了以下优点: + +* 定义 `IValidationEnabled` 向任意类添加自动验证. 所有的[应用服务](Application-Services.md)都实现了该接口,所以它们会被自动验证. +* 自动将数据注解属性的验证错误信息本地化. +* 提供可扩展的服务来验证方法调用或对象的状态。 +* 提供[FluentValidation](https://fluentvalidation.net/)的集成. + +## 验证DTO + +本节简要介绍了验证系统.有关详细信息请参阅[ASP.NET Core验证文档](https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation). + +### 数据注解 Attribute + +使用数据注解是一种以声明式对[DTO](Data-Transfer-Objects.md)进行验证的简单方法. +示例 : + +````csharp +public class CreateBookDto +{ + [Required] + [StringLength(100)] + public string Name { get; set; } + + [Required] + [StringLength(1000)] + public string Description { get; set; } + + [Range(0, 999.99)] + public decimal Price { get; set; } +} +```` + +当使用该类作为[应用服务](Application-Services.md)或控制器的参数时,将对其自动验证并抛出本地化异常(由ABP框架[处理](Exception-Handling.md)). + +### IValidatableObject + +`IValidatableObject` can be implemented by a DTO to perform custom validation logic. `CreateBookDto` in the following example implements this interface and checks if the `Name` is equals to the `Description` and returns a validation error in this case. +可以将DTO实现 `IValidatableObject` 接口进行自定义验证逻辑. 下面的示例中 `CreateBookDto` 实现了这个接口,并检查 `Name` 是否等于 `Description` 并返回一个验证错误. + +````csharp +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Acme.BookStore +{ + public class CreateBookDto : IValidatableObject + { + [Required] + [StringLength(100)] + public string Name { get; set; } + + [Required] + [StringLength(1000)] + public string Description { get; set; } + + [Range(0, 999.99)] + public decimal Price { get; set; } + + public IEnumerable Validate( + ValidationContext validationContext) + { + if (Name == Description) + { + yield return new ValidationResult( + "Name and Description can not be the same!", + new[] { "Name", "Description" } + ); + } + } + } +} +```` + +#### 解析服务 + +如果你需要从[依赖注入系统](Dependency-Injection.md)解析服务,可以使用 `ValidationContext` 对象. +例: + +````csharp +var myService = validationContext.GetRequiredService(); +```` + +> 虽然可以在 `Validate` 方法中解析服务实现任何可能性,但在DTO中实现领域验证逻辑不是一个很好的做法. 应保持简单的DTO,他们的目的是传输数据(DTO:数据传输对象). + +## 验证基础设施 + +本节介绍了ABP框架提供的一些额外的服务. + +### IValidationEnabled 接口 + +`IValidationEnabled` 是可以由任何类来实现的空标记接口(注册到[DI](Dependency-Injection.md)并从中解析),让ABP框架为该类执行验证系统. +示例 : + +````csharp +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Validation; + +namespace Acme.BookStore +{ + public class MyService : ITransientDependency, IValidationEnabled + { + public virtual async Task DoItAsync(MyInput input) + { + //... + } + } +} +```` + +> ABP框架使用[动态代理/拦截](Dynamic-Proxying-Interceptors.md)系统来执行验证.为了使其工作,你的方法应该是 **virtual** 的,服务应该被注入并通过接口(如`IMyService`)使用. + +### AbpValidationException + +一旦ABP确定了一个验证错误,它就会抛出类型为 `AbpValidationException` 的异常. 你的应用程序代码可以抛出 `AbpValidationException`,但大多数情况不会使用它. + +* `ValidationErrors` 是 `AbpValidationException` 的属性,它包含了验证错误列表. +* `AbpValidationException` 的日志级别设置为 `Warning`. 它将所有验证错误记录到[日志系统](Logging.md). +* `AbpValidationException` 由ABP框架自动捕获并将HTTP状态码设置为400转换成可用的错误响应. 参阅[异常处理](Exception-Handling.md)文档了解更多. + +## 高级主题 + +### IObjectValidator + +除了自动验证你可能需要手动验证对象,这种情况下[注入](Dependency-Injection.md)并使用 `IObjectValidator` 服务: + +* `Validate` 方法根据验证​​规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常. +* `GetErrors` 不会抛出异常,只返回验证错误. + +`IObjectValidator` 默认由 `ObjectValidator` 实现. `ObjectValidator`是可扩展的; 可以实现`IObjectValidationContributor`接口提供自定义逻辑. +示例 : + +````csharp +public class MyObjectValidationContributor + : IObjectValidationContributor, ITransientDependency +{ + public void AddErrors(ObjectValidationContext context) + { + //Get the validating object + var obj = context.ValidatingObject; + + //Add the validation errors if available + context.Errors.Add(...); + } +} +```` + +* 记录将类注册到[DI](Dependency-Injection.md)(实现`ITransientDependency` 如同本例) +* ABP会自动发现验证类,并用于任何类型的对象验证(包括自动方法调用验证). + +### IMethodInvocationValidator + +`IMethodInvocationValidator` 用于验证方法调用. 它在内部使用 `IObjectValidator` 来验证传递给方法调用的对象. 由于框架会自动使用此服务,通常你并不需要此服务,但在少数情况下你可能在应用程序中重用或替换它. + +## FluentValidation Integration + +Volo.Abp.FluentValidation 包将FluentValidation库集成到了验证系统(通过实现 `IObjectValidationContributor`). 请参阅[FluentValidation集成文档](FluentValidation.md)了解更多信息. \ No newline at end of file diff --git a/docs/zh-Hans/Virtual-File-System.md b/docs/zh-Hans/Virtual-File-System.md index 49c97c8162..97cf22c73e 100644 --- a/docs/zh-Hans/Virtual-File-System.md +++ b/docs/zh-Hans/Virtual-File-System.md @@ -39,7 +39,8 @@ namespace MyCompany.MyProject ````C# - + + ```` diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 3c6c58cd68..72f92203db 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -75,7 +75,14 @@ "path": "Exception-Handling.md" }, { - "text": "验证" + "text": "验证", + "path": "Validation.md", + "items": [ + { + "text": "FluentValidation集成", + "path": "FluentValidation.md" + } + ] }, { "text": "授权" @@ -254,7 +261,7 @@ "items": [ { "text": "PostgreSQL 集成", - "path": "Best-Practices/PostgreSQL-Integration.md" + "path": "Entity-Framework-Core-PostgreSQL.md" } ] }, diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 088a9437a8..b731aff187 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28922.388 MinimumVisualStudioVersion = 10.0.40219.1 @@ -256,6 +256,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Minify", "src\Volo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Minify.Tests", "test\Volo.Abp.Minify.Tests\Volo.Abp.Minify.Tests.csproj", "{E69182B3-350A-43F5-A935-5EBBEBECEF97}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Serilog", "src\Volo.Abp.AspNetCore.Serilog\Volo.Abp.AspNetCore.Serilog.csproj", "{3B801003-BE74-49ED-9749-DA5E99F45EBF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Serilog.Tests", "test\Volo.Abp.AspNetCore.Serilog.Tests\Volo.Abp.AspNetCore.Serilog.Tests.csproj", "{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -762,6 +766,14 @@ Global {E69182B3-350A-43F5-A935-5EBBEBECEF97}.Debug|Any CPU.Build.0 = Debug|Any CPU {E69182B3-350A-43F5-A935-5EBBEBECEF97}.Release|Any CPU.ActiveCfg = Release|Any CPU {E69182B3-350A-43F5-A935-5EBBEBECEF97}.Release|Any CPU.Build.0 = Release|Any CPU + {3B801003-BE74-49ED-9749-DA5E99F45EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B801003-BE74-49ED-9749-DA5E99F45EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B801003-BE74-49ED-9749-DA5E99F45EBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B801003-BE74-49ED-9749-DA5E99F45EBF}.Release|Any CPU.Build.0 = Release|Any CPU + {9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -892,6 +904,8 @@ Global {73559227-EBF0-475F-835B-1FF0CD9132AA} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {928DC30D-C078-4BB4-A9F8-FE7252C67DC6} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {E69182B3-350A-43F5-A935-5EBBEBECEF97} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {3B801003-BE74-49ED-9749-DA5E99F45EBF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs index 4ff54f39bf..e93f558afd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs @@ -11,14 +11,14 @@ namespace Microsoft.AspNetCore.Builder { if (ctx.User.Identity?.IsAuthenticated != true) { - var result = await ctx.AuthenticateAsync(schema); + var result = await ctx.AuthenticateAsync(schema).ConfigureAwait(false); if (result.Succeeded && result.Principal != null) { ctx.User = result.Principal; } } - await next(); + await next().ConfigureAwait(false); }); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs index 074cc936d0..0c3b05090c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs +++ b/framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs @@ -14,7 +14,11 @@ namespace Volo.Abp.AspNetCore.Authentication.OAuth.Claims public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer) { - var prop = userData.GetProperty(ValueType); + JsonElement prop; + + if (!userData.TryGetProperty(ValueType, out prop)) + return; + if (prop.ValueKind == JsonValueKind.Null) { return; diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs index ba8802a80e..b260df4247 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy TenantConfiguration tenant = null; if (resolveResult.TenantIdOrName != null) { - tenant = await FindTenantAsync(resolveResult.TenantIdOrName); + tenant = await FindTenantAsync(resolveResult.TenantIdOrName).ConfigureAwait(false); if (tenant == null) { //TODO: A better exception? @@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy using (_currentTenant.Change(tenant?.Id, tenant?.Name)) { - await next(context); + await next(context).ConfigureAwait(false); } } @@ -53,11 +53,11 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { if (Guid.TryParse(tenantIdOrName, out var parsedTenantId)) { - return await _tenantStore.FindAsync(parsedTenantId); + return await _tenantStore.FindAsync(parsedTenantId).ConfigureAwait(false); } else { - return await _tenantStore.FindAsync(tenantIdOrName); + return await _tenantStore.FindAsync(tenantIdOrName).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs index 838150fd49..a4f7eb0567 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs @@ -7,6 +7,7 @@ using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.DynamicProxying; +using Volo.Abp.Threading; using Volo.Abp.Users; namespace Volo.Abp.AspNetCore.Mvc.Client @@ -42,12 +43,12 @@ namespace Volo.Abp.AspNetCore.Mvc.Client configuration = await Cache.GetOrAddAsync( cacheKey, - async () => await Proxy.Service.GetAsync(), + async () => await Proxy.Service.GetAsync().ConfigureAwait(false), () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(120) //TODO: Should be configurable. Default value should be higher (5 mins would be good). } - ); + ).ConfigureAwait(false); if (httpContext != null) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs index f769f512a5..9671703db8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteFeatureChecker.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client public override async Task GetOrNullAsync(string name) { - var configuration = await ConfigurationClient.GetAsync(); + var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false); return configuration.Features.Values.GetOrDefault(name); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs index 02c97c0598..42b6eeb543 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLanguageProvider.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client public async Task> GetLanguagesAsync() { - var configuration = await ConfigurationClient.GetAsync(); + var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false); return configuration.Localization.Languages; } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index 79033f3679..d60256a501 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -55,9 +55,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client private Dictionary GetResourceOrNull() { - var applicationConfigurationDto = AsyncHelper.RunSync( - () => _applicationConfigurationClient.GetAsync() - ); + var applicationConfigurationDto = AsyncHelper.RunSync(() => _applicationConfigurationClient.GetAsync()); var resource = applicationConfigurationDto .Localization.Values diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs index cbddb7c3c7..553160029b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs @@ -16,15 +16,15 @@ namespace Volo.Abp.AspNetCore.Mvc.Client public async Task IsGrantedAsync(string name) { - var configuration = await ConfigurationClient.GetAsync(); + var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false); return configuration.Auth.GrantedPolicies.ContainsKey(name); } - public Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name) + public async Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name) { /* This provider always works for the current principal. */ - return IsGrantedAsync(name); + return await IsGrantedAsync(name).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs index db3ea6e9a6..d6526a0b7b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs @@ -17,13 +17,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client public async Task GetOrNullAsync(string name) { - var configuration = await ConfigurationClient.GetAsync(); + var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false); return configuration.Setting.Values.GetOrDefault(name); } public async Task> GetAllAsync() { - var configuration = await ConfigurationClient.GetAsync(); + var configuration = await ConfigurationClient.GetAsync().ConfigureAwait(false); return configuration .Setting.Values .Select(s => new SettingValue(s.Key, s.Value)) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs index 718abbb6a9..8e95376663 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/RemoteTenantStore.cs @@ -39,13 +39,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client tenantConfiguration = await Cache.GetOrAddAsync( cacheKey, - async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name)), + async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name).ConfigureAwait(false)), () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5) //TODO: Should be configurable. } - ); + ).ConfigureAwait(false); if (httpContext != null) { @@ -67,13 +67,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client tenantConfiguration = await Cache.GetOrAddAsync( cacheKey, - async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id)), + async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id).ConfigureAwait(false)), () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5) //TODO: Should be configurable. } - ); + ).ConfigureAwait(false); if (httpContext != null) { @@ -85,12 +85,58 @@ namespace Volo.Abp.AspNetCore.Mvc.Client public TenantConfiguration Find(string name) { - return AsyncHelper.RunSync(() => FindAsync(name)); + var cacheKey = CreateCacheKey(name); + var httpContext = HttpContextAccessor?.HttpContext; + + if (httpContext != null && httpContext.Items[cacheKey] is TenantConfiguration tenantConfiguration) + { + return tenantConfiguration; + } + + tenantConfiguration = Cache.GetOrAdd( + cacheKey, + () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByNameAsync(name).ConfigureAwait(false))), + () => new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = + TimeSpan.FromMinutes(5) //TODO: Should be configurable. + } + ); + + if (httpContext != null) + { + httpContext.Items[cacheKey] = tenantConfiguration; + } + + return tenantConfiguration; } public TenantConfiguration Find(Guid id) { - return AsyncHelper.RunSync(() => FindAsync(id)); + var cacheKey = CreateCacheKey(id); + var httpContext = HttpContextAccessor?.HttpContext; + + if (httpContext != null && httpContext.Items[cacheKey] is TenantConfiguration tenantConfiguration) + { + return tenantConfiguration; + } + + tenantConfiguration = Cache.GetOrAdd( + cacheKey, + () => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await Proxy.Service.FindTenantByIdAsync(id).ConfigureAwait(false))), + () => new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = + TimeSpan.FromMinutes(5) //TODO: Should be configurable. + } + ); + + if (httpContext != null) + { + httpContext.Items[cacheKey] = tenantConfiguration; + } + + return tenantConfiguration; } protected virtual TenantConfiguration CreateTenantConfiguration(FindTenantResultDto tenantResultDto) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs index 8eeeb1e929..4b3a4dd471 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Breadcrumb/AbpBreadcrumbTagHelperService.cs @@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb { var list = InitilizeFormGroupContentsContext(context, output); - await output.GetChildContentAsync(); + await output.GetChildContentAsync().ConfigureAwait(false); SetInnerOlTag(context, output); SetInnerList(context, output, list); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs index ffba80fb6f..65cffd8cb6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Carousel/AbpCarouselTagHelperService.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel var itemList = InitilizeCarouselItemsContentsContext(context, output); - await output.GetChildContentAsync(); + await output.GetChildContentAsync().ConfigureAwait(false); SetOneItemAsActive(context, output, itemList); SetItems(context, output, itemList); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs index 9dc279334b..509b801ba9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionItemTagHelperService.cs @@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse { SetRandomIdIfNotProvided(); - var innerContent = (await output.GetChildContentAsync()).GetContent(); + var innerContent = (await output.GetChildContentAsync().ConfigureAwait(false)).GetContent(); var html = GetAccordionHeaderItem(context, output) + GetAccordionContentItem(context, output, innerContent); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs index 20e62604a9..c6c5c2eb5e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpAccordionTagHelperService.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse var items = InitilizeFormGroupContentsContext(context, output); - await output.GetChildContentAsync(); + await output.GetChildContentAsync().ConfigureAwait(false); var content = GetContent(items); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs index 10e49b92a7..2b81961f67 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Collapse/AbpCollapseBodyTagHelperService.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse output.Attributes.AddClass("multi-collapse"); } - var innerContent = (await output.GetChildContentAsync()).GetContent(); + var innerContent = (await output.GetChildContentAsync().ConfigureAwait(false)).GetContent(); output.Content.SetHtmlContent(innerContent); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs index 673204b302..459a7be318 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Dropdown/AbpDropdownButtonTagHelperService.cs @@ -26,9 +26,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { - var content = await output.GetChildContentAsync(); + var content = await output.GetChildContentAsync().ConfigureAwait(false); - var buttonsAsHtml = await GetButtonsAsHtmlAsync(context, output, content); + var buttonsAsHtml = await GetButtonsAsHtmlAsync(context, output, content).ConfigureAwait(false); output.PreElement.SetHtmlContent(buttonsAsHtml); @@ -43,13 +43,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown { var buttonBuilder = new StringBuilder(""); - var mainButton = await GetMainButtonAsync(context, output, content); + var mainButton = await GetMainButtonAsync(context, output, content).ConfigureAwait(false); buttonBuilder.AppendLine(mainButton); if (TagHelper.DropdownStyle == DropdownStyle.Split) { - var splitButton = await GetSplitButtonAsync(context, output); + var splitButton = await GetSplitButtonAsync(context, output).ConfigureAwait(false); buttonBuilder.AppendLine(splitButton); } @@ -68,7 +68,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown abpButtonTagHelper.ButtonType = TagHelper.ButtonType; var attributes = GetAttributesForMainButton(context, output); - var buttonTag = await abpButtonTagHelper.ProcessAndGetOutputAsync(attributes, context, "button", TagMode.StartTagAndEndTag); + var buttonTag = await abpButtonTagHelper.ProcessAndGetOutputAsync(attributes, context, "button", TagMode.StartTagAndEndTag).ConfigureAwait(false); buttonTag.PreContent.SetHtmlContent(content.GetContent()); @@ -89,7 +89,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown abpButtonTagHelper.ButtonType = TagHelper.ButtonType; var attributes = GetAttributesForSplitButton(context, output); - return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag); + return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual TagHelperAttributeList GetAttributesForMainButton(TagHelperContext context, TagHelperOutput output) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs index d925fd11e8..6767e2bf1d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs @@ -19,14 +19,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions tagHelper.Init(context); - await tagHelper.ProcessAsync(innerContext, innerOutput); + await tagHelper.ProcessAsync(innerContext, innerOutput).ConfigureAwait(false); return innerOutput; } public static async Task RenderAsync(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, HtmlEncoder htmlEncoder, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) { - var innerOutput = await tagHelper.ProcessAndGetOutputAsync(attributeList, context, tagName, tagMode); + var innerOutput = await tagHelper.ProcessAndGetOutputAsync(attributeList, context, tagName, tagMode).ConfigureAwait(false); return innerOutput.Render(htmlEncoder); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs index ee2a920980..5fb439b6f7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs @@ -37,11 +37,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form NormalizeTagMode(context, output); - var childContent = (await output.GetChildContentAsync()).GetContent(); + var childContent = (await output.GetChildContentAsync().ConfigureAwait(false)).GetContent(); - await ConvertToMvcForm(context, output); + await ConvertToMvcForm(context, output).ConfigureAwait(false); - await ProcessFieldsAsync(context, output); + await ProcessFieldsAsync(context, output).ConfigureAwait(false); SetContent(context, output, list, childContent); @@ -67,9 +67,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form ViewContext = TagHelper.ViewContext }; - var formTagOutput = await formTagHelper.ProcessAndGetOutputAsync(output.Attributes, context, "form", TagMode.StartTagAndEndTag); + var formTagOutput = await formTagHelper.ProcessAndGetOutputAsync(output.Attributes, context, "form", TagMode.StartTagAndEndTag).ConfigureAwait(false); - await formTagOutput.GetChildContentAsync(); + await formTagOutput.GetChildContentAsync().ConfigureAwait(false); output.PostContent.SetHtmlContent(output.PostContent.GetContent() + formTagOutput.PostContent.GetContent()); output.PreContent.SetHtmlContent(output.PreContent.GetContent() + formTagOutput.PreContent.GetContent()); @@ -134,11 +134,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { if (IsSelectGroup(context, model)) { - await ProcessSelectGroupAsync(context, output, model); + await ProcessSelectGroupAsync(context, output, model).ConfigureAwait(false); } else { - await ProcessInputGroupAsync(context, output, model); + await ProcessInputGroupAsync(context, output, model).ConfigureAwait(false); } } } @@ -147,7 +147,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { var abpSelectTagHelper = GetSelectGroupTagHelper(context, output, model); - await abpSelectTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag); + await abpSelectTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual AbpTagHelper GetSelectGroupTagHelper(TagHelperContext context, TagHelperOutput output, ModelExpression model) @@ -185,7 +185,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form abpButtonTagHelper.Text = "Submit"; abpButtonTagHelper.ButtonType = AbpButtonType.Primary; - return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag); + return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual async Task ProcessInputGroupAsync(TagHelperContext context, TagHelperOutput output, ModelExpression model) @@ -195,7 +195,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form abpInputTagHelper.ViewContext = TagHelper.ViewContext; abpInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true; - await abpInputTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag); + await abpInputTagHelper.RenderAsync(new TagHelperAttributeList(), context, _htmlEncoder, "div", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual List GetModels(TagHelperContext context, TagHelperOutput output) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 75fe4f23e7..b1195b729e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -27,7 +27,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { - var (innerHtml, isCheckBox) = await GetFormInputGroupAsHtmlAsync(context, output); + var (innerHtml, isCheckBox) = await GetFormInputGroupAsHtmlAsync(context, output).ConfigureAwait(false); var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder(); @@ -57,12 +57,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual async Task<(string, bool)> GetFormInputGroupAsHtmlAsync(TagHelperContext context, TagHelperOutput output) { - var (inputTag, isCheckBox) = await GetInputTagHelperOutputAsync(context, output); + var (inputTag, isCheckBox) = await GetInputTagHelperOutputAsync(context, output).ConfigureAwait(false); var inputHtml = inputTag.Render(_encoder); - var label = await GetLabelAsHtmlAsync(context, output, inputTag, isCheckBox); + var label = await GetLabelAsHtmlAsync(context, output, inputTag, isCheckBox).ConfigureAwait(false); var info = GetInfoAsHtml(context, output, inputTag, isCheckBox); - var validation = isCheckBox ? "" : await GetValidationAsHtmlAsync(context, output, inputTag); + var validation = isCheckBox ? "" : await GetValidationAsHtmlAsync(context, output, inputTag).ConfigureAwait(false); return (GetContent(context, output, label, inputHtml, validation, info, isCheckBox), isCheckBox); } @@ -82,7 +82,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form var attributeList = new TagHelperAttributeList { { "class", "text-danger" } }; - return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag); + return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual string GetContent(TagHelperContext context, TagHelperOutput output, string label, string inputHtml, string validation, string infoHtml, bool isCheckbox) @@ -125,7 +125,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form { var tagHelper = GetInputTagHelper(context, output); - var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "input"); + var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "input").ConfigureAwait(false); ConvertToTextAreaIfTextArea(inputTagHelperOutput); AddDisabledAttribute(inputTagHelperOutput); @@ -227,7 +227,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form if (string.IsNullOrEmpty(TagHelper.Label)) { - return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox) + GetRequiredSymbol(context, output); + return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox).ConfigureAwait(false) + GetRequiredSymbol(context, output); } var checkboxClass = isCheckbox ? "class=\"custom-control-label\" " : ""; @@ -301,7 +301,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form attributeList.AddClass("custom-control-label"); } - return await labelTagHelper.RenderAsync(attributeList, context, _encoder, "label", TagMode.StartTagAndEndTag); + return await labelTagHelper.RenderAsync(attributeList, context, _encoder, "label", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual void ConvertToTextAreaIfTextArea(TagHelperOutput tagHelperOutput) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index b18bc6ed75..f1260883ef 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -30,7 +30,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { - var innerHtml = await GetFormInputGroupAsHtmlAsync(context, output); + var innerHtml = await GetFormInputGroupAsHtmlAsync(context, output).ConfigureAwait(false); var order = TagHelper.AspFor.ModelExplorer.GetDisplayOrder(); @@ -52,10 +52,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form protected virtual async Task GetFormInputGroupAsHtmlAsync(TagHelperContext context, TagHelperOutput output) { - var selectTag = await GetSelectTagAsync(context, output); + var selectTag = await GetSelectTagAsync(context, output).ConfigureAwait(false); var selectAsHtml = selectTag.Render(_encoder); - var label = await GetLabelAsHtmlAsync(context, output, selectTag); - var validation = await GetValidationAsHtmlAsync(context, output, selectTag); + var label = await GetLabelAsHtmlAsync(context, output, selectTag).ConfigureAwait(false); + var validation = await GetValidationAsHtmlAsync(context, output, selectTag).ConfigureAwait(false); var infoText = GetInfoAsHtml(context, output, selectTag); return label + Environment.NewLine + selectAsHtml + Environment.NewLine + infoText + Environment.NewLine + validation; @@ -75,7 +75,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form ViewContext = TagHelper.ViewContext }; - var selectTagHelperOutput = await selectTagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag); + var selectTagHelperOutput = await selectTagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag).ConfigureAwait(false); selectTagHelperOutput.Attributes.AddClass("form-control"); selectTagHelperOutput.Attributes.AddClass(GetSize(context, output)); @@ -123,7 +123,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form return "" + GetRequiredSymbol(context, output); } - return await GetLabelAsHtmlUsingTagHelperAsync(context, output) + GetRequiredSymbol(context, output); + return await GetLabelAsHtmlUsingTagHelperAsync(context, output).ConfigureAwait(false) + GetRequiredSymbol(context, output); } protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output) @@ -242,7 +242,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form ViewContext = TagHelper.ViewContext }; - return await labelTagHelper.RenderAsync(new TagHelperAttributeList(), context, _encoder, "label", TagMode.StartTagAndEndTag); + return await labelTagHelper.RenderAsync(new TagHelperAttributeList(), context, _encoder, "label", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual async Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) @@ -255,7 +255,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form var attributeList = new TagHelperAttributeList { { "class", "text-danger" } }; - return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag); + return await validationMessageTagHelper.RenderAsync(attributeList, context, _encoder, "span", TagMode.StartTagAndEndTag).ConfigureAwait(false); } protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs index e78d59ee82..bb8107bc52 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelperService.cs @@ -8,6 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "div"; + output.Attributes.AddClass("col"); ProcessSizeClasses(context, output); @@ -52,6 +53,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid classString += "-" + size.ToString("D"); } + output.Attributes.RemoveClass("col"); output.Attributes.AddClass(classString); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs index 25307c3fee..f1d2f5c02f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/AbpPaginationTagHelperService.cs @@ -31,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination } ProcessMainTag(context, output); - await SetContentAsHtmlAsync(context, output); + await SetContentAsHtmlAsync(context, output).ConfigureAwait(false); } protected virtual async Task SetContentAsHtmlAsync(TagHelperContext context, TagHelperOutput output) @@ -39,9 +39,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination var html = new StringBuilder(""); html.AppendLine(GetOpeningTags(context, output)); - html.AppendLine(await GetPreviousButtonAsync(context, output)); - html.AppendLine(await GetPagesAsync(context, output)); - html.AppendLine(await GetNextButton(context, output)); + html.AppendLine(await GetPreviousButtonAsync(context, output).ConfigureAwait(false)); + html.AppendLine(await GetPagesAsync(context, output).ConfigureAwait(false)); + html.AppendLine(await GetNextButton(context, output).ConfigureAwait(false)); html.AppendLine(GetClosingTags(context, output)); output.Content.SetHtmlContent(html.ToString()); @@ -61,7 +61,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination foreach (var page in TagHelper.Model.Pages) { - pagesHtml.AppendLine(await GetPageAsync(context, output, page)); + pagesHtml.AppendLine(await GetPageAsync(context, output, page).ConfigureAwait(false)); } return pagesHtml.ToString(); @@ -86,7 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination } else { - pageHtml.AppendLine(await RenderAnchorTagHelperLinkHtmlAsync(context, output, page.Index.ToString(), page.Index.ToString())); + pageHtml.AppendLine(await RenderAnchorTagHelperLinkHtmlAsync(context, output, page.Index.ToString(), page.Index.ToString()).ConfigureAwait(false)); } pageHtml.AppendLine(""); @@ -102,7 +102,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination : (TagHelper.Model.CurrentPage - 1).ToString(); return "
  • \r\n" + - (await RenderAnchorTagHelperLinkHtmlAsync(context, output, currentPage, localizationKey)) + "
  • "; + (await RenderAnchorTagHelperLinkHtmlAsync(context, output, currentPage, localizationKey).ConfigureAwait(false)) + " "; } protected virtual async Task GetNextButton(TagHelperContext context, TagHelperOutput output) @@ -111,7 +111,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination var currentPage = (TagHelper.Model.CurrentPage + 1).ToString(); return "
  • = TagHelper.Model.TotalPageCount ? "disabled" : "") + "\">\r\n" + - (await RenderAnchorTagHelperLinkHtmlAsync(context, output, currentPage, localizationKey)) + + (await RenderAnchorTagHelperLinkHtmlAsync(context, output, currentPage, localizationKey).ConfigureAwait(false)) + "
  • "; } @@ -121,7 +121,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination var anchorTagHelper = GetAnchorTagHelper(currentPage, out var attributeList); - var tagHelperOutput = await anchorTagHelper.ProcessAndGetOutputAsync(attributeList, context, "a", TagMode.StartTagAndEndTag); + var tagHelperOutput = await anchorTagHelper.ProcessAndGetOutputAsync(attributeList, context, "a", TagMode.StartTagAndEndTag).ConfigureAwait(false); tagHelperOutput.Content.SetHtmlContent(localizer[localizationKey]); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs index fb724af9c8..1b74a338dd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabDropdownTagHelperService.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab throw new Exception("Name of tab dropdown tag can not bu null or empty."); } - await output.GetChildContentAsync(); + await output.GetChildContentAsync().ConfigureAwait(false); var tabHeader = GetTabHeaderItem(context, output); var tabHeaderItems = context.GetValue>(TabItems); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs index ba5e3e811a..54a29bf691 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab { public class AbpTabLinkTagHelperService : AbpTagHelperService { - public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { SetPlaceholderForNameIfNotProvided(); @@ -18,6 +18,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, TagHelper.ParentDropdownName, false)); output.SuppressOutput(); + + return Task.CompletedTask; } protected virtual string GetTabHeaderItem(TagHelperContext context, TagHelperOutput output) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs index 2de18d0592..7d8dc7224c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabTagHelperService.cs @@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab { SetPlaceholderForNameIfNotProvided(); - var innerContent = await output.GetChildContentAsync(); + var innerContent = await output.GetChildContentAsync().ConfigureAwait(false); var tabHeader = GetTabHeaderItem(context, output); var tabContent = GetTabContentItem(context, output, innerContent.GetContent()); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabsTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabsTagHelperService.cs index 0098cbc1f0..fbafb2b63c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabsTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabsTagHelperService.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab var items = InitilizeFormGroupContentsContext(context, output); - await output.GetChildContentAsync(); + await output.GetChildContentAsync().ConfigureAwait(false); var headers = GetHeaders(context, output, items); var contents = GetConents(context, output, items); @@ -45,8 +45,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab var headerColumnSize = GetHeaderColumnSize(); var contentColumnSize = 12 - headerColumnSize; - headers = PlaceInsideColunm(headers, headerColumnSize); - contents = PlaceInsideColunm(contents, contentColumnSize); + headers = PlaceInsideColumn(headers, headerColumnSize); + contents = PlaceInsideColumn(contents, contentColumnSize); } @@ -79,9 +79,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab return surroundedContents; } - protected virtual string PlaceInsideColunm(string contents, int columnSize) + protected virtual string PlaceInsideColumn(string contents, int columnSize) { - var surroundedContents = "
    " + Environment.NewLine + + var surroundedContents = "
    " + Environment.NewLine + contents + "
    "; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj index f3556c1dbd..c6ad85408b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.Bootstrap Volo.Abp.AspNetCore.Mvc.UI.Bootstrap $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj index 8601c0e51d..a1b83cbaef 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.Bundling Volo.Abp.AspNetCore.Mvc.UI.Bundling true diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs index f5806364f3..5683a2039f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs @@ -61,12 +61,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling public virtual async Task> GetStyleBundleFilesAsync(string bundleName) { - return await GetBundleFilesAsync(Options.StyleBundles, bundleName, StyleBundler); + return await GetBundleFilesAsync(Options.StyleBundles, bundleName, StyleBundler).ConfigureAwait(false); } public virtual async Task> GetScriptBundleFilesAsync(string bundleName) { - return await GetBundleFilesAsync(Options.ScriptBundles, bundleName, ScriptBundler); + return await GetBundleFilesAsync(Options.ScriptBundles, bundleName, ScriptBundler).ConfigureAwait(false); } protected virtual async Task> GetBundleFilesAsync(BundleConfigurationCollection bundles, string bundleName, IBundler bundler) @@ -185,17 +185,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling foreach (var contributor in contributors) { - await contributor.PreConfigureBundleAsync(context); + await contributor.PreConfigureBundleAsync(context).ConfigureAwait(false); } foreach (var contributor in contributors) { - await contributor.ConfigureBundleAsync(context); + await contributor.ConfigureBundleAsync(context).ConfigureAwait(false); } foreach (var contributor in contributors) { - await contributor.PostConfigureBundleAsync(context); + await contributor.PostConfigureBundleAsync(context).ConfigureAwait(false); } return context.Files; @@ -207,7 +207,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling foreach (var contributor in contributors) { - await contributor.ConfigureDynamicResourcesAsync(context); + await contributor.ConfigureDynamicResourcesAsync(context).ConfigureAwait(false); } return context.Files; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs index fc59051720..a7c504054c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleItemTagHelperService.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers TagHelper.CreateBundleTagHelperItem() }, TagHelper.GetNameOrNull() - ); + ).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs index a8eadce1e8..45aeffaf92 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpBundleTagHelperService.cs @@ -20,16 +20,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers await ResourceService.ProcessAsync( context, output, - await GetBundleItems(context, output), + await GetBundleItems(context, output).ConfigureAwait(false), TagHelper.GetNameOrNull() - ); + ).ConfigureAwait(false); } protected virtual async Task> GetBundleItems(TagHelperContext context, TagHelperOutput output) { var bundleItems = new List(); context.Items[AbpTagHelperConsts.ContextBundleItemListKey] = bundleItems; - await output.GetChildContentAsync(); //TODO: Is there a way of executing children without getting content? + await output.GetChildContentAsync().ConfigureAwait(false); //TODO: Is there a way of executing children without getting content? return bundleItems; } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs index 73b6e025ea..9095fdf335 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs @@ -56,7 +56,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers CreateBundle(bundleName, bundleItems); - var bundleFiles = await GetBundleFilesAsync(bundleName); + var bundleFiles = await GetBundleFilesAsync(bundleName).ConfigureAwait(false); output.Content.Clear(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs index b087db517f..8ab0dffc15 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs @@ -36,7 +36,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers protected override async Task> GetBundleFilesAsync(string bundleName) { - return await BundleManager.GetScriptBundleFilesAsync(bundleName); + return await BundleManager.GetScriptBundleFilesAsync(bundleName).ConfigureAwait(false); } protected override void AddHtmlTag(TagHelperContext context, TagHelperOutput output, string file) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs index 2d273345cb..f82606fa03 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs @@ -36,7 +36,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers protected override async Task> GetBundleFilesAsync(string bundleName) { - return await BundleManager.GetStyleBundleFilesAsync(bundleName); + return await BundleManager.GetStyleBundleFilesAsync(bundleName).ConfigureAwait(false); } protected override void AddHtmlTag(TagHelperContext context, TagHelperOutput output, string file) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs index d0bea87196..7cb02623f1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs @@ -17,7 +17,7 @@ namespace Pages.Abp.MultiTenancy public async Task FindTenantByNameAsync(string name) { - var tenant = await TenantStore.FindAsync(name); + var tenant = await TenantStore.FindAsync(name).ConfigureAwait(false); if (tenant == null) { @@ -34,7 +34,7 @@ namespace Pages.Abp.MultiTenancy public async Task FindTenantByIdAsync(Guid id) { - var tenant = await TenantStore.FindAsync(id); + var tenant = await TenantStore.FindAsync(id).ConfigureAwait(false); if (tenant == null) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs index 5da47875d9..c36d36f61f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs @@ -21,14 +21,14 @@ namespace Pages.Abp.MultiTenancy [Route("tenants/by-name/{name}")] public async Task FindTenantByNameAsync(string name) { - return await _abpTenantAppService.FindTenantByNameAsync(name); + return await _abpTenantAppService.FindTenantByNameAsync(name).ConfigureAwait(false); } [HttpGet] [Route("tenants/by-id/{id}")] public async Task FindTenantByIdAsync(Guid id) { - return await _abpTenantAppService.FindTenantByIdAsync(id); + return await _abpTenantAppService.FindTenantByIdAsync(id).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs index bfdbb98db8..da4d6d207d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs @@ -34,7 +34,7 @@ namespace Pages.Abp.MultiTenancy if (CurrentTenant.IsAvailable) { - var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()); + var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()).ConfigureAwait(false); Input.Name = tenant?.Name; } } @@ -47,7 +47,7 @@ namespace Pages.Abp.MultiTenancy } else { - var tenant = await TenantStore.FindAsync(Input.Name); + var tenant = await TenantStore.FindAsync(Input.Name).ConfigureAwait(false); if (tenant == null) { throw new UserFriendlyException(L["GivenTenantIsNotAvailable", Input.Name]); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj index 960fbd3205..7a31569dda 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json index 7151dc73f3..5887243cb4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/cs.json @@ -6,6 +6,7 @@ "Switch": "změnit", "Name": "Název", "SwitchTenantHint": "Nechte pole prázdné ke změně na hostitele.", + "SwitchTenant": "Změnit tenant", "NotSelected": "Nevybrán" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/zh-Hant.json b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/zh-Hant.json new file mode 100644 index 0000000000..12eea67007 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/zh-Hant.json @@ -0,0 +1,12 @@ +{ + "culture": "zh-Hant", + "texts": { + "GivenTenantIsNotAvailable": "指定的租戶不可用: {0}", + "SwitchTenant": "切換租戶", + "Name": "名稱", + "SwitchTenantHint": "將name欄位留空以切換到主控端.", + "Tenant": "租戶", + "Switch": "切換", + "NotSelected": "尚未選定" + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj index 92937c38ce..7a86cbb464 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.Packages Volo.Abp.AspNetCore.Mvc.UI.Packages true diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/MainNavbarMenuViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/MainNavbarMenuViewComponent.cs index 0369457165..bccd8e00de 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/MainNavbarMenuViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/MainNavbarMenuViewComponent.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Menu public async Task InvokeAsync() { - var menu = await _menuManager.GetAsync(StandardMenus.Main); + var menu = await _menuManager.GetAsync(StandardMenus.Main).ConfigureAwait(false); return View("~/Themes/Basic/Components/Menu/Default.cshtml", menu); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs index c6921d3210..e58190060b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar public async Task InvokeAsync() { - var languages = await _languageProvider.GetLanguagesAsync(); + var languages = await _languageProvider.GetLanguagesAsync().ConfigureAwait(false); var currentLanguage = languages.FindByCulture( CultureInfo.CurrentCulture.Name, CultureInfo.CurrentUICulture.Name diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolsViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolsViewComponent.cs index bfd02bbf4a..862dbe7e2f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolsViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/MainNavbarToolsViewComponent.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar public async Task InvokeAsync() { - var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main); + var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main).ConfigureAwait(false); return View("~/Themes/Basic/Components/Toolbar/Default.cshtml", toolbar); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/UserMenuViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/UserMenuViewComponent.cs index cde4208578..feb7fb09a5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/UserMenuViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/UserMenu/UserMenuViewComponent.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar public async Task InvokeAsync() { - var menu = await _menuManager.GetAsync(StandardMenus.User); + var menu = await _menuManager.GetAsync(StandardMenus.User).ConfigureAwait(false); return View("~/Themes/Basic/Components/Toolbar/UserMenu/Default.cshtml", menu); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs index 1ed1d2d5d3..01e812adfe 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars var languageProvider = context.ServiceProvider.GetService(); //TODO: This duplicates GetLanguages() usage. Can we eleminate this? - var languages = await languageProvider.GetLanguagesAsync(); + var languages = await languageProvider.GetLanguagesAsync().ConfigureAwait(false); if (languages.Count > 1) { context.Toolbar.Items.Add(new ToolbarItem(typeof(LanguageSwitchViewComponent))); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj index f26bc29d7e..168ca481fd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs index 371b886382..1fb4c12cf2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs @@ -61,7 +61,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers if (string.IsNullOrWhiteSpace(page)) { - return "~/Pages/Error/Default.cshtml"; + return "~/Views/Error/Default.cshtml"; } return page; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs index f1ac30779a..e2d66a7d11 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars foreach (var contributor in Options.Contributors) { - await contributor.ConfigureToolbarAsync(context); + await contributor.ConfigureToolbarAsync(context).ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml index f1c6bb91d3..cfd16a2b8c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Views/Error/Default.cshtml @@ -2,8 +2,8 @@ @using System.Collections.Generic @using Localization.Resources.AbpUi @using Microsoft.AspNetCore.Mvc.Localization -@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Error -@model AbpErrorPageModel +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Views.Error +@model AbpErrorViewModel @inject IHtmlLocalizer L @{ var errorMessage = Model.ErrorInfo.Message; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj index c869ae2789..0962057909 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj index d9651aca86..d26c12fc7a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI.Widgets Volo.Abp.AspNetCore.Mvc.UI.Widgets true diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpViewComponentHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpViewComponentHelper.cs index 826c7635cf..e148947c77 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpViewComponentHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpViewComponentHelper.cs @@ -33,10 +33,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets var widget = Options.Widgets.Find(name); if (widget == null) { - return await DefaultViewComponentHelper.InvokeAsync(name, arguments); + return await DefaultViewComponentHelper.InvokeAsync(name, arguments).ConfigureAwait(false); } - return await InvokeWidgetAsync(arguments, widget); + return await InvokeWidgetAsync(arguments, widget).ConfigureAwait(false); } public virtual async Task InvokeAsync(Type componentType, object arguments) @@ -44,10 +44,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets var widget = Options.Widgets.Find(componentType); if (widget == null) { - return await DefaultViewComponentHelper.InvokeAsync(componentType, arguments); + return await DefaultViewComponentHelper.InvokeAsync(componentType, arguments).ConfigureAwait(false); } - return await InvokeWidgetAsync(arguments, widget); + return await InvokeWidgetAsync(arguments, widget).ConfigureAwait(false); } public virtual void Contextualize(ViewContext viewContext) @@ -68,7 +68,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets return new HtmlContentBuilder() .AppendHtml($"
    ") - .AppendHtml(await DefaultViewComponentHelper.InvokeAsync(widget.ViewComponentType, arguments)) + .AppendHtml(await DefaultViewComponentHelper.InvokeAsync(widget.ViewComponentType, arguments).ConfigureAwait(false)) .AppendHtml("
    "); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetManager.cs index ffd03d28dc..2249090bd8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetManager.cs @@ -27,14 +27,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets { var widget = Options.Widgets.Find(widgetComponentType); - return await IsGrantedAsyncInternal(widget, widgetComponentType.FullName); + return await IsGrantedAsyncInternal(widget, widgetComponentType.FullName).ConfigureAwait(false); } public async Task IsGrantedAsync(string name) { var widget = Options.Widgets.Find(name); - return await IsGrantedAsyncInternal(widget, name); + return await IsGrantedAsyncInternal(widget, name).ConfigureAwait(false); } private async Task IsGrantedAsyncInternal(WidgetDefinition widget, string wantedWidgetName) @@ -48,7 +48,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets { foreach (var requiredPolicy in widget.RequiredPolicies) { - if (!(await AuthorizationService.AuthorizeAsync(requiredPolicy)).Succeeded) + if (!(await AuthorizationService.AuthorizeAsync(requiredPolicy).ConfigureAwait(false)).Succeeded) { return false; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj index aff29f8709..fb784efd44 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc.UI Volo.Abp.AspNetCore.Mvc.UI $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index d4affa5fca..0778c57747 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true Volo.Abp.AspNetCore.Mvc Volo.Abp.AspNetCore.Mvc $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; @@ -25,7 +26,7 @@ - + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index ebc086dee6..06ce49551b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.Extensions.Hosting; using Volo.Abp.ApiVersioning; using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.DependencyInjection; @@ -64,6 +65,14 @@ namespace Volo.Abp.AspNetCore.Mvc options.IgnoredInterfaces.AddIfNotContains(typeof(IActionFilter)); }); + context.Services.PostConfigure(options => + { + if (options.MinifyGeneratedScript == null) + { + options.MinifyGeneratedScript = context.Services.GetHostingEnvironment().IsProduction(); + } + }); + var mvcCoreBuilder = context.Services.AddMvcCore(); context.Services.ExecutePreConfiguredActions(mvcCoreBuilder); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs index fb29e17496..55d5512c6a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs @@ -4,6 +4,8 @@ namespace Volo.Abp.AspNetCore.Mvc { public class AbpAspNetCoreMvcOptions { + public bool? MinifyGeneratedScript { get; set; } + public AbpConventionalControllerOptions ConventionalControllers { get; } public AbpAspNetCoreMvcOptions() diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs index a633edb37e..4aedf0b087 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs @@ -5,6 +5,7 @@ using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc.Features; using Volo.Abp.AspNetCore.Mvc.ModelBinding; +using Volo.Abp.AspNetCore.Mvc.Response; using Volo.Abp.AspNetCore.Mvc.Uow; using Volo.Abp.AspNetCore.Mvc.Validation; @@ -28,6 +29,7 @@ namespace Volo.Abp.AspNetCore.Mvc private static void AddFilters(MvcOptions options) { options.Filters.AddService(typeof(AbpAuditActionFilter)); + options.Filters.AddService(typeof(AbpNoContentActionFilter)); options.Filters.AddService(typeof(AbpFeatureActionFilter)); options.Filters.AddService(typeof(AbpValidationActionFilter)); options.Filters.AddService(typeof(AbpUowActionFilter)); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index f3af9182ba..1744658d41 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Volo.Abp.Application.Services; using Volo.Abp.Authorization; using Volo.Abp.Features; @@ -34,7 +35,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations IAuthorizationService authorizationService, ICurrentUser currentUser, ISettingProvider settingProvider, - SettingDefinitionManager settingDefinitionManager, + ISettingDefinitionManager settingDefinitionManager, IFeatureDefinitionManager featureDefinitionManager, ILanguageProvider languageProvider) { @@ -55,11 +56,12 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations return new ApplicationConfigurationDto { - Auth = await GetAuthConfigAsync(), - Features = await GetFeaturesConfigAsync(), - Localization = await GetLocalizationConfigAsync(), + Auth = await GetAuthConfigAsync().ConfigureAwait(false), + Features = await GetFeaturesConfigAsync().ConfigureAwait(false), + Localization = await GetLocalizationConfigAsync().ConfigureAwait(false), CurrentUser = GetCurrentUser(), Setting = await GetSettingConfigAsync() +.ConfigureAwait(false) }; } @@ -76,23 +78,35 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations protected virtual async Task GetAuthConfigAsync() { + Logger.LogDebug("Executing AbpApplicationConfigurationAppService.GetAuthConfigAsync()"); + var authConfig = new ApplicationAuthConfigurationDto(); - foreach (var policyName in await _abpAuthorizationPolicyProvider.GetPoliciesNamesAsync()) + var policyNames = await _abpAuthorizationPolicyProvider.GetPoliciesNamesAsync().ConfigureAwait(false); + + Logger.LogDebug($"GetPoliciesNamesAsync returns {policyNames.Count} items."); + + foreach (var policyName in policyNames) { authConfig.Policies[policyName] = true; - if (await _authorizationService.IsGrantedAsync(policyName)) + Logger.LogDebug($"_authorizationService.IsGrantedAsync? {policyName}"); + + if (await _authorizationService.IsGrantedAsync(policyName).ConfigureAwait(false)) { authConfig.GrantedPolicies[policyName] = true; } } + Logger.LogDebug("Executed AbpApplicationConfigurationAppService.GetAuthConfigAsync()"); + return authConfig; } protected virtual async Task GetLocalizationConfigAsync() { + Logger.LogDebug("Executing AbpApplicationConfigurationAppService.GetLocalizationConfigAsync()"); + var localizationConfig = new ApplicationLocalizationConfigurationDto(); localizationConfig.Languages.AddRange(await _languageProvider.GetLanguagesAsync()); @@ -115,12 +129,14 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations localizationConfig.CurrentCulture = GetCurrentCultureInfo(); + Logger.LogDebug("Executed AbpApplicationConfigurationAppService.GetLocalizationConfigAsync()"); + return localizationConfig; } private static CurrentCultureDto GetCurrentCultureInfo() { - return new CurrentCultureDto + return new CurrentCultureDto { Name = CultureInfo.CurrentUICulture.Name, DisplayName = CultureInfo.CurrentUICulture.DisplayName, @@ -145,6 +161,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations private async Task GetSettingConfigAsync() { + Logger.LogDebug("Executing AbpApplicationConfigurationAppService.GetSettingConfigAsync()"); + var result = new ApplicationSettingConfigurationDto { Values = new Dictionary() @@ -157,14 +175,18 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations continue; } - result.Values[settingDefinition.Name] = await _settingProvider.GetOrNullAsync(settingDefinition.Name); + result.Values[settingDefinition.Name] = await _settingProvider.GetOrNullAsync(settingDefinition.Name).ConfigureAwait(false); } + Logger.LogDebug("Executed AbpApplicationConfigurationAppService.GetSettingConfigAsync()"); + return result; } protected virtual async Task GetFeaturesConfigAsync() { + Logger.LogDebug("Executing AbpApplicationConfigurationAppService.GetFeaturesConfigAsync()"); + var result = new ApplicationFeatureConfigurationDto(); foreach (var featureDefinition in _featureDefinitionManager.GetAll()) @@ -174,9 +196,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations continue; } - result.Values[featureDefinition.Name] = await FeatureChecker.GetOrNullAsync(featureDefinition.Name); + result.Values[featureDefinition.Name] = await FeatureChecker.GetOrNullAsync(featureDefinition.Name).ConfigureAwait(false); } + Logger.LogDebug("Executed AbpApplicationConfigurationAppService.GetFeaturesConfigAsync()"); + return result; } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs index 98e09ff9a8..ae41e579c9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs @@ -15,9 +15,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations } [HttpGet] - public Task GetAsync() + public async Task GetAsync() { - return _applicationConfigurationAppService.GetAsync(); + return await _applicationConfigurationAppService.GetAsync().ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs index bce46bab44..00cef65179 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs @@ -1,10 +1,11 @@ -using System.Diagnostics; -using System.Text; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Volo.Abp.Auditing; using Volo.Abp.Http; using Volo.Abp.Json; +using Volo.Abp.Minify.Scripts; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { @@ -15,23 +16,31 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { private readonly IAbpApplicationConfigurationAppService _configurationAppService; private readonly IJsonSerializer _jsonSerializer; + private readonly AbpAspNetCoreMvcOptions _options; + private readonly IJavascriptMinifier _javascriptMinifier; public AbpApplicationConfigurationScriptController( IAbpApplicationConfigurationAppService configurationAppService, - IJsonSerializer jsonSerializer) + IJsonSerializer jsonSerializer, + IOptions options, + IJavascriptMinifier javascriptMinifier) { _configurationAppService = configurationAppService; _jsonSerializer = jsonSerializer; + _options = options.Value; + _javascriptMinifier = javascriptMinifier; } [HttpGet] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] public async Task Get() { + var script = CreateAbpExtendScript(await _configurationAppService.GetAsync().ConfigureAwait(false)); + return Content( - CreateAbpExtendScript( - await _configurationAppService.GetAsync() - ), + _options.MinifyGeneratedScript == true + ? _javascriptMinifier.Minify(script) + : script, MimeTypes.Application.Javascript ); } @@ -42,7 +51,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations script.AppendLine("(function(){"); script.AppendLine(); - script.AppendLine($"$.extend(true, abp, {_jsonSerializer.Serialize(config, indented: Debugger.IsAttached)})"); + script.AppendLine($"$.extend(true, abp, {_jsonSerializer.Serialize(config, indented: true)})"); script.AppendLine(); script.AppendLine("abp.event.trigger('abp.configurationInitialized');"); script.AppendLine(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs index 33932137cb..4699689d76 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs @@ -27,7 +27,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing { if (!ShouldSaveAudit(context, out var auditLog, out var auditLogAction)) { - await next(); + await next().ConfigureAwait(false); return; } @@ -37,7 +37,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing try { - var result = await next(); + var result = await next().ConfigureAwait(false); if (result.Exception != null && !result.ExceptionHandled) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs index de8958920d..cfd75840a7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs @@ -8,10 +8,12 @@ namespace Volo.Abp.AspNetCore.Mvc.Authentication public abstract class ChallengeAccountController : AbpController { protected string[] ChallengeAuthenticationSchemas { get; } + protected string AuthenticationType { get; } protected ChallengeAccountController(string[] challengeAuthenticationSchemas = null) { - ChallengeAuthenticationSchemas = challengeAuthenticationSchemas ?? new[]{ "oidc" }; + ChallengeAuthenticationSchemas = challengeAuthenticationSchemas ?? new[] { "oidc" }; + AuthenticationType = "Identity.Application"; } [HttpGet] @@ -40,9 +42,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Authentication [HttpGet] public async Task Logout(string returnUrl = "", string returnUrlHash = "") { - await HttpContext.SignOutAsync(); + await HttpContext.SignOutAsync().ConfigureAwait(false); - return RedirectSafely(returnUrl, returnUrlHash); + if (HttpContext.User.Identity.AuthenticationType == AuthenticationType) + { + return RedirectSafely(returnUrl, returnUrlHash); + } + + return new SignOutResult(ChallengeAuthenticationSchemas); } protected RedirectResult RedirectSafely(string returnUrl, string returnUrlHash = null) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs index 577acda339..ffca5b12ee 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Features/AbpFeatureActionFilter.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Features { if (!context.ActionDescriptor.IsControllerAction()) { - await next(); + await next().ConfigureAwait(false); return; } @@ -33,9 +33,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Features { await _methodInvocationAuthorizationService.CheckAsync( new MethodInvocationFeatureCheckerContext(methodInfo) - ); + ).ConfigureAwait(false); - await next(); + await next().ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs index 1916b9aa16..1e31da90f8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding public async Task BindModelAsync(ModelBindingContext bindingContext) { - await _simpleTypeModelBinder.BindModelAsync(bindingContext); + await _simpleTypeModelBinder.BindModelAsync(bindingContext).ConfigureAwait(false); if (!bindingContext.Result.IsModelSet) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs index b94e5c6a92..99cada9602 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs @@ -1,7 +1,9 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Volo.Abp.Auditing; using Volo.Abp.Http; using Volo.Abp.Http.ProxyScripting; +using Volo.Abp.Minify.Scripts; namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting { @@ -11,10 +13,16 @@ namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting public class AbpServiceProxyScriptController : AbpController { private readonly IProxyScriptManager _proxyScriptManager; + private readonly AbpAspNetCoreMvcOptions _options; + private readonly IJavascriptMinifier _javascriptMinifier; - public AbpServiceProxyScriptController(IProxyScriptManager proxyScriptManager) + public AbpServiceProxyScriptController(IProxyScriptManager proxyScriptManager, + IOptions options, + IJavascriptMinifier javascriptMinifier) { _proxyScriptManager = proxyScriptManager; + _options = options.Value; + _javascriptMinifier = javascriptMinifier; } [HttpGet] @@ -22,7 +30,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting public ActionResult GetAll(ServiceProxyGenerationModel model) { model.Normalize(); - return Content(_proxyScriptManager.GetScript(model.CreateOptions()), MimeTypes.Application.Javascript); + + var script = _proxyScriptManager.GetScript(model.CreateOptions()); + + return Content( + _options.MinifyGeneratedScript == true + ? _javascriptMinifier.Minify(script) + : script, + MimeTypes.Application.Javascript + ); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs index 20dae137e7..5cc9a0a3c5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs @@ -11,8 +11,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting public bool UseCache { get; set; } - public bool Minify { get; set; } - public string Modules { get; set; } public string Controllers { get; set; } @@ -34,7 +32,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting public ProxyScriptingModel CreateOptions() { - var options = new ProxyScriptingModel(Type, UseCache, Minify); + var options = new ProxyScriptingModel(Type, UseCache); if (!Modules.IsNullOrEmpty()) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs new file mode 100644 index 0000000000..b6d56b2f2a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs @@ -0,0 +1,31 @@ +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Filters; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.Response +{ + public class AbpNoContentActionFilter : IAsyncActionFilter, ITransientDependency + { + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + if (!context.ActionDescriptor.IsControllerAction()) + { + await next(); + return; + } + + await next(); + + if (context.HttpContext.Response.StatusCode == (int)HttpStatusCode.OK) + { + var returnType = context.ActionDescriptor.GetReturnType(); + if (returnType == typeof(Task) || returnType == typeof(void)) + { + context.HttpContext.Response.StatusCode = (int)HttpStatusCode.NoContent; + } + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs index 552ce7e04e..56153fedea 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow { if (!context.ActionDescriptor.IsControllerAction()) { - await next(); + await next().ConfigureAwait(false); return; } @@ -39,7 +39,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow if (unitOfWorkAttr?.IsDisabled == true) { - await next(); + await next().ConfigureAwait(false); return; } @@ -48,10 +48,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow //Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware if (_unitOfWorkManager.TryBeginReserved(AbpUnitOfWorkMiddleware.UnitOfWorkReservationName, options)) { - var result = await next(); + var result = await next().ConfigureAwait(false); if (!Succeed(result)) { - await RollbackAsync(context); + await RollbackAsync(context).ConfigureAwait(false); } return; @@ -60,10 +60,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow //Begin a new, independent unit of work using (var uow = _unitOfWorkManager.Begin(options)) { - var result = await next(); + var result = await next().ConfigureAwait(false); if (Succeed(result)) { - await uow.CompleteAsync(context.HttpContext.RequestAborted); + await uow.CompleteAsync(context.HttpContext.RequestAborted).ConfigureAwait(false); } } } @@ -89,7 +89,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow var currentUow = _unitOfWorkManager.Current; if (currentUow != null) { - await currentUow.RollbackAsync(context.HttpContext.RequestAborted); + await currentUow.RollbackAsync(context.HttpContext.RequestAborted).ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs index ca87f2b962..ae047fa30a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/AbpValidationActionFilter.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; -using Volo.Abp.Aspects; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.Validation @@ -22,12 +21,12 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation if (!context.ActionDescriptor.IsControllerAction() || !context.ActionDescriptor.HasObjectResult()) { - await next(); + await next().ConfigureAwait(false); return; } _validator.Validate(context.ModelState); - await next(); + await next().ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Microsoft/AspNetCore/Builder/AbpAspNetCoreSerilogApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Serilog/Microsoft/AspNetCore/Builder/AbpAspNetCoreSerilogApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..cf15367e15 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Microsoft/AspNetCore/Builder/AbpAspNetCoreSerilogApplicationBuilderExtensions.cs @@ -0,0 +1,13 @@ +using Volo.Abp.AspNetCore.Serilog; + +namespace Microsoft.AspNetCore.Builder +{ + public static class AbpAspNetCoreSerilogApplicationBuilderExtensions + { + public static IApplicationBuilder UseAbpSerilogEnrichers(this IApplicationBuilder app) + { + return app + .UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json new file mode 100644 index 0000000000..cb1bd6546c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:61851/", + "sslPort": 44301 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Volo.Abp.AspNetCore.Serilog": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj new file mode 100644 index 0000000000..f450e04423 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj @@ -0,0 +1,27 @@ + + + + + + netcoreapp3.1 + Volo.Abp.AspNetCore.Serilog + Volo.Abp.AspNetCore.Serilog + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + true + Library + + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpAspNetCoreSerilogModule.cs b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpAspNetCoreSerilogModule.cs new file mode 100644 index 0000000000..dc8e7c1ce4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpAspNetCoreSerilogModule.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.AspNetCore.Serilog +{ + [DependsOn( + typeof(AbpMultiTenancyModule), + typeof(AbpAspNetCoreModule) + )] + public class AbpAspNetCoreSerilogModule : AbpModule + { + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpAspNetCoreSerilogOptions.cs b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpAspNetCoreSerilogOptions.cs new file mode 100644 index 0000000000..84f212ff4a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpAspNetCoreSerilogOptions.cs @@ -0,0 +1,30 @@ +namespace Volo.Abp.AspNetCore.Serilog +{ + public class AbpAspNetCoreSerilogOptions + { + public AllEnricherPropertyNames EnricherPropertyNames { get; } = new AllEnricherPropertyNames(); + + public class AllEnricherPropertyNames + { + /// + /// Default value: "TenantId". + /// + public string TenantId { get; set; } = "TenantId"; + + /// + /// Default value: "UserId". + /// + public string UserId { get; set; } = "UserId"; + + /// + /// Default value: "ClientId". + /// + public string ClientId { get; set; } = "ClientId"; + + /// + /// Default value: "CorrelationId". + /// + public string CorrelationId { get; set; } = "CorrelationId"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs new file mode 100644 index 0000000000..8a8f032766 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Serilog/Volo/Abp/AspNetCore/Serilog/AbpSerilogMiddleware.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Serilog.Context; +using Serilog.Core; +using Serilog.Core.Enrichers; +using Volo.Abp.Clients; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Tracing; +using Volo.Abp.Users; + +namespace Volo.Abp.AspNetCore.Serilog +{ + public class AbpSerilogMiddleware : IMiddleware, ITransientDependency + { + private readonly ICurrentClient _currentClient; + private readonly ICurrentTenant _currentTenant; + private readonly ICurrentUser _currentUser; + private readonly ICorrelationIdProvider _correlationIdProvider; + private readonly AbpAspNetCoreSerilogOptions _options; + + public AbpSerilogMiddleware( + ICurrentTenant currentTenant, + ICurrentUser currentUser, + ICurrentClient currentClient, + ICorrelationIdProvider correlationIdProvider, + IOptions options) + { + _currentTenant = currentTenant; + _currentUser = currentUser; + _currentClient = currentClient; + _correlationIdProvider = correlationIdProvider; + _options = options.Value; + } + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + var enrichers = new List(); + + if (_currentTenant?.Id != null) + { + enrichers.Add(new PropertyEnricher(_options.EnricherPropertyNames.TenantId, _currentTenant.Id)); + } + + if (_currentUser?.Id != null) + { + enrichers.Add(new PropertyEnricher(_options.EnricherPropertyNames.UserId, _currentUser.Id)); + } + + if (_currentClient?.Id != null) + { + enrichers.Add(new PropertyEnricher(_options.EnricherPropertyNames.ClientId, _currentClient.Id)); + } + + var correlationId = _correlationIdProvider.Get(); + if (!string.IsNullOrEmpty(correlationId)) + { + enrichers.Add(new PropertyEnricher(_options.EnricherPropertyNames.CorrelationId, correlationId)); + } + + using (LogContext.Push(enrichers.ToArray())) + { + await next(context).ConfigureAwait(false); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs index 22c0079571..295a8bd100 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs @@ -2,6 +2,7 @@ using JetBrains.Annotations; using Microsoft.AspNetCore.RequestLocalization; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Volo.Abp; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.ExceptionHandling; @@ -20,7 +21,20 @@ namespace Microsoft.AspNetCore.Builder Check.NotNull(app, nameof(app)); app.ApplicationServices.GetRequiredService>().Value = app; - app.ApplicationServices.GetRequiredService().Initialize(app.ApplicationServices); + var application = app.ApplicationServices.GetRequiredService(); + var applicationLifetime = app.ApplicationServices.GetRequiredService(); + + applicationLifetime.ApplicationStopping.Register(() => + { + application.Shutdown(); + }); + + applicationLifetime.ApplicationStopped.Register(() => + { + application.Dispose(); + }); + + application.Initialize(app.ApplicationServices); } public static IApplicationBuilder UseAuditing(this IApplicationBuilder app) @@ -42,7 +56,8 @@ namespace Microsoft.AspNetCore.Builder .UseMiddleware(); } - public static IApplicationBuilder UseAbpRequestLocalization(this IApplicationBuilder app, Action optionsAction = null) + public static IApplicationBuilder UseAbpRequestLocalization(this IApplicationBuilder app, + Action optionsAction = null) { app.ApplicationServices .GetRequiredService() @@ -62,4 +77,4 @@ namespace Microsoft.AspNetCore.Builder return app.UseMiddleware(); } } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs index 75d903557e..32fed42dc2 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs @@ -25,11 +25,13 @@ namespace Microsoft.AspNetCore.RequestLocalization { var middleware = new RequestLocalizationMiddleware( next, - new OptionsWrapper(_requestLocalizationOptionsProvider.GetLocalizationOptions()), + new OptionsWrapper( + await _requestLocalizationOptionsProvider.GetLocalizationOptionsAsync() +.ConfigureAwait(false)), _loggerFactory ); - await middleware.Invoke(context); + await middleware.Invoke(context).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs index 730f6e3937..51932953ed 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/DefaultAbpRequestLocalizationOptionsProvider.cs @@ -2,67 +2,76 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.DependencyInjection; +using Nito.AsyncEx; using Volo.Abp.DependencyInjection; using Volo.Abp.Localization; using Volo.Abp.Settings; -using Volo.Abp.Threading; namespace Microsoft.AspNetCore.RequestLocalization { public class DefaultAbpRequestLocalizationOptionsProvider : IAbpRequestLocalizationOptionsProvider, ISingletonDependency { - private readonly IServiceProvider _serviceProvider; - private Lazy _lazyRequestLocalizationOptions; + private readonly IServiceScopeFactory _serviceProviderFactory; + private readonly SemaphoreSlim _syncSemaphore; + private Action _optionsAction; + private RequestLocalizationOptions _requestLocalizationOptions; - public DefaultAbpRequestLocalizationOptionsProvider(IServiceProvider serviceProvider) + public DefaultAbpRequestLocalizationOptionsProvider(IServiceScopeFactory serviceProviderFactory) { - _serviceProvider = serviceProvider; + _serviceProviderFactory = serviceProviderFactory; + _syncSemaphore = new SemaphoreSlim(1, 1); } public void InitLocalizationOptions(Action optionsAction = null) { - _lazyRequestLocalizationOptions = new Lazy(() => + _optionsAction = optionsAction; + } + + public async Task GetLocalizationOptionsAsync() + { + if (_requestLocalizationOptions == null) { - using (var serviceScope = _serviceProvider.CreateScope()) + using (await _syncSemaphore.LockAsync().ConfigureAwait(false)) { - var languageProvider = serviceScope.ServiceProvider.GetRequiredService(); - var settingProvider = serviceScope.ServiceProvider.GetRequiredService(); + using (var serviceScope = _serviceProviderFactory.CreateScope()) + { + var languageProvider = serviceScope.ServiceProvider.GetRequiredService(); + var settingProvider = serviceScope.ServiceProvider.GetRequiredService(); - var languages = AsyncHelper.RunSync(languageProvider.GetLanguagesAsync); - var defaultLanguage = AsyncHelper.RunSync(() => - settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage)); + var languages = await languageProvider.GetLanguagesAsync().ConfigureAwait(false); + var defaultLanguage = await settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage).ConfigureAwait(false); - var options = !languages.Any() - ? new RequestLocalizationOptions() - : new RequestLocalizationOptions - { - DefaultRequestCulture = DefaultGetRequestCulture(defaultLanguage, languages), + var options = !languages.Any() + ? new RequestLocalizationOptions() + : new RequestLocalizationOptions + { + DefaultRequestCulture = DefaultGetRequestCulture(defaultLanguage, languages), - SupportedCultures = languages - .Select(l => l.CultureName) - .Distinct() - .Select(c => new CultureInfo(c)) - .ToArray(), + SupportedCultures = languages + .Select(l => l.CultureName) + .Distinct() + .Select(c => new CultureInfo(c)) + .ToArray(), - SupportedUICultures = languages - .Select(l => l.UiCultureName) - .Distinct() - .Select(c => new CultureInfo(c)) - .ToArray() - }; + SupportedUICultures = languages + .Select(l => l.UiCultureName) + .Distinct() + .Select(c => new CultureInfo(c)) + .ToArray() + }; - optionsAction?.Invoke(options); - return options; + _optionsAction?.Invoke(options); + _requestLocalizationOptions = options; + } } - }, true); - } + } - public RequestLocalizationOptions GetLocalizationOptions() - { - return _lazyRequestLocalizationOptions.Value; + return _requestLocalizationOptions; } private static RequestCulture DefaultGetRequestCulture(string defaultLanguage, IReadOnlyList languages) diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs index 5179bb48ee..86cd3153f7 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/IAbpRequestLocalizationOptionsProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; namespace Microsoft.AspNetCore.RequestLocalization @@ -7,6 +8,6 @@ namespace Microsoft.AspNetCore.RequestLocalization { void InitLocalizationOptions(Action optionsAction = null); - RequestLocalizationOptions GetLocalizationOptions(); + Task GetLocalizationOptionsAsync(); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs index 78ae28e63f..d56c29709a 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpAuditingMiddleware.cs @@ -30,7 +30,7 @@ namespace Volo.Abp.AspNetCore.Auditing { if (!ShouldWriteAuditLog(context)) { - await next(context); + await next(context).ConfigureAwait(false); return; } @@ -38,11 +38,11 @@ namespace Volo.Abp.AspNetCore.Auditing { try { - await next(context); + await next(context).ConfigureAwait(false); } finally { - await scope.SaveAsync(); + await scope.SaveAsync().ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index cdd921dae4..d9954dc424 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -29,7 +29,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { try { - await next(context); + await next(context).ConfigureAwait(false); } catch (Exception ex) { @@ -44,7 +44,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling { if (actionInfo.IsObjectResult) //TODO: Align with AbpExceptionFilter.ShouldHandleException! { - await HandleAndWrapException(context, ex); + await HandleAndWrapException(context, ex).ConfigureAwait(false); return; } } @@ -72,7 +72,7 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling errorInfoConverter.Convert(exception) ) ) - ); + ).ConfigureAwait(false); } private Task ClearCacheHeaders(object state) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs index b3ee565100..068adffefb 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AbpCorrelationIdMiddleware.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Tracing try { - await next(context); + await next(context).ConfigureAwait(false); } finally { diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs index c9ac1be509..46572b4450 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs @@ -20,8 +20,8 @@ namespace Volo.Abp.AspNetCore.Uow { using (var uow = _unitOfWorkManager.Reserve(UnitOfWorkReservationName)) { - await next(context); - await uow.CompleteAsync(context.RequestAborted); + await next(context).ConfigureAwait(false); + await uow.CompleteAsync(context.RequestAborted).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs index 434ddc9d16..a49145298a 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs @@ -18,38 +18,11 @@ namespace Volo.Abp.Auditing _auditingManager = auditingManager; } - public override void Intercept(IAbpMethodInvocation invocation) - { - if (!ShouldIntercept(invocation, out var auditLog, out var auditLogAction)) - { - invocation.Proceed(); - return; - } - - var stopwatch = Stopwatch.StartNew(); - - try - { - invocation.Proceed(); - } - catch (Exception ex) - { - auditLog.Exceptions.Add(ex); - throw; - } - finally - { - stopwatch.Stop(); - auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - auditLog.Actions.Add(auditLogAction); - } - } - public override async Task InterceptAsync(IAbpMethodInvocation invocation) { if (!ShouldIntercept(invocation, out var auditLog, out var auditLogAction)) { - await invocation.ProceedAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); return; } @@ -57,7 +30,7 @@ namespace Volo.Abp.Auditing try { - await invocation.ProceedAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); } catch (Exception ex) { diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs index 546d54299c..94920fe1be 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptorRegistrar.cs @@ -32,6 +32,8 @@ namespace Volo.Abp.Auditing //TODO: Move to a better place public static bool ShouldAuditTypeByDefault(Type type) { + //TODO: In an inheritance chain, it would be better to check the attributes on the top class first. + if (type.IsDefined(typeof(AuditedAttribute), true)) { return true; diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs index d314d31799..25738843c0 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs @@ -116,17 +116,7 @@ namespace Volo.Abp.Auditing if (ShouldSave(saveHandle.AuditLog)) { - await _auditingStore.SaveAsync(saveHandle.AuditLog); - } - } - - protected virtual void Save(DisposableSaveHandle saveHandle) - { - BeforeSave(saveHandle); - - if (ShouldSave(saveHandle.AuditLog)) - { - _auditingStore.Save(saveHandle.AuditLog); + await _auditingStore.SaveAsync(saveHandle.AuditLog).ConfigureAwait(false); } } @@ -162,12 +152,7 @@ namespace Volo.Abp.Auditing public async Task SaveAsync() { - await _auditingManager.SaveAsync(this); - } - - public void Save() - { - _auditingManager.Save(this); + await _auditingManager.SaveAsync(this).ConfigureAwait(false); } public void Dispose() diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs index 596f67523a..4709b745d2 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs @@ -5,8 +5,6 @@ namespace Volo.Abp.Auditing { public interface IAuditLogSaveHandle : IDisposable { - void Save(); - Task SaveAsync(); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs index 101ec8b03e..7166af642b 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs @@ -4,8 +4,6 @@ namespace Volo.Abp.Auditing { public interface IAuditingStore { - void Save(AuditLogInfo auditInfo); - Task SaveAsync(AuditLogInfo auditInfo); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs index 8067ede5c5..eeb6c7803c 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs @@ -15,14 +15,9 @@ namespace Volo.Abp.Auditing Logger = NullLogger.Instance; } - public void Save(AuditLogInfo auditInfo) - { - Logger.LogInformation(auditInfo.ToString()); - } - public Task SaveAsync(AuditLogInfo auditInfo) { - Save(auditInfo); + Logger.LogInformation(auditInfo.ToString()); return Task.FromResult(0); } } diff --git a/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs b/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs index 9d16a6a55c..ef033170f6 100644 --- a/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs +++ b/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs @@ -7,91 +7,93 @@ namespace Microsoft.AspNetCore.Authorization { public static class AbpAuthorizationServiceExtensions { - public static Task AuthorizeAsync(this IAuthorizationService authorizationService, string policyName) + public static async Task AuthorizeAsync(this IAuthorizationService authorizationService, string policyName) { - return AuthorizeAsync( + return await AuthorizeAsync( authorizationService, - authorizationService.AsAbpAuthorizationService().CurrentPrincipal, + null, policyName - ); + ).ConfigureAwait(false); } - public static Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement) + public static async Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement) { - return authorizationService.AuthorizeAsync( + return await authorizationService.AuthorizeAsync( authorizationService.AsAbpAuthorizationService().CurrentPrincipal, resource, requirement - ); + ).ConfigureAwait(false); } - public static Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, AuthorizationPolicy policy) + public static async Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, AuthorizationPolicy policy) { - return authorizationService.AuthorizeAsync( + return await authorizationService.AuthorizeAsync( authorizationService.AsAbpAuthorizationService().CurrentPrincipal, resource, policy - ); + ).ConfigureAwait(false); } - public static Task AuthorizeAsync(this IAuthorizationService authorizationService, AuthorizationPolicy policy) + public static async Task AuthorizeAsync(this IAuthorizationService authorizationService, AuthorizationPolicy policy) { - return AuthorizeAsync(authorizationService, authorizationService.AsAbpAuthorizationService().CurrentPrincipal, + return await AuthorizeAsync( + authorizationService, + null, policy - ); + ).ConfigureAwait(false); } - public static Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, IEnumerable requirements) + public static async Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, IEnumerable requirements) { - return authorizationService.AuthorizeAsync( + return await authorizationService.AuthorizeAsync( authorizationService.AsAbpAuthorizationService().CurrentPrincipal, resource, requirements - ); + ).ConfigureAwait(false); } - public static Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, string policyName) + public static async Task AuthorizeAsync(this IAuthorizationService authorizationService, object resource, string policyName) { - return authorizationService.AuthorizeAsync( + return await authorizationService.AuthorizeAsync( authorizationService.AsAbpAuthorizationService().CurrentPrincipal, resource, policyName - ); + ).ConfigureAwait(false); } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, string policyName) { - return (await authorizationService.AuthorizeAsync(policyName)).Succeeded; + return (await authorizationService.AuthorizeAsync(policyName).ConfigureAwait(false)).Succeeded; } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement) { - return (await authorizationService.AuthorizeAsync(resource, requirement)).Succeeded; + return (await authorizationService.AuthorizeAsync(resource, requirement).ConfigureAwait(false)).Succeeded; } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, object resource, AuthorizationPolicy policy) { - return (await authorizationService.AuthorizeAsync(resource, policy)).Succeeded; + return (await authorizationService.AuthorizeAsync(resource, policy).ConfigureAwait(false)).Succeeded; } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, AuthorizationPolicy policy) { - return (await authorizationService.AuthorizeAsync(policy)).Succeeded; + return (await authorizationService.AuthorizeAsync(policy).ConfigureAwait(false)).Succeeded; } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, object resource, IEnumerable requirements) { - return (await authorizationService.AuthorizeAsync(resource, requirements)).Succeeded; + return (await authorizationService.AuthorizeAsync(resource, requirements).ConfigureAwait(false)).Succeeded; } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, object resource, string policyName) { - return (await authorizationService.AuthorizeAsync(resource, policyName)).Succeeded; + return (await authorizationService.AuthorizeAsync(resource, policyName).ConfigureAwait(false)).Succeeded; } public static async Task CheckAsync(this IAuthorizationService authorizationService, string policyName) { - if (!await authorizationService.IsGrantedAsync(policyName)) + if (!await authorizationService.IsGrantedAsync(policyName).ConfigureAwait(false)) { throw new AbpAuthorizationException("Authorization failed! Given policy has not granted: " + policyName); } @@ -99,7 +101,7 @@ namespace Microsoft.AspNetCore.Authorization public static async Task CheckAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement) { - if (!await authorizationService.IsGrantedAsync(resource, requirement)) + if (!await authorizationService.IsGrantedAsync(resource, requirement).ConfigureAwait(false)) { throw new AbpAuthorizationException("Authorization failed! Given requirement has not granted for given resource: " + resource); } @@ -107,7 +109,7 @@ namespace Microsoft.AspNetCore.Authorization public static async Task CheckAsync(this IAuthorizationService authorizationService, object resource, AuthorizationPolicy policy) { - if (!await authorizationService.IsGrantedAsync(resource, policy)) + if (!await authorizationService.IsGrantedAsync(resource, policy).ConfigureAwait(false)) { throw new AbpAuthorizationException("Authorization failed! Given policy has not granted for given resource: " + resource); } @@ -115,7 +117,7 @@ namespace Microsoft.AspNetCore.Authorization public static async Task CheckAsync(this IAuthorizationService authorizationService, AuthorizationPolicy policy) { - if (!await authorizationService.IsGrantedAsync(policy)) + if (!await authorizationService.IsGrantedAsync(policy).ConfigureAwait(false)) { throw new AbpAuthorizationException("Authorization failed! Given policy has not granted."); } @@ -123,7 +125,7 @@ namespace Microsoft.AspNetCore.Authorization public static async Task CheckAsync(this IAuthorizationService authorizationService, object resource, IEnumerable requirements) { - if (!await authorizationService.IsGrantedAsync(resource, requirements)) + if (!await authorizationService.IsGrantedAsync(resource, requirements).ConfigureAwait(false)) { throw new AbpAuthorizationException("Authorization failed! Given requirements have not granted for given resource: " + resource); } @@ -131,7 +133,7 @@ namespace Microsoft.AspNetCore.Authorization public static async Task CheckAsync(this IAuthorizationService authorizationService, object resource, string policyName) { - if (!await authorizationService.IsGrantedAsync(resource, policyName)) + if (!await authorizationService.IsGrantedAsync(resource, policyName).ConfigureAwait(false)) { throw new AbpAuthorizationException("Authorization failed! Given polist has not granted for given resource: " + resource); } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs index f636877fc1..61454b76e1 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Authorization public override async Task GetPolicyAsync(string policyName) { - var policy = await base.GetPolicyAsync(policyName); + var policy = await base.GetPolicyAsync(policyName).ConfigureAwait(false); if (policy != null) { return policy; diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs index 74314e815d..5c7afbd7c7 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AuthorizationInterceptor.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; -using Volo.Abp.Threading; namespace Volo.Abp.Authorization { @@ -14,16 +13,10 @@ namespace Volo.Abp.Authorization _methodInvocationAuthorizationService = methodInvocationAuthorizationService; } - public override void Intercept(IAbpMethodInvocation invocation) - { - AsyncHelper.RunSync(() => AuthorizeAsync(invocation)); - invocation.Proceed(); - } - public override async Task InterceptAsync(IAbpMethodInvocation invocation) { - await AuthorizeAsync(invocation); - await invocation.ProceedAsync(); + await AuthorizeAsync(invocation).ConfigureAwait(false); + await invocation.ProceedAsync().ConfigureAwait(false); } protected virtual async Task AuthorizeAsync(IAbpMethodInvocation invocation) @@ -32,7 +25,7 @@ namespace Volo.Abp.Authorization new MethodInvocationAuthorizationContext( invocation.Method ) - ); + ).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs index 56baba8ce4..1e063f1f0e 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.Authorization foreach (var authorizationAttribute in GetAuthorizationDataAttributes(context.Method)) { - await CheckAsync(authorizationAttribute); + await CheckAsync(authorizationAttribute).ConfigureAwait(false); } } @@ -74,7 +74,7 @@ namespace Volo.Abp.Authorization } else { - await _authorizationService.CheckAsync(authorizationAttribute.Policy); + await _authorizationService.CheckAsync(authorizationAttribute.Policy).ConfigureAwait(false); } //TODO: What about roles and other props? diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/PermissionRequirementHandler.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/PermissionRequirementHandler.cs index d4ec7c1d3c..89c0a1f71b 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/PermissionRequirementHandler.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/PermissionRequirementHandler.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.Authorization AuthorizationHandlerContext context, PermissionRequirement requirement) { - if (await _permissionChecker.IsGrantedAsync(context.User, requirement.PermissionName)) + if (await _permissionChecker.IsGrantedAsync(context.User, requirement.PermissionName).ConfigureAwait(false)) { context.Succeed(requirement); } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs index d6975e38ec..33aeb568b2 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Authorization.Permissions } return await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, clientId) - ? PermissionGrantResult.Granted +.ConfigureAwait(false) ? PermissionGrantResult.Granted : PermissionGrantResult.Undefined; } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index a87a22fcf5..165a354743 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs @@ -27,9 +27,9 @@ namespace Volo.Abp.Authorization.Permissions PermissionValueProviderManager = permissionValueProviderManager; } - public virtual Task IsGrantedAsync(string name) + public virtual async Task IsGrantedAsync(string name) { - return IsGrantedAsync(PrincipalAccessor.Principal, name); + return await IsGrantedAsync(PrincipalAccessor.Principal, name).ConfigureAwait(false); } public virtual async Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name) @@ -56,7 +56,7 @@ namespace Volo.Abp.Authorization.Permissions continue; } - var result = await provider.CheckAsync(context); + var result = await provider.CheckAsync(context).ConfigureAwait(false); if (result == PermissionGrantResult.Granted) { diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs index b98867a78e..f5322b4f12 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs @@ -27,7 +27,7 @@ namespace Volo.Abp.Authorization.Permissions foreach (var role in roles) { - if (await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, role)) + if (await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, role).ConfigureAwait(false)) { return PermissionGrantResult.Granted; } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs index c7f327c40c..49a1eec366 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Authorization.Permissions } return await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, userId) - ? PermissionGrantResult.Granted +.ConfigureAwait(false) ? PermissionGrantResult.Granted : PermissionGrantResult.Undefined; } } diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs index 0d5c7612b2..96caf956b1 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs @@ -89,7 +89,7 @@ namespace Autofac.Builder foreach (var interceptor in interceptors) { registrationBuilder.InterceptedBy( - typeof(CastleAbpInterceptorAdapter<>).MakeGenericType(interceptor) + typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(interceptor) ); } diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs index ff2d45b2a4..1c1a24ff66 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs @@ -1,6 +1,6 @@ // This software is part of the Autofac IoC container // Copyright © 2015 Autofac Contributors -// http://autofac.org +// https://autofac.org // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -33,19 +33,21 @@ namespace Autofac.Extensions.DependencyInjection /// /// /// - public class AutofacServiceProvider : IServiceProvider, ISupportRequiredService + public class AutofacServiceProvider : IServiceProvider, ISupportRequiredService, IDisposable { - private readonly IComponentContext _componentContext; + private readonly ILifetimeScope _lifetimeScope; + + private bool _disposed = false; /// /// Initializes a new instance of the class. /// - /// - /// The component context from which services should be resolved. + /// + /// The lifetime scope from which services will be resolved. /// - public AutofacServiceProvider(IComponentContext componentContext) + public AutofacServiceProvider(ILifetimeScope lifetimeScope) { - this._componentContext = componentContext; + this._lifetimeScope = lifetimeScope; } /// @@ -66,7 +68,7 @@ namespace Autofac.Extensions.DependencyInjection /// public object GetRequiredService(Type serviceType) { - return this._componentContext.Resolve(serviceType); + return this._lifetimeScope.Resolve(serviceType); } /// @@ -81,7 +83,40 @@ namespace Autofac.Extensions.DependencyInjection /// public object GetService(Type serviceType) { - return this._componentContext.ResolveOptional(serviceType); + return this._lifetimeScope.ResolveOptional(serviceType); + } + + /// + /// Gets the underlying instance of . + /// + public ILifetimeScope LifetimeScope => _lifetimeScope; + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// + /// to release both managed and unmanaged resources; + /// to release only unmanaged resources. + /// + protected virtual void Dispose(bool disposing) + { + if (!this._disposed) + { + this._disposed = true; + if (disposing) + { + this._lifetimeScope.Dispose(); + } + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs index 38a0afb2cd..2b5f6fa7a5 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs @@ -23,7 +23,8 @@ namespace Volo.Abp.BackgroundJobs services.OnRegistred(context => { - if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IBackgroundJob<>))) + if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IBackgroundJob<>)) || + ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IAsyncBackgroundJob<>))) { jobTypes.Add(context.ImplementationType); } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs new file mode 100644 index 0000000000..3c76bd718e --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Volo.Abp.BackgroundJobs +{ + public abstract class AsyncBackgroundJob : IAsyncBackgroundJob + { + //TODO: Add UOW, Localization and other useful properties..? + + public ILogger> Logger { get; set; } + + protected AsyncBackgroundJob() + { + Logger = NullLogger>.Instance; + } + + public abstract Task ExecuteAsync(TArgs args); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobArgsHelper.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobArgsHelper.cs index 284a2cbb42..58199a9659 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobArgsHelper.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobArgsHelper.cs @@ -13,7 +13,8 @@ namespace Volo.Abp.BackgroundJobs continue; } - if (@interface.GetGenericTypeDefinition() != typeof(IBackgroundJob<>)) + if (@interface.GetGenericTypeDefinition() != typeof(IBackgroundJob<>) && + @interface.GetGenericTypeDefinition() != typeof(IAsyncBackgroundJob<>)) { continue; } @@ -27,7 +28,9 @@ namespace Volo.Abp.BackgroundJobs return genericArgs[0]; } - throw new AbpException($"Could not find type of the job args. Ensure that given type implements the {typeof(IBackgroundJob<>).AssemblyQualifiedName} interface. Given job type: {jobType.AssemblyQualifiedName}"); + throw new AbpException($"Could not find type of the job args. " + + $"Ensure that given type implements the {typeof(IBackgroundJob<>).AssemblyQualifiedName} or {typeof(IAsyncBackgroundJob<>).AssemblyQualifiedName} interface. " + + $"Given job type: {jobType.AssemblyQualifiedName}"); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs index df0ec36dd6..c9b5790003 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using System; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs @@ -19,7 +20,7 @@ namespace Volo.Abp.BackgroundJobs Logger = NullLogger.Instance; } - public virtual void Execute(JobExecutionContext context) + public virtual async Task ExecuteAsync(JobExecutionContext context) { var job = context.ServiceProvider.GetService(context.JobType); if (job == null) @@ -27,15 +28,24 @@ namespace Volo.Abp.BackgroundJobs throw new AbpException("The job type is not registered to DI: " + context.JobType); } - var jobExecuteMethod = context.JobType.GetMethod(nameof(IBackgroundJob.Execute)); + var jobExecuteMethod = context.JobType.GetMethod(nameof(IBackgroundJob.Execute)) ?? + context.JobType.GetMethod(nameof(IAsyncBackgroundJob.ExecuteAsync)); if (jobExecuteMethod == null) { - throw new AbpException($"Given job type does not implement {typeof(IBackgroundJob<>).Name}. The job type was: " + context.JobType); + throw new AbpException($"Given job type does not implement {typeof(IBackgroundJob<>).Name} or {typeof(IAsyncBackgroundJob<>).Name}. " + + "The job type was: " + context.JobType); } try { - jobExecuteMethod.Invoke(job, new[] { context.JobArgs }); + if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob.ExecuteAsync)) + { + await ((Task) jobExecuteMethod.Invoke(job, new[] {context.JobArgs})).ConfigureAwait(false); + } + else + { + jobExecuteMethod.Invoke(job, new[] { context.JobArgs }); + } } catch (Exception ex) { diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs new file mode 100644 index 0000000000..262d95d35b --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.BackgroundJobs +{ + /// + /// Defines interface of a background job. + /// + public interface IAsyncBackgroundJob + { + /// + /// Executes the job with the . + /// + /// Job arguments. + Task ExecuteAsync(TArgs args); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJobExecuter.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJobExecuter.cs index 2470b2945b..eaea1764f3 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJobExecuter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJobExecuter.cs @@ -1,7 +1,9 @@ -namespace Volo.Abp.BackgroundJobs +using System.Threading.Tasks; + +namespace Volo.Abp.BackgroundJobs { public interface IBackgroundJobExecuter { - void Execute(JobExecutionContext context); + Task ExecuteAsync(JobExecutionContext context); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs index 4a61aa2845..676a3eaafc 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.Hangfire { @@ -25,7 +26,7 @@ namespace Volo.Abp.BackgroundJobs.Hangfire { var jobType = Options.GetJob(typeof(TArgs)).JobType; var context = new JobExecutionContext(scope.ServiceProvider, jobType, args); - JobExecuter.Execute(context); + AsyncHelper.RunSync(() => JobExecuter.ExecuteAsync(context)); } } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/IJobQueueManager.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/IJobQueueManager.cs index da560d1ed2..8cafb8c247 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/IJobQueueManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/IJobQueueManager.cs @@ -1,9 +1,10 @@ -using Volo.Abp.Threading; +using System.Threading.Tasks; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.RabbitMQ { public interface IJobQueueManager : IRunnable { - IJobQueue Get(); + Task> GetAsync(); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs index f2b00345a1..fb18ca00f9 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs @@ -10,6 +10,7 @@ using Nito.AsyncEx; using RabbitMQ.Client; using RabbitMQ.Client.Events; using Volo.Abp.RabbitMQ; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.RabbitMQ { @@ -71,11 +72,11 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ { CheckDisposed(); - using (await SyncObj.LockAsync()) + using (await SyncObj.LockAsync().ConfigureAwait(false)) { - await EnsureInitializedAsync(); + await EnsureInitializedAsync().ConfigureAwait(false); - await PublishAsync(args, priority, delay); + await PublishAsync(args, priority, delay).ConfigureAwait(false); return null; } @@ -90,9 +91,9 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ return; } - using (await SyncObj.LockAsync()) + using (await SyncObj.LockAsync().ConfigureAwait(false)) { - await EnsureInitializedAsync(); + await EnsureInitializedAsync().ConfigureAwait(false); } } @@ -181,7 +182,7 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ try { - JobExecuter.Execute(context); + AsyncHelper.RunSync(() => JobExecuter.ExecuteAsync(context)); ChannelAccessor.Channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); } catch (BackgroundJobExecutionException) diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueManager.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueManager.cs index 73b7c21d2a..6c50460003 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueManager.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Nito.AsyncEx; using Volo.Abp.DependencyInjection; using Volo.Abp.Threading; @@ -17,6 +18,8 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ protected AbpBackgroundJobOptions Options { get; } + protected SemaphoreSlim SyncSemaphore { get; } + public JobQueueManager( IOptions options, IServiceProvider serviceProvider) @@ -24,6 +27,7 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ ServiceProvider = serviceProvider; Options = options.Value; JobQueues = new ConcurrentDictionary(); + SyncSemaphore = new SemaphoreSlim(1, 1); } public async Task StartAsync(CancellationToken cancellationToken = default) @@ -36,7 +40,7 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ foreach (var jobConfiguration in Options.GetJobs()) { var jobQueue = (IRunnable)ServiceProvider.GetRequiredService(typeof(IJobQueue<>).MakeGenericType(jobConfiguration.ArgsType)); - await jobQueue.StartAsync(cancellationToken); + await jobQueue.StartAsync(cancellationToken).ConfigureAwait(false); JobQueues[jobConfiguration.JobName] = jobQueue; } } @@ -45,26 +49,37 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ { foreach (var jobQueue in JobQueues.Values) { - await jobQueue.StopAsync(cancellationToken); + await jobQueue.StopAsync(cancellationToken).ConfigureAwait(false); } JobQueues.Clear(); } - public IJobQueue Get() + public async Task> GetAsync() { var jobConfiguration = Options.GetJob(typeof(TArgs)); - return (IJobQueue)JobQueues.GetOrAdd(jobConfiguration.JobName, _ => + if (JobQueues.TryGetValue(jobConfiguration.JobName, out var jobQueue)) + { + return (IJobQueue)jobQueue; + } + + using (await SyncSemaphore.LockAsync().ConfigureAwait(false)) { - var jobQueue = (IRunnable) ServiceProvider - .GetRequiredService(typeof(IJobQueue<>) - .MakeGenericType(typeof(TArgs))); + if (JobQueues.TryGetValue(jobConfiguration.JobName, out jobQueue)) + { + return (IJobQueue)jobQueue; + } - AsyncHelper.RunSync(() => jobQueue.StartAsync()); + jobQueue = (IJobQueue)ServiceProvider + .GetRequiredService(typeof(IJobQueue<>).MakeGenericType(typeof(TArgs))); - return jobQueue; - }); + await jobQueue.StartAsync().ConfigureAwait(false); + + JobQueues.TryAdd(jobConfiguration.JobName, jobQueue); + + return (IJobQueue)jobQueue; + } } } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs index c2976e43fb..8945beb6cb 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/RabbitMqBackgroundJobManager.cs @@ -14,14 +14,13 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ _jobQueueManager = jobQueueManager; } - public Task EnqueueAsync( + public async Task EnqueueAsync( TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) { - return _jobQueueManager - .Get() - .EnqueueAsync(args, priority, delay); + var jobQueue = await _jobQueueManager.GetAsync().ConfigureAwait(false); + return await jobQueue.EnqueueAsync(args, priority, delay).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs index 03b5cb73e4..a16690f346 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -9,92 +10,88 @@ using Volo.Abp.Timing; namespace Volo.Abp.BackgroundJobs { - public class BackgroundJobWorker : PeriodicBackgroundWorkerBase, IBackgroundJobWorker + public class BackgroundJobWorker : AsyncPeriodicBackgroundWorkerBase, IBackgroundJobWorker { protected AbpBackgroundJobOptions JobOptions { get; } protected AbpBackgroundJobWorkerOptions WorkerOptions { get; } - protected IServiceScopeFactory ServiceScopeFactory { get; } - public BackgroundJobWorker( AbpTimer timer, IOptions jobOptions, IOptions workerOptions, IServiceScopeFactory serviceScopeFactory) - : base(timer) + : base( + timer, + serviceScopeFactory) { - ServiceScopeFactory = serviceScopeFactory; WorkerOptions = workerOptions.Value; JobOptions = jobOptions.Value; Timer.Period = WorkerOptions.JobPollPeriod; } - protected override void DoWork() + protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) { - using (var scope = ServiceScopeFactory.CreateScope()) - { - var store = scope.ServiceProvider.GetRequiredService(); + var store = workerContext.ServiceProvider.GetRequiredService(); - var waitingJobs = store.GetWaitingJobs(WorkerOptions.MaxJobFetchCount); + var waitingJobs = await store.GetWaitingJobsAsync(WorkerOptions.MaxJobFetchCount).ConfigureAwait(false); - if (!waitingJobs.Any()) - { - return; - } + if (!waitingJobs.Any()) + { + return; + } + + var jobExecuter = workerContext.ServiceProvider.GetRequiredService(); + var clock = workerContext.ServiceProvider.GetRequiredService(); + var serializer = workerContext.ServiceProvider.GetRequiredService(); - var jobExecuter = scope.ServiceProvider.GetRequiredService(); - var clock = scope.ServiceProvider.GetRequiredService(); - var serializer = scope.ServiceProvider.GetRequiredService(); + foreach (var jobInfo in waitingJobs) + { + jobInfo.TryCount++; + jobInfo.LastTryTime = clock.Now; - foreach (var jobInfo in waitingJobs) + try { - jobInfo.TryCount++; - jobInfo.LastTryTime = clock.Now; + var jobConfiguration = JobOptions.GetJob(jobInfo.JobName); + var jobArgs = serializer.Deserialize(jobInfo.JobArgs, jobConfiguration.ArgsType); + var context = new JobExecutionContext(workerContext.ServiceProvider, jobConfiguration.JobType, jobArgs); try { - var jobConfiguration = JobOptions.GetJob(jobInfo.JobName); - var jobArgs = serializer.Deserialize(jobInfo.JobArgs, jobConfiguration.ArgsType); - var context = new JobExecutionContext(scope.ServiceProvider, jobConfiguration.JobType, jobArgs); + await jobExecuter.ExecuteAsync(context).ConfigureAwait(false); - try - { - jobExecuter.Execute(context); + await store.DeleteAsync(jobInfo.Id).ConfigureAwait(false); + } + catch (BackgroundJobExecutionException) + { + var nextTryTime = CalculateNextTryTime(jobInfo, clock); - store.Delete(jobInfo.Id); + if (nextTryTime.HasValue) + { + jobInfo.NextTryTime = nextTryTime.Value; } - catch (BackgroundJobExecutionException) + else { - var nextTryTime = CalculateNextTryTime(jobInfo, clock); - - if (nextTryTime.HasValue) - { - jobInfo.NextTryTime = nextTryTime.Value; - } - else - { - jobInfo.IsAbandoned = true; - } - - TryUpdate(store, jobInfo); + jobInfo.IsAbandoned = true; } + + await TryUpdateAsync(store, jobInfo).ConfigureAwait(false); } - catch (Exception ex) - { - Logger.LogException(ex); - jobInfo.IsAbandoned = true; - TryUpdate(store, jobInfo); - } + } + catch (Exception ex) + { + Logger.LogException(ex); + jobInfo.IsAbandoned = true; + await TryUpdateAsync(store, jobInfo).ConfigureAwait(false); } } } - protected virtual void TryUpdate(IBackgroundJobStore store, BackgroundJobInfo jobInfo) + protected virtual async Task TryUpdateAsync(IBackgroundJobStore store, BackgroundJobInfo jobInfo) { try { - store.Update(jobInfo); + await store.UpdateAsync(jobInfo).ConfigureAwait(false); } catch (Exception updateEx) { diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs index 0994029f70..266bb37fde 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs @@ -32,7 +32,7 @@ namespace Volo.Abp.BackgroundJobs public virtual async Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) { var jobName = BackgroundJobNameAttribute.GetName(); - var jobId = await EnqueueAsync(jobName, args, priority, delay); + var jobId = await EnqueueAsync(jobName, args, priority, delay).ConfigureAwait(false); return jobId.ToString(); } @@ -53,7 +53,7 @@ namespace Volo.Abp.BackgroundJobs jobInfo.NextTryTime = Clock.Now.Add(delay.Value); } - await Store.InsertAsync(jobInfo); + await Store.InsertAsync(jobInfo).ConfigureAwait(false); return jobInfo.Id; } diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs index f909b3846d..839156c225 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/IBackgroundJobStore.cs @@ -9,13 +9,6 @@ namespace Volo.Abp.BackgroundJobs /// public interface IBackgroundJobStore { - /// - /// Gets a BackgroundJobInfo based on the given jobId. - /// - /// The Job Unique Identifier. - /// The BackgroundJobInfo object. - BackgroundJobInfo Find(Guid jobId); - /// /// Gets a BackgroundJobInfo based on the given jobId. /// @@ -23,27 +16,12 @@ namespace Volo.Abp.BackgroundJobs /// The BackgroundJobInfo object. Task FindAsync(Guid jobId); - /// - /// Inserts a background job. - /// - /// Job information. - void Insert(BackgroundJobInfo jobInfo); - /// /// Inserts a background job. /// /// Job information. Task InsertAsync(BackgroundJobInfo jobInfo); - /// - /// Gets waiting jobs. It should get jobs based on these: - /// Conditions: !IsAbandoned And NextTryTime <= Clock.Now. - /// Order by: Priority DESC, TryCount ASC, NextTryTime ASC. - /// Maximum result: . - /// - /// Maximum result count. - List GetWaitingJobs(int maxResultCount); - /// /// Gets waiting jobs. It should get jobs based on these: /// Conditions: !IsAbandoned And NextTryTime <= Clock.Now. @@ -53,24 +31,12 @@ namespace Volo.Abp.BackgroundJobs /// Maximum result count. Task> GetWaitingJobsAsync(int maxResultCount); - /// - /// Deletes a job. - /// - /// The Job Unique Identifier. - void Delete(Guid jobId); - /// /// Deletes a job. /// /// The Job Unique Identifier. Task DeleteAsync(Guid jobId); - /// - /// Updates a job. - /// - /// Job information. - void Update(BackgroundJobInfo jobInfo); - /// /// Updates a job. /// diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs index 30dd7fe090..cafe75b539 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs @@ -23,21 +23,11 @@ namespace Volo.Abp.BackgroundJobs _jobs = new ConcurrentDictionary(); } - public BackgroundJobInfo Find(Guid jobId) - { - return _jobs.GetOrDefault(jobId); - } - public virtual Task FindAsync(Guid jobId) { return Task.FromResult(_jobs.GetOrDefault(jobId)); } - public void Insert(BackgroundJobInfo jobInfo) - { - _jobs[jobInfo.Id] = jobInfo; - } - public virtual Task InsertAsync(BackgroundJobInfo jobInfo) { _jobs[jobInfo.Id] = jobInfo; @@ -45,17 +35,6 @@ namespace Volo.Abp.BackgroundJobs return Task.FromResult(0); } - public List GetWaitingJobs(int maxResultCount) - { - return _jobs.Values - .Where(t => !t.IsAbandoned && t.NextTryTime <= Clock.Now) - .OrderByDescending(t => t.Priority) - .ThenBy(t => t.TryCount) - .ThenBy(t => t.NextTryTime) - .Take(maxResultCount) - .ToList(); - } - public virtual Task> GetWaitingJobsAsync(int maxResultCount) { var waitingJobs = _jobs.Values @@ -69,10 +48,6 @@ namespace Volo.Abp.BackgroundJobs return Task.FromResult(waitingJobs); } - public void Delete(Guid jobId) - { - _jobs.TryRemove(jobId, out _); - } public virtual Task DeleteAsync(Guid jobId) { @@ -80,15 +55,7 @@ namespace Volo.Abp.BackgroundJobs return Task.FromResult(0); } - - public void Update(BackgroundJobInfo jobInfo) - { - if (jobInfo.IsAbandoned) - { - DeleteAsync(jobInfo.Id); - } - } - + public virtual Task UpdateAsync(BackgroundJobInfo jobInfo) { if (jobInfo.IsAbandoned) diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs new file mode 100644 index 0000000000..cd8474e654 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Volo.Abp.Threading; + +namespace Volo.Abp.BackgroundWorkers +{ + public abstract class AsyncPeriodicBackgroundWorkerBase : BackgroundWorkerBase + { + protected IServiceScopeFactory ServiceScopeFactory { get; } + protected AbpTimer Timer { get; } + + protected AsyncPeriodicBackgroundWorkerBase( + AbpTimer timer, + IServiceScopeFactory serviceScopeFactory) + { + ServiceScopeFactory = serviceScopeFactory; + Timer = timer; + Timer.Elapsed += Timer_Elapsed; + } + + public override async Task StartAsync(CancellationToken cancellationToken = default) + { + await base.StartAsync(cancellationToken).ConfigureAwait(false); + Timer.Start(cancellationToken); + } + + public override async Task StopAsync(CancellationToken cancellationToken = default) + { + Timer.Stop(cancellationToken); + await base.StopAsync(cancellationToken).ConfigureAwait(false); + } + + private void Timer_Elapsed(object sender, System.EventArgs e) + { + try + { + using (var scope = ServiceScopeFactory.CreateScope()) + { + AsyncHelper.RunSync( + () => DoWorkAsync(new PeriodicBackgroundWorkerContext(scope.ServiceProvider)) + ); + } + } + catch (Exception ex) + { + Logger.LogException(ex); + } + } + + protected abstract Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerContext.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerContext.cs new file mode 100644 index 0000000000..dc5635ae88 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerContext.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Abp.BackgroundWorkers +{ + public class PeriodicBackgroundWorkerContext + { + public IServiceProvider ServiceProvider { get; } + + public PeriodicBackgroundWorkerContext(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs index a8b884e096..27a0b05173 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs @@ -56,7 +56,7 @@ namespace Volo.Abp.BackgroundWorkers foreach (var worker in _backgroundWorkers) { - await worker.StartAsync(cancellationToken); + await worker.StartAsync(cancellationToken).ConfigureAwait(false); } } @@ -66,7 +66,7 @@ namespace Volo.Abp.BackgroundWorkers foreach (var worker in _backgroundWorkers) { - await worker.StopAsync(cancellationToken); + await worker.StopAsync(cancellationToken).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs index e699e4cbc8..863657ab79 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Volo.Abp.Threading; @@ -11,35 +12,38 @@ namespace Volo.Abp.BackgroundWorkers /// public abstract class PeriodicBackgroundWorkerBase : BackgroundWorkerBase { - protected readonly AbpTimer Timer; + protected IServiceScopeFactory ServiceScopeFactory { get; } + protected AbpTimer Timer { get; } - /// - /// Initializes a new instance of the class. - /// - /// A timer. - protected PeriodicBackgroundWorkerBase(AbpTimer timer) + protected PeriodicBackgroundWorkerBase( + AbpTimer timer, + IServiceScopeFactory serviceScopeFactory) { + ServiceScopeFactory = serviceScopeFactory; Timer = timer; Timer.Elapsed += Timer_Elapsed; } public override async Task StartAsync(CancellationToken cancellationToken = default) { - await base.StartAsync(cancellationToken); + await base.StartAsync(cancellationToken).ConfigureAwait(false); Timer.Start(cancellationToken); } public override async Task StopAsync(CancellationToken cancellationToken = default) { Timer.Stop(cancellationToken); - await base.StopAsync(cancellationToken); + await base.StopAsync(cancellationToken).ConfigureAwait(false); } - + private void Timer_Elapsed(object sender, System.EventArgs e) { try { - DoWork(); + using (var scope = ServiceScopeFactory.CreateScope()) + { + DoWork(new PeriodicBackgroundWorkerContext(scope.ServiceProvider)); + } } catch (Exception ex) { @@ -50,6 +54,6 @@ namespace Volo.Abp.BackgroundWorkers /// /// Periodic works should be done by implementing this method. /// - protected abstract void DoWork(); + protected abstract void DoWork(PeriodicBackgroundWorkerContext workerContext); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index dbcfb184eb..daa64060f7 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -175,7 +175,7 @@ namespace Volo.Abp.Caching cachedBytes = await Cache.GetAsync( NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token) - ); + ).ConfigureAwait(false); } catch (Exception ex) { @@ -250,22 +250,22 @@ namespace Volo.Abp.Caching CancellationToken token = default) { token = CancellationTokenProvider.FallbackToProvider(token); - var value = await GetAsync(key, hideErrors, token); + var value = await GetAsync(key, hideErrors, token).ConfigureAwait(false); if (value != null) { return value; } - using (await SyncSemaphore.LockAsync(token)) + using (await SyncSemaphore.LockAsync(token).ConfigureAwait(false)) { - value = await GetAsync(key, hideErrors, token); + value = await GetAsync(key, hideErrors, token).ConfigureAwait(false); if (value != null) { return value; } - value = await factory(); - await SetAsync(key, value, optionsFactory?.Invoke(), hideErrors, token); + value = await factory().ConfigureAwait(false); + await SetAsync(key, value, optionsFactory?.Invoke(), hideErrors, token).ConfigureAwait(false); } return value; @@ -331,7 +331,7 @@ namespace Volo.Abp.Caching Serializer.Serialize(value), options ?? DefaultCacheOptions, CancellationTokenProvider.FallbackToProvider(token) - ); + ).ConfigureAwait(false); } catch (Exception ex) { @@ -387,7 +387,7 @@ namespace Volo.Abp.Caching try { - await Cache.RefreshAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)); + await Cache.RefreshAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)).ConfigureAwait(false); } catch (Exception ex) { @@ -443,7 +443,7 @@ namespace Volo.Abp.Caching try { - await Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)); + await Cache.RemoveAsync(NormalizeKey(key), CancellationTokenProvider.FallbackToProvider(token)).ConfigureAwait(false); } catch (Exception ex) { diff --git a/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj b/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj index adcf4f8c2f..3d01363064 100644 --- a/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj +++ b/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj @@ -15,6 +15,7 @@ + diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/AbpCastleCoreModule.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/AbpCastleCoreModule.cs index 0f9a10bda1..0cb59767a4 100644 --- a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/AbpCastleCoreModule.cs +++ b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/AbpCastleCoreModule.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.Castle { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddTransient(typeof(CastleAbpInterceptorAdapter<>)); + context.Services.AddTransient(typeof(AbpAsyncDeterminationInterceptor<>)); } } } diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/AbpAsyncDeterminationInterceptor.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/AbpAsyncDeterminationInterceptor.cs new file mode 100644 index 0000000000..4f852ce475 --- /dev/null +++ b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/AbpAsyncDeterminationInterceptor.cs @@ -0,0 +1,15 @@ +using Castle.DynamicProxy; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Castle.DynamicProxy +{ + public class AbpAsyncDeterminationInterceptor : AsyncDeterminationInterceptor + where TInterceptor : IAbpInterceptor + { + public AbpAsyncDeterminationInterceptor(TInterceptor abpInterceptor) + : base(new CastleAsyncAbpInterceptorAdapter(abpInterceptor)) + { + + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs deleted file mode 100644 index edb52aff86..0000000000 --- a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Reflection; -using System.Threading.Tasks; -using Castle.DynamicProxy; -using Volo.Abp.DynamicProxy; -using Volo.Abp.Threading; - -namespace Volo.Abp.Castle.DynamicProxy -{ - public class CastleAbpInterceptorAdapter : IInterceptor - where TInterceptor : IAbpInterceptor - { - private static readonly MethodInfo MethodExecuteWithoutReturnValueAsync = - typeof(CastleAbpInterceptorAdapter) - .GetMethod( - nameof(ExecuteWithoutReturnValueAsync), - BindingFlags.NonPublic | BindingFlags.Instance - ); - - private static readonly MethodInfo MethodExecuteWithReturnValueAsync = - typeof(CastleAbpInterceptorAdapter) - .GetMethod( - nameof(ExecuteWithReturnValueAsync), - BindingFlags.NonPublic | BindingFlags.Instance - ); - - private readonly TInterceptor _abpInterceptor; - - public CastleAbpInterceptorAdapter(TInterceptor abpInterceptor) - { - _abpInterceptor = abpInterceptor; - } - - public void Intercept(IInvocation invocation) - { - var proceedInfo = invocation.CaptureProceedInfo(); - - var method = invocation.MethodInvocationTarget ?? invocation.Method; - - if (method.IsAsync()) - { - InterceptAsyncMethod(invocation, proceedInfo); - } - else - { - InterceptSyncMethod(invocation, proceedInfo); - } - } - - private void InterceptSyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo) - { - _abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation, proceedInfo)); - } - - private void InterceptAsyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo) - { - if (invocation.Method.ReturnType == typeof(Task)) - { - invocation.ReturnValue = MethodExecuteWithoutReturnValueAsync - .Invoke(this, new object[] { invocation, proceedInfo }); - } - else - { - invocation.ReturnValue = MethodExecuteWithReturnValueAsync - .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) - .Invoke(this, new object[] {invocation, proceedInfo}); - } - } - - private async Task ExecuteWithoutReturnValueAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo) - { - await Task.Yield(); - - await _abpInterceptor.InterceptAsync( - new CastleAbpMethodInvocationAdapter(invocation, proceedInfo) - ); - } - - private async Task ExecuteWithReturnValueAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo) - { - await Task.Yield(); - - await _abpInterceptor.InterceptAsync( - new CastleAbpMethodInvocationAdapter(invocation, proceedInfo) - ); - - return await (Task)invocation.ReturnValue; - } - } -} diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs index 0963da406b..7fbc9fdf0a 100644 --- a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs +++ b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs @@ -1,77 +1,26 @@ using System; -using System.Collections.Generic; -using System.Reflection; using System.Threading.Tasks; using Castle.DynamicProxy; using Volo.Abp.DynamicProxy; -using Volo.Abp.Threading; namespace Volo.Abp.Castle.DynamicProxy { - public class CastleAbpMethodInvocationAdapter : IAbpMethodInvocation + public class CastleAbpMethodInvocationAdapter : CastleAbpMethodInvocationAdapterBase, IAbpMethodInvocation { - public object[] Arguments => Invocation.Arguments; - - public IReadOnlyDictionary ArgumentsDictionary => _lazyArgumentsDictionary.Value; - private readonly Lazy> _lazyArgumentsDictionary; - - public Type[] GenericArguments => Invocation.GenericArguments; - - public object TargetObject => Invocation.InvocationTarget ?? Invocation.MethodInvocationTarget; - - public MethodInfo Method => Invocation.MethodInvocationTarget ?? Invocation.Method; - - public object ReturnValue - { - get => _actualReturnValue ?? Invocation.ReturnValue; - set => Invocation.ReturnValue = value; - } - - private object _actualReturnValue; - - protected IInvocation Invocation { get; } protected IInvocationProceedInfo ProceedInfo { get; } + protected Func Proceed { get; } - public CastleAbpMethodInvocationAdapter(IInvocation invocation, IInvocationProceedInfo proceedInfo) + public CastleAbpMethodInvocationAdapter(IInvocation invocation, IInvocationProceedInfo proceedInfo, + Func proceed) + : base(invocation) { - Invocation = invocation; ProceedInfo = proceedInfo; - - _lazyArgumentsDictionary = new Lazy>(GetArgumentsDictionary); + Proceed = proceed; } - public void Proceed() + public override async Task ProceedAsync() { - ProceedInfo.Invoke(); - - if (Invocation.Method.IsAsync()) - { - AsyncHelper.RunSync(() => (Task)Invocation.ReturnValue); - } - } - - public Task ProceedAsync() - { - ProceedInfo.Invoke(); - - _actualReturnValue = Invocation.ReturnValue; - - return Invocation.Method.IsAsync() - ? (Task)_actualReturnValue - : Task.FromResult(_actualReturnValue); - } - - private IReadOnlyDictionary GetArgumentsDictionary() - { - var dict = new Dictionary(); - - var methodParameters = Method.GetParameters(); - for (int i = 0; i < methodParameters.Length; i++) - { - dict[methodParameters[i].Name] = Invocation.Arguments[i]; - } - - return dict; + await Proceed(Invocation, ProceedInfo).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapterBase.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapterBase.cs new file mode 100644 index 0000000000..09609699a8 --- /dev/null +++ b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapterBase.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using Castle.DynamicProxy; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Castle.DynamicProxy +{ + public abstract class CastleAbpMethodInvocationAdapterBase : IAbpMethodInvocation + { + public object[] Arguments => Invocation.Arguments; + + public IReadOnlyDictionary ArgumentsDictionary => _lazyArgumentsDictionary.Value; + private readonly Lazy> _lazyArgumentsDictionary; + + public Type[] GenericArguments => Invocation.GenericArguments; + + public object TargetObject => Invocation.InvocationTarget ?? Invocation.MethodInvocationTarget; + + public MethodInfo Method => Invocation.MethodInvocationTarget ?? Invocation.Method; + + public object ReturnValue { get; set; } + + protected IInvocation Invocation { get; } + + protected CastleAbpMethodInvocationAdapterBase(IInvocation invocation) + { + Invocation = invocation; + _lazyArgumentsDictionary = new Lazy>(GetArgumentsDictionary); + } + + public abstract Task ProceedAsync(); + + private IReadOnlyDictionary GetArgumentsDictionary() + { + var dict = new Dictionary(); + + var methodParameters = Method.GetParameters(); + for (int i = 0; i < methodParameters.Length; i++) + { + dict[methodParameters[i].Name] = Invocation.Arguments[i]; + } + + return dict; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapterWithReturnValue.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapterWithReturnValue.cs new file mode 100644 index 0000000000..bf91102337 --- /dev/null +++ b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapterWithReturnValue.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using Castle.DynamicProxy; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Castle.DynamicProxy +{ + public class CastleAbpMethodInvocationAdapterWithReturnValue : CastleAbpMethodInvocationAdapterBase, IAbpMethodInvocation + { + protected IInvocationProceedInfo ProceedInfo { get; } + protected Func> Proceed { get; } + + public CastleAbpMethodInvocationAdapterWithReturnValue(IInvocation invocation, + IInvocationProceedInfo proceedInfo, + Func> proceed) + : base(invocation) + { + ProceedInfo = proceedInfo; + Proceed = proceed; + } + + public override async Task ProceedAsync() + { + ReturnValue = await Proceed(Invocation, ProceedInfo); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAsyncAbpInterceptorAdapter.cs b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAsyncAbpInterceptorAdapter.cs new file mode 100644 index 0000000000..bd379f442d --- /dev/null +++ b/framework/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAsyncAbpInterceptorAdapter.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using Castle.DynamicProxy; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Castle.DynamicProxy +{ + public class CastleAsyncAbpInterceptorAdapter : AsyncInterceptorBase + where TInterceptor : IAbpInterceptor + { + private readonly TInterceptor _abpInterceptor; + + public CastleAsyncAbpInterceptorAdapter(TInterceptor abpInterceptor) + { + _abpInterceptor = abpInterceptor; + } + + protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func proceed) + { + await _abpInterceptor.InterceptAsync( + new CastleAbpMethodInvocationAdapter(invocation, proceedInfo, proceed) + ).ConfigureAwait(false); + } + + protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func> proceed) + { + var adapter = new CastleAbpMethodInvocationAdapterWithReturnValue(invocation, proceedInfo, proceed); + + await _abpInterceptor.InterceptAsync( + adapter + ).ConfigureAwait(false); + + return (TResult)adapter.ReturnValue; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj index 46f3d32d6a..1ddfe2abec 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj +++ b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj @@ -15,10 +15,12 @@ - + - - + + + + diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index a616d29409..34bf95fdf1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -19,10 +19,6 @@ namespace Volo.Abp.Cli { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - // TODO: workaround until subsequent issues of https://github.com/dotnet/corefx/issues/30166 are resolved - // a permanent fix will probably be published with the release of .net core 3.0: https://github.com/dotnet/corefx/issues/36553 - AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); - Configure(options => { options.Commands["help"] = typeof(HelpCommand); @@ -33,6 +29,7 @@ namespace Volo.Abp.Cli options.Commands["add-module"] = typeof(AddModuleCommand); options.Commands["login"] = typeof(LoginCommand); options.Commands["logout"] = typeof(LogoutCommand); + options.Commands["suite"] = typeof(SuiteCommand); }); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs index 66d16f9305..f91cbfd140 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.Cli.Auth { var configuration = new IdentityClientConfiguration( CliUrls.AccountAbpIo, - "role email abpio abpio_www abpio_commercial", + "role email abpio abpio_www abpio_commercial offline_access", "abp-cli", "1q2w3e*", OidcConstants.GrantTypes.Password, @@ -35,7 +35,7 @@ namespace Volo.Abp.Cli.Auth configuration["[o]abp-organization-name"] = organizationName; } - var accessToken = await AuthenticationService.GetAccessTokenAsync(configuration); + var accessToken = await AuthenticationService.GetAccessTokenAsync(configuration).ConfigureAwait(false); File.WriteAllText(CliPaths.AccessToken, accessToken, Encoding.UTF8); } @@ -45,5 +45,10 @@ namespace Volo.Abp.Cli.Auth FileHelper.DeleteIfExists(CliPaths.AccessToken); return Task.CompletedTask; } + + public static bool IsLoggedIn() + { + return File.Exists(CliPaths.AccessToken); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index f02f03d502..b53327cba3 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -41,7 +41,7 @@ namespace Volo.Abp.Cli { Logger.LogInformation("ABP CLI (https://abp.io)"); - await CheckCliVersionAsync(); + await CheckCliVersionAsync().ConfigureAwait(false); var commandLineArgs = CommandLineArgumentParser.Parse(args); var commandType = CommandSelector.Select(commandLineArgs); @@ -52,7 +52,7 @@ namespace Volo.Abp.Cli try { - await command.ExecuteAsync(commandLineArgs); + await command.ExecuteAsync(commandLineArgs).ConfigureAwait(false); } catch (CliUsageException usageException) { @@ -69,14 +69,14 @@ namespace Volo.Abp.Cli { var assembly = typeof(CliService).Assembly; var toolPath = GetToolPath(assembly); - var currentCliVersion = await GetCurrentCliVersion(toolPath, assembly); + var currentCliVersion = await GetCurrentCliVersion(assembly).ConfigureAwait(false); var updateChannel = GetUpdateChannel(currentCliVersion); Logger.LogInformation($"Version {currentCliVersion} ({updateChannel} channel)"); try { - var latestVersion = await GetLatestVersion(updateChannel); + var latestVersion = await GetLatestVersion(updateChannel).ConfigureAwait(false); if (latestVersion != null && latestVersion > currentCliVersion) { @@ -100,26 +100,25 @@ namespace Volo.Abp.Cli return assembly.Location.Substring(0, assembly.Location.IndexOf(".store", StringComparison.Ordinal)); } - private async Task GetCurrentCliVersion(string toolPath, Assembly assembly) + private static async Task GetCurrentCliVersion(Assembly assembly) { SemanticVersion currentCliVersion = default; - if (!string.IsNullOrEmpty(toolPath)) + + var consoleOutput = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list -g")); + string line; + while ((line = await consoleOutput.ReadLineAsync().ConfigureAwait(false)) != null) { - var consoleOutput = new StringReader(CmdHelper.RunCmdAndGetOutput($"dotnet tool list --tool-path {toolPath}")); - string line; - while ((line = await consoleOutput.ReadLineAsync()) != null) + if (line.StartsWith("volo.abp.cli", StringComparison.InvariantCultureIgnoreCase)) { - if (line.StartsWith("Volo.Abp.Cli", StringComparison.InvariantCultureIgnoreCase)) - { - var version = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1]; + var version = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)[1]; - SemanticVersion.TryParse(version, out currentCliVersion); + SemanticVersion.TryParse(version, out currentCliVersion); - break; - } + break; } } + if (currentCliVersion == null) { // If not a tool executable, fallback to assembly version and treat as dev without updates @@ -156,13 +155,13 @@ namespace Volo.Abp.Cli switch (updateChannel) { case UpdateChannel.Stable: - return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli").ConfigureAwait(false); case UpdateChannel.Prerelease: - return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includePreviews: true); + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includePreviews: true).ConfigureAwait(false); case UpdateChannel.Nightly: - return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true); + return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true).ConfigureAwait(false); default: return default; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs index 3c034d5702..8c4c8c01f2 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs @@ -4,10 +4,26 @@ { #if DEBUG public const string WwwAbpIo = "https://localhost:44328/"; + public const string AccountAbpIo = "https://localhost:44333/"; + + public const string NuGetRootPath = "https://localhost:44373/"; #else public const string WwwAbpIo = "https://abp.io/"; + public const string AccountAbpIo = "https://account.abp.io/"; + + public const string NuGetRootPath = "https://nuget.abp.io/"; #endif + + public static string GetNuGetServiceIndexUrl(string apiKey) + { + return $"{NuGetRootPath}{apiKey}/v3/index.json"; + } + + public static string GetNuGetPackageInfoUrl(string apiKey, string packageId) + { + return $"{NuGetRootPath}{apiKey}/v3/package/{packageId}/index.json"; + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index a7afbfa87d..d8715c2700 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -42,7 +42,7 @@ namespace Volo.Abp.Cli.Commands commandLineArgs.Target, commandLineArgs.Options.GetOrNull(Options.StartupProject.Short, Options.StartupProject.Long), skipDbMigrations - ); + ).ConfigureAwait(false); } public string GetUsageInfo() @@ -75,9 +75,8 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return "Adds a multi-package module to a solution by finding all packages of the module, " + - "finding related projects in the solution and adding each package to the" + - " corresponding project in the solution."; + return "Add a multi-package module to a solution by finding all packages of the module, " + + "finding related projects in the solution and adding each package to the corresponding project in the solution."; } protected virtual string GetSolutionFile(CommandLineArgs commandLineArgs) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs index 211d20d5e1..cbfde5610f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs @@ -37,7 +37,7 @@ namespace Volo.Abp.Cli.Commands await ProjectNugetPackageAdder.AddAsync( GetProjectFile(commandLineArgs), commandLineArgs.Target - ); + ).ConfigureAwait(false); } public string GetUsageInfo() @@ -68,9 +68,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return "Adds a new ABP package to a project by adding related nuget package" + - " as a dependency to the project and adding [DependsOn(...)] attribute to" + - " the module class in the project."; + return "Add a new ABP package to a project by adding related NuGet package dependencies and [DependsOn(...)] attributes."; } protected virtual string GetProjectFile(CommandLineArgs commandLineArgs) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs index 97dfe23944..edd7bd985a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs @@ -79,7 +79,7 @@ namespace Volo.Abp.Cli.Commands gitHubLocalRepositoryPath, commandLineArgs.Options ) - ); + ).ConfigureAwait(false); using (var templateFileStream = new MemoryStream(result.ZipContent)) { @@ -143,7 +143,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return "Downloads the source code of the specified module."; + return "Download the source code of the specified module."; } public static class Options diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs index dd9145e8db..70d5112e95 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/HelpCommand.cs @@ -24,12 +24,19 @@ namespace Volo.Abp.Cli.Commands AbpCliOptions = cliOptions.Value; } - public async Task ExecuteAsync(CommandLineArgs commandLineArgs) + public Task ExecuteAsync(CommandLineArgs commandLineArgs) { if (string.IsNullOrWhiteSpace(commandLineArgs.Target)) { Logger.LogInformation(GetUsageInfo()); - return; + return Task.CompletedTask; + } + + if (!AbpCliOptions.Commands.ContainsKey(commandLineArgs.Target)) + { + Logger.LogWarning($"There is no command named {commandLineArgs.Target}."); + Logger.LogInformation(GetUsageInfo()); + return Task.CompletedTask; } var commandType = AbpCliOptions.Commands[commandLineArgs.Target]; @@ -39,6 +46,8 @@ namespace Volo.Abp.Cli.Commands var command = (IConsoleCommand) scope.ServiceProvider.GetRequiredService(commandType); Logger.LogInformation(command.GetUsageInfo()); } + + return Task.CompletedTask; } public string GetUsageInfo() @@ -82,7 +91,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return string.Empty; + return "Show command line help. Write ` abp help `"; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs index 5efbc358f0..175f45aa75 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs @@ -48,7 +48,7 @@ namespace Volo.Abp.Cli.Commands commandLineArgs.Target, password, commandLineArgs.Options.GetOrNull(Options.Organization.Short, Options.Organization.Long) - ); + ).ConfigureAwait(false); Logger.LogInformation($"Successfully logged in as '{commandLineArgs.Target}'"); } @@ -72,7 +72,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return string.Empty; + return "Sign in to " + CliUrls.AccountAbpIo + "."; } public static class Options diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LogoutCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LogoutCommand.cs index d3024635fb..464d40e74d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LogoutCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LogoutCommand.cs @@ -31,7 +31,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return string.Empty; + return "Sign out from " + CliUrls.AccountAbpIo + "."; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 44c1789907..1314f058c2 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -97,7 +97,7 @@ namespace Volo.Abp.Cli.Commands gitHubLocalRepositoryPath, commandLineArgs.Options ) - ); + ).ConfigureAwait(false); using (var templateFileStream = new MemoryStream(result.ZipContent)) { @@ -165,7 +165,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(" abp new Acme.BookStore -d mongodb"); sb.AppendLine(" abp new Acme.BookStore -d mongodb -o d:\\my-project"); sb.AppendLine(" abp new Acme.BookStore -t module"); - sb.AppendLine(" abp new Acme.BookStore -t module no-ui"); + sb.AppendLine(" abp new Acme.BookStore -t module --no-ui"); sb.AppendLine(" abp new Acme.BookStore --local-framework-ref --abp-path \"D:\\github\\abp\""); sb.AppendLine(""); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); @@ -175,7 +175,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return "Generates a new solution based on the ABP startup templates."; + return "Generate a new solution based on the ABP startup templates."; } protected virtual DatabaseProvider GetDatabaseProvider(CommandLineArgs commandLineArgs) @@ -246,4 +246,4 @@ namespace Volo.Abp.Cli.Commands } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs new file mode 100644 index 0000000000..1697489d71 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs @@ -0,0 +1,156 @@ +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.Licensing; +using Volo.Abp.Cli.Utils; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class SuiteCommand : IConsoleCommand, ITransientDependency + { + private const string SuitePackageName = "Volo.Abp.Suite"; + public ILogger Logger { get; set; } + private readonly IApiKeyService _apiKeyService; + + public SuiteCommand(IApiKeyService apiKeyService) + { + _apiKeyService = apiKeyService; + Logger = NullLogger.Instance; + } + + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + var operationType = NamespaceHelper.NormalizeNamespace(commandLineArgs.Target); + + switch (operationType) + { + case "": + case null: + RunSuite(); + break; + + case "install": + Logger.LogInformation("Installing ABP Suite..."); + await InstallSuiteAsync().ConfigureAwait(false); + break; + + case "update": + Logger.LogInformation("Updating ABP Suite..."); + await UpdateSuiteAsync().ConfigureAwait(false); + break; + + case "remove": + Logger.LogInformation("Removing ABP Suite..."); + RemoveSuite(); + break; + } + } + + private async Task InstallSuiteAsync() + { + var nugetIndexUrl = await GetNuGetIndexUrlAsync().ConfigureAwait(false); + + if (nugetIndexUrl == null) + { + return; + } + + var result = CmdHelper.RunCmd("dotnet tool install " + SuitePackageName + " --add-source " + nugetIndexUrl + " -g"); + + if (result == 0) + { + Logger.LogInformation("ABP Suite has been successfully installed."); + Logger.LogInformation("You can run it with the CLI command \"abp suite\""); + } + } + + private async Task UpdateSuiteAsync() + { + var nugetIndexUrl = await GetNuGetIndexUrlAsync().ConfigureAwait(false); + + if (nugetIndexUrl == null) + { + return; + } + + CmdHelper.RunCmd("dotnet tool update " + SuitePackageName + " --add-source " + nugetIndexUrl + " -g"); + } + + private static void RemoveSuite() + { + CmdHelper.RunCmd("dotnet tool uninstall " + SuitePackageName + " -g"); + } + + private void RunSuite() + { + try + { + if (!GlobalToolHelper.IsGlobalToolInstalled("abp-suite")) + { + Logger.LogWarning("ABP Suite is not installed! To install it you can run the command: \"abp suite install\""); + return; + } + } + catch (Exception ex) + { + Logger.LogWarning("Couldn't check ABP Suite installed status: " + ex.Message); + } + + CmdHelper.RunCmd("abp-suite"); + } + + private async Task GetNuGetIndexUrlAsync() + { + var apiKeyResult = await _apiKeyService.GetApiKeyOrNullAsync().ConfigureAwait(false); + + if (apiKeyResult == null || string.IsNullOrEmpty(apiKeyResult.ApiKey)) + { + Logger.LogError("Couldn't retrieve your NuGet API key!"); + Logger.LogWarning(File.Exists(CliPaths.AccessToken) + ? "Make sure you have an active session and license on commercial.abp.io. To re-sign in you can use the CLI command \"abp login \"." + : "You are not signed in to commercial.abp.io. Use the CLI command \"abp login \" to sign in."); + + return null; + } + + return CliUrls.GetNuGetServiceIndexUrl(apiKeyResult.ApiKey); + } + + public string GetUsageInfo() + { + var sb = new StringBuilder(); + + sb.AppendLine(""); + sb.AppendLine("Usage:"); + sb.AppendLine(""); + sb.AppendLine(" abp suite [options]"); + sb.AppendLine(""); + sb.AppendLine("Options:"); + sb.AppendLine(""); + sb.AppendLine(" (run ABP Suite)"); + sb.AppendLine("install (install ABP Suite as a dotnet global tool)"); + sb.AppendLine("update (update ABP Suite to the latest)"); + sb.AppendLine("remove (uninstall ABP Suite)"); + sb.AppendLine(""); + sb.AppendLine("Examples:"); + sb.AppendLine(""); + sb.AppendLine(" abp suite"); + sb.AppendLine(" abp suite install"); + sb.AppendLine(" abp suite update"); + sb.AppendLine(" abp suite remove"); + sb.AppendLine(""); + + return sb.ToString(); + } + + public string GetShortDescription() + { + return "Install, update, remove or start ABP Suite. See https://commercial.abp.io/tools/suite."; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs index a1775bb987..166720c64e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs @@ -5,12 +5,9 @@ using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; using Volo.Abp.Cli.Args; -using Volo.Abp.Cli.ProjectBuilding.Analyticses; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.DependencyInjection; -using Volo.Abp.Json; namespace Volo.Abp.Cli.Commands { @@ -20,21 +17,12 @@ namespace Volo.Abp.Cli.Commands private readonly VoloNugetPackagesVersionUpdater _nugetPackagesVersionUpdater; private readonly NpmPackagesUpdater _npmPackagesUpdater; - private readonly ICliAnalyticsCollect _cliAnalyticsCollect; - private readonly AbpCliOptions _options; - private readonly IJsonSerializer _jsonSerializer; public UpdateCommand(VoloNugetPackagesVersionUpdater nugetPackagesVersionUpdater, - NpmPackagesUpdater npmPackagesUpdater, - ICliAnalyticsCollect cliAnalyticsCollect, - IJsonSerializer jsonSerializer, - IOptions options) + NpmPackagesUpdater npmPackagesUpdater) { _nugetPackagesVersionUpdater = nugetPackagesVersionUpdater; _npmPackagesUpdater = npmPackagesUpdater; - _cliAnalyticsCollect = cliAnalyticsCollect; - _jsonSerializer = jsonSerializer; - _options = options.Value; Logger = NullLogger.Instance; } @@ -44,24 +32,18 @@ namespace Volo.Abp.Cli.Commands var updateNpm = commandLineArgs.Options.ContainsKey(Options.Packages.Npm); var updateNuget = commandLineArgs.Options.ContainsKey(Options.Packages.NuGet); - var directory = commandLineArgs.Options.GetOrNull(Options.SolutionPath.Short, Options.SolutionPath.Long); - if (directory == null) - { - directory = Directory.GetCurrentDirectory(); - } + var directory = commandLineArgs.Options.GetOrNull(Options.SolutionPath.Short, Options.SolutionPath.Long) ?? + Directory.GetCurrentDirectory(); - var both = (updateNuget && updateNpm) || (!updateNuget && !updateNpm); - - if (updateNuget || both) + if (updateNuget || !updateNpm) { - await UpdateNugetPackages(commandLineArgs, directory); + await UpdateNugetPackages(commandLineArgs, directory).ConfigureAwait(false); } - if (updateNpm || both) + if (updateNpm || !updateNuget) { UpdateNpmPackages(directory); } - } private void UpdateNpmPackages(string directory) @@ -80,7 +62,7 @@ namespace Volo.Abp.Cli.Commands { var solutionName = Path.GetFileName(solution).RemovePostFix(".sln"); - await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, includePreviews); + await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, includePreviews).ConfigureAwait(false); Logger.LogInformation($"Volo packages are updated in {solutionName} solution."); return; @@ -92,7 +74,7 @@ namespace Volo.Abp.Cli.Commands { var projectName = Path.GetFileName(project).RemovePostFix(".csproj"); - await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, includePreviews); + await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, includePreviews).ConfigureAwait(false); Logger.LogInformation($"Volo packages are updated in {projectName} project."); return; @@ -131,8 +113,7 @@ namespace Volo.Abp.Cli.Commands public string GetShortDescription() { - return "Automatically updates all ABP related NuGet packages and NPM packages in a" + - " solution or project to the latest versions"; + return "Update all ABP related NuGet packages and NPM packages in a solution or project to the latest version."; } public static class Options diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs index bc0b39a85a..ca1a23fcfc 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs @@ -3,27 +3,42 @@ using System.IO; using System.Net.Http; using System.Text; using IdentityModel.Client; +using Volo.Abp.Cli.Auth; namespace Volo.Abp.Cli.Http { public class CliHttpClient : HttpClient { + public static TimeSpan DefaultTimeout { get; set; } = TimeSpan.FromMinutes(1); + public CliHttpClient(TimeSpan? timeout = null) : base(new CliHttpClientHandler()) { - Timeout = timeout ?? TimeSpan.FromMinutes(1); + Timeout = timeout ?? DefaultTimeout; AddAuthentication(this); } + public CliHttpClient(bool setBearerToken) : base(new CliHttpClientHandler()) + { + Timeout = DefaultTimeout; + + if (setBearerToken) + { + AddAuthentication(this); + } + } + private static void AddAuthentication(HttpClient client) { - if (File.Exists(CliPaths.AccessToken)) + if (!AuthService.IsLoggedIn()) + { + return; + } + + var accessToken = File.ReadAllText(CliPaths.AccessToken, Encoding.UTF8); + if (!accessToken.IsNullOrEmpty()) { - var accessToken = File.ReadAllText(CliPaths.AccessToken, Encoding.UTF8); - if (!accessToken.IsNullOrEmpty()) - { - client.SetBearerToken(accessToken); - } + client.SetBearerToken(accessToken); } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs index c8f221b73c..a22b6bba4a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs @@ -1,5 +1,14 @@ using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Polly; +using Polly.Extensions.Http; +using Volo.Abp.Cli.Auth; using Volo.Abp.Cli.Http; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; @@ -10,32 +19,75 @@ namespace Volo.Abp.Cli.Licensing public class AbpIoApiKeyService : IApiKeyService, ITransientDependency { protected IJsonSerializer JsonSerializer { get; } - protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } + private readonly ILogger _logger; + private DeveloperApiKeyResult _apiKeyResult = null; - public AbpIoApiKeyService(IJsonSerializer jsonSerializer, IRemoteServiceExceptionHandler remoteServiceExceptionHandler) + public AbpIoApiKeyService(IJsonSerializer jsonSerializer, IRemoteServiceExceptionHandler remoteServiceExceptionHandler, ILogger logger) { JsonSerializer = jsonSerializer; RemoteServiceExceptionHandler = remoteServiceExceptionHandler; + _logger = logger; } - public async Task GetApiKeyOrNullAsync() + public async Task GetApiKeyOrNullAsync(bool invalidateCache = false) { - using (var client = new CliHttpClient()) + if (!AuthService.IsLoggedIn()) { - var url = $"{CliUrls.WwwAbpIo}api/license/api-key"; + return null; + } - var response = await client.GetAsync(url); + if (invalidateCache) + { + _apiKeyResult = null; + } + + if (_apiKeyResult != null) + { + return _apiKeyResult; + } + + var url = $"{CliUrls.WwwAbpIo}api/license/api-key"; + + using (var client = new CliHttpClient()) + { + var response = await HttpPolicyExtensions + .HandleTransientHttpError() + .OrResult(msg => !msg.IsSuccessStatusCode) + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(3), + TimeSpan.FromSeconds(7) + }, + (responseMessage, timeSpan, retryCount, context) => + { + if (responseMessage.Exception != null) + { + _logger.LogWarning( + $"{retryCount}. request attempt failed to {url} with an error: \"{responseMessage.Exception.Message}\". " + + $"Waiting {timeSpan.TotalSeconds} secs for the next try..."); + } + else if (responseMessage.Result != null) + { + _logger.LogWarning( + $"{retryCount}. request attempt failed {url} with {(int)responseMessage.Result.StatusCode}-{responseMessage.Result.ReasonPhrase}. " + + $"Waiting {timeSpan.TotalSeconds} secs for the next try..."); + } + }) + .ExecuteAsync(async () => await client.GetAsync(url).ConfigureAwait(false)).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); } - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response).ConfigureAwait(false); + + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var apiKeyResult = JsonSerializer.Deserialize(responseContent); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(responseContent); + return apiKeyResult; } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/DeveloperApiKeyResult.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/DeveloperApiKeyResult.cs index 0b1fe54c2f..481aa6f404 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/DeveloperApiKeyResult.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/DeveloperApiKeyResult.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.Cli.Licensing public bool HasActiveLicense { get; set; } public string OrganizationName { get; set; } public string ApiKey { get; set; } - public DateTime LicenseEndTime { get; set; } + public DateTime? LicenseEndTime { get; set; } public string LicenseCode { get; set; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/IApiKeyService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/IApiKeyService.cs index 23ff81555a..8638472e5c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/IApiKeyService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/IApiKeyService.cs @@ -4,6 +4,6 @@ namespace Volo.Abp.Cli.Licensing { public interface IApiKeyService { - Task GetApiKeyOrNullAsync(); + Task GetApiKeyOrNullAsync(bool invalidateCache = false); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs index 700303006b..37d487f106 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs @@ -2,10 +2,19 @@ using Newtonsoft.Json; using NuGet.Versioning; using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Net; +using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Polly; +using Polly.Extensions.Http; using Volo.Abp.Cli.Http; +using Volo.Abp.Cli.Licensing; using Volo.Abp.Cli.ProjectBuilding; +using Volo.Abp.Cli.ProjectModification; using Volo.Abp.DependencyInjection; using Volo.Abp.Json; using Volo.Abp.Threading; @@ -14,37 +23,54 @@ namespace Volo.Abp.Cli.NuGet { public class NuGetService : ITransientDependency { + public ILogger Logger { get; set; } protected IJsonSerializer JsonSerializer { get; } - protected ICancellationTokenProvider CancellationTokenProvider { get; } - protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } + private readonly IApiKeyService _apiKeyService; public NuGetService( IJsonSerializer jsonSerializer, IRemoteServiceExceptionHandler remoteServiceExceptionHandler, - ICancellationTokenProvider cancellationTokenProvider) + ICancellationTokenProvider cancellationTokenProvider, IApiKeyService apiKeyService) { JsonSerializer = jsonSerializer; RemoteServiceExceptionHandler = remoteServiceExceptionHandler; CancellationTokenProvider = cancellationTokenProvider; + _apiKeyService = apiKeyService; + Logger = NullLogger.Instance; } public async Task GetLatestVersionOrNullAsync(string packageId, bool includePreviews = false, bool includeNightly = false) { - using (var client = new CliHttpClient()) + var url = includeNightly ? + $"https://www.myget.org/F/abp-nightly/api/v3/flatcontainer/{packageId.ToLowerInvariant()}/index.json" : + $"https://api.nuget.org/v3-flatcontainer/{packageId.ToLowerInvariant()}/index.json"; + + + using (var client = new CliHttpClient(setBearerToken: false)) { - var url = includeNightly ? - $"https://www.myget.org/F/abp-nightly/api/v3/flatcontainer/{packageId.ToLowerInvariant()}/index.json" : - $"https://api.nuget.org/v3-flatcontainer/{packageId.ToLowerInvariant()}/index.json"; + var responseMessage = await GetHttpResponseMessageWithRetryAsync(client, url).ConfigureAwait(false); - var responseMessage = await client.GetAsync(url, CancellationTokenProvider.Token); + if (responseMessage.StatusCode == HttpStatusCode.NotFound) + { + var commercialNuGetUrl = await GetNuGetUrlForCommercialPackage(packageId).ConfigureAwait(false); + responseMessage = await GetHttpResponseMessageWithRetryAsync(client, commercialNuGetUrl).ConfigureAwait(false); + } + + if (!responseMessage.IsSuccessStatusCode) + { + throw new Exception($"ERROR: Remote server returns '{responseMessage.StatusCode}'"); + } - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage).ConfigureAwait(false); - var result = await responseMessage.Content.ReadAsStringAsync(); + var responseContent = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); - var versions = JsonSerializer.Deserialize(result).Versions.Select(x => SemanticVersion.Parse(x)); + var versions = JsonSerializer + .Deserialize(responseContent) + .Versions + .Select(SemanticVersion.Parse); if (!includePreviews && !includeNightly) { @@ -56,6 +82,42 @@ namespace Volo.Abp.Cli.NuGet } } + private async Task GetNuGetUrlForCommercialPackage(string packageId) + { + var apiKeyResult = await _apiKeyService.GetApiKeyOrNullAsync(); + return CliUrls.GetNuGetPackageInfoUrl(apiKeyResult.ApiKey, packageId); + } + + private async Task GetHttpResponseMessageWithRetryAsync(HttpClient client, string url) + { + return await HttpPolicyExtensions + .HandleTransientHttpError() + .OrResult(msg => !msg.IsSuccessStatusCode) + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(3), + TimeSpan.FromSeconds(7) + }, + (responseMessage, timeSpan, retryCount, context) => + { + if (responseMessage.Exception != null) + { + Logger.LogWarning( + $"{retryCount}. HTTP request attempt failed to {url} with an error: HTTP {(int)responseMessage.Result.StatusCode}-{responseMessage.Exception.Message}. " + + $"Waiting {timeSpan.TotalSeconds} secs for the next try..."); + } + else if (responseMessage.Result != null) + { + Logger.LogWarning( + $"{retryCount}. HTTP request attempt failed to {url} with an error: {(int)responseMessage.Result.StatusCode}-{responseMessage.Result.ReasonPhrase}. " + + $"Waiting {timeSpan.TotalSeconds} secs for the next try..."); + } + }) + .ExecuteAsync(async () => await client.GetAsync(url, CancellationTokenProvider.Token)); + } + + public class NuGetVersionResultDto { [JsonProperty("versions")] diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs index fd0a0e5246..a422f0ff44 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs @@ -49,7 +49,7 @@ namespace Volo.Abp.Cli.ProjectBuilding string version = null) { - var latestVersion = await GetLatestSourceCodeVersionAsync(name, type); + var latestVersion = await GetLatestSourceCodeVersionAsync(name, type).ConfigureAwait(false); if (version == null) { version = latestVersion; @@ -73,7 +73,7 @@ namespace Volo.Abp.Cli.ProjectBuilding Type = type, Version = version } - ); + ).ConfigureAwait(false); if (Options.CacheTemplates) { @@ -98,11 +98,11 @@ namespace Volo.Abp.Cli.ProjectBuilding MimeTypes.Application.Json ), CancellationTokenProvider.Token - ); + ).ConfigureAwait(false); - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response).ConfigureAwait(false); - var result = await response.Content.ReadAsStringAsync(); + var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); return JsonSerializer.Deserialize(result).Version; } @@ -118,11 +118,11 @@ namespace Volo.Abp.Cli.ProjectBuilding $"{CliUrls.WwwAbpIo}api/download/{input.Type}/", new StringContent(postData, Encoding.UTF8, MimeTypes.Application.Json), CancellationTokenProvider.Token - ); + ).ConfigureAwait(false); - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage).ConfigureAwait(false); - return await responseMessage.Content.ReadAsByteArrayAsync(); + return await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs index fdfbb8b5d3..79fc70cfcc 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Analyticses/CliAnalyticsCollect.cs @@ -38,12 +38,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Analyticses $"{CliUrls.WwwAbpIo}api/clianalytics/collect", new StringContent(postData, Encoding.UTF8, MimeTypes.Application.Json), _cancellationTokenProvider.Token - ); + ).ConfigureAwait(false); if (!responseMessage.IsSuccessStatusCode) { var exceptionMessage = "Remote server returns '" + (int)responseMessage.StatusCode + "-" + responseMessage.ReasonPhrase + "'. "; - var remoteServiceErrorMessage = await _remoteServiceExceptionHandler.GetAbpRemoteServiceErrorAsync(responseMessage); + var remoteServiceErrorMessage = await _remoteServiceExceptionHandler.GetAbpRemoteServiceErrorAsync(responseMessage).ConfigureAwait(false); if (remoteServiceErrorMessage != null) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveFolderStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveFolderStep.cs index ddf7010dd7..636175f0b1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveFolderStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveFolderStep.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { @@ -14,7 +15,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps public override void Execute(ProjectBuildContext context) { //Remove the folder content - var folderPathWithSlash = _folderPath + "/"; + var folderPathWithSlash = _folderPath.EnsureEndsWith('/'); context.Files.RemoveAll(file => file.Name.StartsWith(folderPathWithSlash)); //Remove the folder diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs index 10b3a07172..8f8310977e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleInfoProvider.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.Cli.ProjectBuilding public async Task GetAsync(string name) { - var moduleList = await GetModuleListAsync(); + var moduleList = await GetModuleListAsync().ConfigureAwait(false); var module = moduleList.FirstOrDefault(m => m.Name == name); @@ -47,10 +47,10 @@ namespace Volo.Abp.Cli.ProjectBuilding var responseMessage = await client.GetAsync( $"{CliUrls.WwwAbpIo}api/download/modules/", CancellationTokenProvider.Token - ); + ).ConfigureAwait(false); - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); - var result = await responseMessage.Content.ReadAsStringAsync(); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage).ConfigureAwait(false); + var result = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); return JsonSerializer.Deserialize>(result); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs index 48f109e1d3..f853a9ec15 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs @@ -43,15 +43,15 @@ namespace Volo.Abp.Cli.ProjectBuilding public async Task BuildAsync(ProjectBuildArgs args) { - var moduleInfo = await GetModuleInfoAsync(args); + var moduleInfo = await GetModuleInfoAsync(args).ConfigureAwait(false); var templateFile = await SourceCodeStore.GetAsync( args.TemplateName, SourceCodeTypes.Module, args.Version - ); + ).ConfigureAwait(false); - var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync(); + var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync().ConfigureAwait(false); if (apiKeyResult?.ApiKey != null) { args.ExtraProperties["api-key"] = apiKeyResult.ApiKey; @@ -96,14 +96,14 @@ namespace Volo.Abp.Cli.ProjectBuilding ProjectName = null, TemplateName = args.TemplateName, TemplateVersion = templateFile.Version - }); + }).ConfigureAwait(false); return new ProjectBuildResult(context.Result.ZipContent, args.TemplateName); } private async Task GetModuleInfoAsync(ProjectBuildArgs args) { - return await ModuleInfoProvider.GetAsync(args.TemplateName); + return await ModuleInfoProvider.GetAsync(args.TemplateName).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs index fe41577583..8a1af93f23 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/RemoteServiceExceptionHandler.cs @@ -32,9 +32,10 @@ namespace Volo.Abp.Cli.ProjectBuilding return; } - var exceptionMessage = "Remote server returns '" + (int)responseMessage.StatusCode + "-" + responseMessage.ReasonPhrase + "'. "; + var exceptionMessage = "Remote server returns '" + (int) responseMessage.StatusCode + "-" + + responseMessage.ReasonPhrase + "'. "; - var remoteServiceErrorMessage = await GetAbpRemoteServiceErrorAsync(responseMessage); + var remoteServiceErrorMessage = await GetAbpRemoteServiceErrorAsync(responseMessage).ConfigureAwait(false); if (remoteServiceErrorMessage != null) { exceptionMessage += remoteServiceErrorMessage; @@ -45,10 +46,18 @@ namespace Volo.Abp.Cli.ProjectBuilding public async Task GetAbpRemoteServiceErrorAsync(HttpResponseMessage responseMessage) { - var errorResult = _jsonSerializer.Deserialize - ( - await responseMessage.Content.ReadAsStringAsync() - ); + RemoteServiceErrorResponse errorResult; + try + { + errorResult = _jsonSerializer.Deserialize + ( + await responseMessage.Content.ReadAsStringAsync() +.ConfigureAwait(false)); + } + catch (JsonReaderException) + { + return null; + } if (errorResult?.Error == null) { @@ -82,7 +91,8 @@ namespace Volo.Abp.Cli.ProjectBuilding for (var i = 0; i < errorResult.Error.ValidationErrors.Length; i++) { var validationError = errorResult.Error.ValidationErrors[i]; - sbError.AppendLine("Validation error #" + i + ": " + validationError.Message + " - Members: " + validationError.Members.JoinAsString(", ") + "."); + sbError.AppendLine("Validation error #" + i + ": " + validationError.Message + " - Members: " + + validationError.Members.JoinAsString(", ") + "."); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs index 9d31e10200..87c399181d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs @@ -51,9 +51,9 @@ namespace Volo.Abp.Cli.ProjectBuilding args.TemplateName, SourceCodeTypes.Template, args.Version - ); + ).ConfigureAwait(false); - var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync(); + var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync().ConfigureAwait(false); if (apiKeyResult?.ApiKey != null) { args.ExtraProperties["api-key"] = apiKeyResult.ApiKey; @@ -103,7 +103,7 @@ namespace Volo.Abp.Cli.ProjectBuilding ProjectName = args.SolutionName.FullName, TemplateName = args.TemplateName, TemplateVersion = templateFile.Version - }); + }).ConfigureAwait(false); return new ProjectBuildResult(context.Result.ZipContent, args.SolutionName.ProjectName); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Module/ModuleTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Module/ModuleTemplateBase.cs index 09b75ac0e2..3faf920ab0 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Module/ModuleTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Module/ModuleTemplateBase.cs @@ -43,6 +43,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Module "MyCompanyName.MyProjectName.Web.Unified", projectFolderPath: "/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified" )); + + steps.Add(new RemoveFolderStep("/angular")); } private void RandomizeSslPorts(ProjectBuildContext context, List steps) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs index 66467bfa36..9af114dfff 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NuGetPackageTarget.cs @@ -2,6 +2,7 @@ { public enum NuGetPackageTarget : byte { + Undefined = 0, DomainShared = 1, Domain = 2, ApplicationContracts = 3, diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs index 9c6edf479d..9d155ba079 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using JetBrains.Annotations; namespace Volo.Abp.Cli.ProjectModification { public static class ProjectFinder { + [CanBeNull] public static string FindNuGetTargetProjectFile(string[] projectFiles, NuGetPackageTarget target) { if (!projectFiles.Any()) @@ -40,7 +42,7 @@ namespace Volo.Abp.Cli.ProjectModification case NuGetPackageTarget.HttpApiClient: return FindProjectEndsWith(projectFiles, assemblyNames, ".HttpApi.Client"); default: - throw new ApplicationException($"{nameof(NuGetPackageTarget)}.{target} has not implemented!"); + return null; } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs index 1bacd7cd61..76b7584ae8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs @@ -45,10 +45,10 @@ namespace Volo.Abp.Cli.ProjectModification await AddAsync( projectFile, await FindNugetPackageInfoAsync(packageName) - ); +.ConfigureAwait(false)).ConfigureAwait(false); } - public async Task AddAsync(string projectFile, NugetPackageInfo package) + public Task AddAsync(string projectFile, NugetPackageInfo package) { using (DirectoryHelper.ChangeCurrentDirectory(Path.GetDirectoryName(projectFile))) { @@ -71,6 +71,8 @@ namespace Volo.Abp.Cli.ProjectModification Logger.LogInformation("Successfully installed."); } + + return Task.CompletedTask; } protected virtual async Task FindNugetPackageInfoAsync(string moduleName) @@ -79,7 +81,7 @@ namespace Volo.Abp.Cli.ProjectModification { var url = $"{CliUrls.WwwAbpIo}api/app/nugetPackage/byName/?name=" + moduleName; - var response = await client.GetAsync(url); + var response = await client.GetAsync(url).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { @@ -88,10 +90,10 @@ namespace Volo.Abp.Cli.ProjectModification throw new CliUsageException($"'{moduleName}' nuget package could not be found!"); } - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response).ConfigureAwait(false); } - var responseContent = await response.Content.ReadAsStringAsync(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); return JsonSerializer.Deserialize(responseContent); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index 5950872419..10191678aa 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -57,7 +57,7 @@ namespace Volo.Abp.Cli.ProjectModification Check.NotNull(solutionFile, nameof(solutionFile)); Check.NotNull(moduleName, nameof(moduleName)); - var module = await FindModuleInfoAsync(moduleName); + var module = await FindModuleInfoAsync(moduleName).ConfigureAwait(false); Logger.LogInformation($"Installing module '{module.Name}' to the solution '{Path.GetFileNameWithoutExtension(solutionFile)}'"); @@ -68,11 +68,11 @@ namespace Volo.Abp.Cli.ProjectModification var targetProjectFile = ProjectFinder.FindNuGetTargetProjectFile(projectFiles, nugetPackage.Target); if (targetProjectFile == null) { - Logger.LogDebug($"Target project is not available for NuGet package '{nugetPackage.Name}'"); + Logger.LogDebug($"Target project is not available for this NuGet package '{nugetPackage.Name}'"); continue; } - await ProjectNugetPackageAdder.AddAsync(targetProjectFile, nugetPackage); + await ProjectNugetPackageAdder.AddAsync(targetProjectFile, nugetPackage).ConfigureAwait(false); } if (!module.NpmPackages.IsNullOrEmpty()) @@ -86,7 +86,7 @@ namespace Volo.Abp.Cli.ProjectModification { foreach (var npmPackage in module.NpmPackages.Where(p => p.ApplicationType.HasFlag(NpmApplicationType.Mvc))) { - await ProjectNpmPackageAdder.AddAsync(Path.GetDirectoryName(targetProject), npmPackage); + await ProjectNpmPackageAdder.AddAsync(Path.GetDirectoryName(targetProject), npmPackage).ConfigureAwait(false); } } } @@ -106,6 +106,11 @@ namespace Volo.Abp.Cli.ProjectModification return; } + if (string.IsNullOrWhiteSpace(startupProject)) + { + startupProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrator.csproj")); + } + var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj")); if (dbMigrationsProject == null) @@ -137,7 +142,7 @@ namespace Volo.Abp.Cli.ProjectModification { var url = $"{CliUrls.WwwAbpIo}api/app/module/byName/?name=" + moduleName; - var response = await client.GetAsync(url); + var response = await client.GetAsync(url).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { @@ -146,10 +151,10 @@ namespace Volo.Abp.Cli.ProjectModification throw new CliUsageException($"ERROR: '{moduleName}' module could not be found!"); } - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response).ConfigureAwait(false); } - var responseContent = await response.Content.ReadAsStringAsync(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); return JsonSerializer.Deserialize(responseContent); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs index 9f6b80b792..4137c7b645 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs @@ -1,19 +1,24 @@ -using NuGet.Versioning; +using System; +using NuGet.Versioning; using System.IO; using System.Threading.Tasks; using System.Xml; using Volo.Abp.Cli.NuGet; using Volo.Abp.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; namespace Volo.Abp.Cli.ProjectModification { public class VoloNugetPackagesVersionUpdater : ITransientDependency { private readonly NuGetService _nuGetService; + public ILogger Logger { get; set; } public VoloNugetPackagesVersionUpdater(NuGetService nuGetService) { _nuGetService = nuGetService; + Logger = NullLogger.Instance; } public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews) @@ -22,42 +27,76 @@ namespace Volo.Abp.Cli.ProjectModification foreach (var filePath in projectPaths) { - await UpdateInternalAsync(filePath, includePreviews); + await UpdateInternalAsync(filePath, includePreviews).ConfigureAwait(false); } } public async Task UpdateProjectAsync(string projectPath, bool includePreviews) { - await UpdateInternalAsync(projectPath, includePreviews); + await UpdateInternalAsync(projectPath, includePreviews).ConfigureAwait(false); } protected virtual async Task UpdateInternalAsync(string projectPath, bool includePreviews) { var fileContent = File.ReadAllText(projectPath); - File.WriteAllText(projectPath, await UpdateVoloPackagesAsync(fileContent, includePreviews)); + File.WriteAllText(projectPath, await UpdateVoloPackagesAsync(fileContent, includePreviews).ConfigureAwait(false)); } private async Task UpdateVoloPackagesAsync(string content, bool includePreviews) { - var doc = new XmlDocument() { PreserveWhitespace = true }; - doc.LoadXml(content); + string packageId = null; - foreach (XmlNode package in doc.SelectNodes("/Project/ItemGroup/PackageReference[starts-with(@Include, 'Volo.')]")) + try { - var versionAttribute = package.Attributes["Version"]; + var doc = new XmlDocument() + { + PreserveWhitespace = true + }; + + doc.LoadXml(content); - var packageId = package.Attributes["Include"].Value; - var packageVersion = SemanticVersion.Parse(versionAttribute.Value); - var latestVersion = await _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews); + var packageNodeList = doc.SelectNodes("/Project/ItemGroup/PackageReference[starts-with(@Include, 'Volo.')]"); - if (latestVersion != null && packageVersion < latestVersion) + if (packageNodeList != null) { - versionAttribute.Value = latestVersion.ToString(); + foreach (XmlNode package in packageNodeList) + { + if (package.Attributes == null) + { + continue; + } + + var versionAttribute = package.Attributes["Version"]; + + packageId = package.Attributes["Include"].Value; + var packageVersion = SemanticVersion.Parse(versionAttribute.Value); + + Logger.LogDebug("Checking package: \"{0}\" - Current version: {1}", packageId, packageVersion); + + var latestVersion = await _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews).ConfigureAwait(false); + + if (latestVersion != null && packageVersion < latestVersion) + { + Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, packageVersion.ToString(), latestVersion.ToString()); + versionAttribute.Value = latestVersion.ToString(); + } + else + { + Logger.LogDebug("Package: \"{0}-v{1}\" is up to date.", packageId, packageVersion); + } + } + + return await Task.FromResult(doc.OuterXml); } } + catch (Exception ex) + { + Logger.LogError("Cannot update volo packages! An error occured while updating the package \"{0}\". Error: {1}", packageId, ex.Message); + Logger.LogException(ex); + } - return doc.OuterXml; + return await Task.FromResult(content); } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs index 0c7c9fc6c0..b871c295f6 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs @@ -11,10 +11,12 @@ namespace Volo.Abp.Cli.Utils Process.Start(procStartInfo).WaitForExit(); } - public static void RunCmd(string command) + public static int RunCmd(string command) { var procStartInfo = new ProcessStartInfo(GetFileName(), GetArguments(command)); - Process.Start(procStartInfo).WaitForExit(); + var process = Process.Start(procStartInfo); + process?.WaitForExit(); + return process?.ExitCode ?? 0; } public static string RunCmdAndGetOutput(string command) @@ -66,7 +68,7 @@ namespace Volo.Abp.Cli.Utils } //Windows default. - return "cmd.exe"; + return "cmd.exe"; } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/GlobalToolHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/GlobalToolHelper.cs new file mode 100644 index 0000000000..8424262324 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/GlobalToolHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; + +namespace Volo.Abp.Cli.Utils +{ + public class GlobalToolHelper + { + /// + /// Checks whether the tool is installed or not. + /// + /// Eg: For AbpSuite tool it's "abp-suite", for ABP CLI tool it's "abp" + public static bool IsGlobalToolInstalled(string toolCommandName) + { + string suitePath; + + if (PlatformHelper.GetPlatform() == RuntimePlatform.LinuxOrMacOs) + { + suitePath = Environment + .ExpandEnvironmentVariables( + Path.Combine("%HOME%", ".dotnet", "tools", toolCommandName) + ); + } + else + { + suitePath = Environment + .ExpandEnvironmentVariables( + Path.Combine(@"%USERPROFILE%", ".dotnet", "tools", toolCommandName + ".exe") + ); + } + + return File.Exists(suitePath); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/PlatformHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/PlatformHelper.cs new file mode 100644 index 0000000000..09d2481782 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/PlatformHelper.cs @@ -0,0 +1,51 @@ +using System; +using System.Runtime.InteropServices; + +namespace Volo.Abp.Cli.Utils +{ + public class PlatformHelper + { + public static OSPlatform GetOperatingSystem() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + //MAC + return OSPlatform.OSX; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return OSPlatform.Linux; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return OSPlatform.Windows; + } + + throw new Exception("Cannot determine operating system!"); + } + + public static RuntimePlatform GetPlatform() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || + RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return RuntimePlatform.LinuxOrMacOs; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return RuntimePlatform.Windows; + } + + throw new Exception("Cannot determine runtime platform!"); + } + } + + public enum RuntimePlatform + { + Windows = 1, + LinuxOrMacOs = 2 + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli/Properties/launchSettings.json b/framework/src/Volo.Abp.Cli/Properties/launchSettings.json new file mode 100644 index 0000000000..e7f99eea04 --- /dev/null +++ b/framework/src/Volo.Abp.Cli/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "Volo.Abp.Cli": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/System/IO/AbpStreamExtensions.cs b/framework/src/Volo.Abp.Core/System/IO/AbpStreamExtensions.cs index e87ab67527..206de7be0d 100644 --- a/framework/src/Volo.Abp.Core/System/IO/AbpStreamExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/IO/AbpStreamExtensions.cs @@ -17,7 +17,7 @@ namespace System.IO { using (var memoryStream = new MemoryStream()) { - await stream.CopyToAsync(memoryStream); + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); return memoryStream.ToArray(); } } diff --git a/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj b/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj index 3eee02f0ac..42c60785ba 100644 --- a/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj +++ b/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj @@ -12,7 +12,7 @@ - + diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs index 1becd3be9b..58f75f3b96 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs @@ -26,5 +26,15 @@ namespace Volo.Abp InitializeModules(); } + + public override void Dispose() + { + base.Dispose(); + + if (ServiceProvider is IDisposable disposableServiceProvider) + { + disposableServiceProvider.Dispose(); + } + } } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/AbpInterceptor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/AbpInterceptor.cs index 8874beafcf..51ab36efc4 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/AbpInterceptor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/AbpInterceptor.cs @@ -3,13 +3,7 @@ namespace Volo.Abp.DynamicProxy { public abstract class AbpInterceptor : IAbpInterceptor - { - public abstract void Intercept(IAbpMethodInvocation invocation); - - public virtual Task InterceptAsync(IAbpMethodInvocation invocation) - { - Intercept(invocation); - return Task.CompletedTask; - } - } + { + public abstract Task InterceptAsync(IAbpMethodInvocation invocation); + } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpInterceptor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpInterceptor.cs index 0d953d9c73..c20cb01277 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpInterceptor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpInterceptor.cs @@ -4,8 +4,6 @@ namespace Volo.Abp.DynamicProxy { public interface IAbpInterceptor { - void Intercept(IAbpMethodInvocation invocation); - Task InterceptAsync(IAbpMethodInvocation invocation); } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpMethodInvocation.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpMethodInvocation.cs index 37a36ac05f..17a89be467 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpMethodInvocation.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/IAbpMethodInvocation.cs @@ -19,8 +19,6 @@ namespace Volo.Abp.DynamicProxy object ReturnValue { get; set; } - void Proceed(); - Task ProceedAsync(); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs index 27c839b023..96a1915e26 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs @@ -5,13 +5,14 @@ namespace Volo.Abp.DynamicProxy { public static class ProxyHelper { + private const string ProxyNamespace = "Castle.Proxies"; /// /// Returns dynamic proxy target object if this is a proxied object, otherwise returns the given object. /// It supports Castle Dynamic Proxies. /// public static object UnProxy(object obj) { - if (obj.GetType().Namespace != "Castle.Proxies") + if (obj.GetType().Namespace != ProxyNamespace) { return obj; } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs index 21ca7c2086..49a86c388a 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs @@ -54,7 +54,7 @@ namespace Volo.Abp.IO { using (var reader = File.OpenText(path)) { - return await reader.ReadToEndAsync(); + return await reader.ReadToEndAsync().ConfigureAwait(false); } } @@ -68,7 +68,7 @@ namespace Volo.Abp.IO using (var stream = File.Open(path, FileMode.Open)) { var result = new byte[stream.Length]; - await stream.ReadAsync(result, 0, (int)stream.Length); + await stream.ReadAsync(result, 0, (int)stream.Length).ConfigureAwait(false); return result; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/AbpCultureHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs similarity index 96% rename from framework/src/Volo.Abp.Core/Volo/Abp/Localization/AbpCultureHelper.cs rename to framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs index ba75ab66ea..92320f737c 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/AbpCultureHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs @@ -4,7 +4,7 @@ using JetBrains.Annotations; namespace Volo.Abp.Localization { - public static class AbpCultureHelper + public static class CultureHelper { public static IDisposable Use([NotNull] string culture, string uiCulture = null) { diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModule.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModule.cs index 6153f4be97..f40c6caf12 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModule.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModule.cs @@ -121,5 +121,17 @@ namespace Volo.Abp.Modularity { ServiceConfigurationContext.Services.PreConfigure(configureOptions); } + + protected void PostConfigure(Action configureOptions) + where TOptions : class + { + ServiceConfigurationContext.Services.PostConfigure(configureOptions); + } + + protected void PostConfigureAll(Action configureOptions) + where TOptions : class + { + ServiceConfigurationContext.Services.PostConfigureAll(configureOptions); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Threading/AsyncOneTimeRunner.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Threading/AsyncOneTimeRunner.cs index 7b440ebfe6..44bd73c074 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Threading/AsyncOneTimeRunner.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Threading/AsyncOneTimeRunner.cs @@ -21,14 +21,14 @@ namespace Volo.Abp.Threading return; } - using (await _semaphore.LockAsync()) + using (await _semaphore.LockAsync().ConfigureAwait(false)) { if (_runBefore) { return; } - await action(); + await action().ConfigureAwait(false); _runBefore = true; } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Threading/InternalAsyncHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Threading/InternalAsyncHelper.cs index 9972e59d3d..ce04a02479 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Threading/InternalAsyncHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Threading/InternalAsyncHelper.cs @@ -14,8 +14,8 @@ namespace Volo.Abp.Threading Exception exception = null; try - { - await actualReturnValue; + { + await actualReturnValue.ConfigureAwait(false); } catch (Exception ex) { @@ -33,9 +33,9 @@ namespace Volo.Abp.Threading Exception exception = null; try - { - await actualReturnValue; - await postAction(); + { + await actualReturnValue.ConfigureAwait(false); + await postAction().ConfigureAwait(false); } catch (Exception ex) { @@ -55,15 +55,15 @@ namespace Volo.Abp.Threading try { if (preAction != null) - { - await preAction(); - } - - await actualReturnValue(); + { + await preAction().ConfigureAwait(false); + } + + await actualReturnValue().ConfigureAwait(false); if (postAction != null) - { - await postAction(); + { + await postAction().ConfigureAwait(false); } } catch (Exception ex) @@ -86,7 +86,7 @@ namespace Volo.Abp.Threading try { - return await actualReturnValue; + return await actualReturnValue.ConfigureAwait(false); } catch (Exception ex) { @@ -114,8 +114,8 @@ namespace Volo.Abp.Threading try { - var result = await actualReturnValue; - await postAction(); + var result = await actualReturnValue.ConfigureAwait(false); + await postAction().ConfigureAwait(false); return result; } catch (Exception ex) @@ -145,15 +145,15 @@ namespace Volo.Abp.Threading try { if (preAction != null) - { - await preAction(); + { + await preAction().ConfigureAwait(false); } - var result = await actualReturnValue(); + var result = await actualReturnValue().ConfigureAwait(false); if (postAction != null) - { - await postAction(); + { + await postAction().ConfigureAwait(false); } return result; diff --git a/framework/src/Volo.Abp.Dapper/Volo.Abp.Dapper.csproj b/framework/src/Volo.Abp.Dapper/Volo.Abp.Dapper.csproj index f7b9d76169..d077d859e1 100644 --- a/framework/src/Volo.Abp.Dapper/Volo.Abp.Dapper.csproj +++ b/framework/src/Volo.Abp.Dapper/Volo.Abp.Dapper.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.Dapper Volo.Abp.Dapper $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs index c20badbeb7..a6a073b67b 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs @@ -31,7 +31,7 @@ namespace Volo.Abp.Data .ServiceProvider .GetRequiredService(contributorType); - await contributor.SeedAsync(context); + await contributor.SeedAsync(context).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo.Abp.Ddd.Application.Contracts.csproj b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo.Abp.Ddd.Application.Contracts.csproj index 0b6eaee362..7da250da5a 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo.Abp.Ddd.Application.Contracts.csproj +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo.Abp.Ddd.Application.Contracts.csproj @@ -13,8 +13,14 @@ + + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/AbpDddApplicationContractsModule.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/AbpDddApplicationContractsModule.cs index e107072221..a8c0eb84b4 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/AbpDddApplicationContractsModule.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/AbpDddApplicationContractsModule.cs @@ -1,12 +1,30 @@ -using Volo.Abp.Auditing; +using Volo.Abp.Application.Localization.Resources.AbpDdd; +using Volo.Abp.Auditing; +using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Application { [DependsOn( - typeof(AbpAuditingModule) + typeof(AbpAuditingModule), + typeof(AbpLocalizationModule) )] public class AbpDddApplicationContractsModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Application/Localization/Resources/AbpDdd"); + }); + } } } diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ILimitedResultRequest.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ILimitedResultRequest.cs index d0088fe155..36af42363c 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ILimitedResultRequest.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ILimitedResultRequest.cs @@ -6,7 +6,8 @@ namespace Volo.Abp.Application.Dtos public interface ILimitedResultRequest { /// - /// Max expected result count. + /// Maximum result count should be returned. + /// This is generally used to limit result count on paging. /// int MaxResultCount { get; set; } } diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs index 0931d090f3..95c55174ad 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs @@ -1,5 +1,9 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.Application.Localization.Resources.AbpDdd; namespace Volo.Abp.Application.Dtos { @@ -7,11 +11,42 @@ namespace Volo.Abp.Application.Dtos /// Simply implements . /// [Serializable] - public class LimitedResultRequestDto : ILimitedResultRequest + public class LimitedResultRequestDto : ILimitedResultRequest, IValidatableObject { + /// + /// Default value: 10. + /// public static int DefaultMaxResultCount { get; set; } = 10; + /// + /// Maximum possible value of the . + /// Default value: 1,000. + /// + public static int MaxMaxResultCount { get; set; } = 1000; + + /// + /// Maximum result count should be returned. + /// This is generally used to limit result count on paging. + /// [Range(1, int.MaxValue)] public virtual int MaxResultCount { get; set; } = DefaultMaxResultCount; + + public virtual IEnumerable Validate(ValidationContext validationContext) + { + if (MaxResultCount > MaxMaxResultCount) + { + var localizer = validationContext.GetRequiredService>(); + + yield return new ValidationResult( + localizer[ + "MaxResultCountExceededExceptionMessage", + nameof(MaxResultCount), + MaxMaxResultCount, + typeof(LimitedResultRequestDto).FullName, + nameof(MaxMaxResultCount) + ], + new[] { nameof(MaxResultCount) }); + } + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/AbpDddApplicationContractsResource.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/AbpDddApplicationContractsResource.cs new file mode 100644 index 0000000000..ceef26f7c7 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/AbpDddApplicationContractsResource.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Localization; + +namespace Volo.Abp.Application.Localization.Resources.AbpDdd +{ + [LocalizationResourceName("AbpDddApplicationContracts")] + public class AbpDddApplicationContractsResource + { + + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/en.json b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/en.json new file mode 100644 index 0000000000..2c514e6c18 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/en.json @@ -0,0 +1,6 @@ +{ + "culture": "en", + "texts": { + "MaxResultCountExceededExceptionMessage": "{0} can not be more than {1}! Increase {2}.{3} on the server side to allow more results." + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/tr.json b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/tr.json new file mode 100644 index 0000000000..428f348427 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/tr.json @@ -0,0 +1,6 @@ +{ + "culture": "tr", + "texts": { + "MaxResultCountExceededExceptionMessage": "{0} en fazla {1} olabilir, daha büyük olamaz! Daha fazla sonuca izin vermek için {2}.{3}'ü sunucu tarafında artırın." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/zh-Hans.json b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/zh-Hans.json new file mode 100644 index 0000000000..0bc563e702 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/zh-Hans.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hans", + "texts": { + "MaxResultCountExceededExceptionMessage": "{0}不能超过 {1}! 在服务器端增加{2}.{3}以获得更多结果." + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/zh-Hant.json b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/zh-Hant.json new file mode 100644 index 0000000000..97a615e901 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Localization/Resources/AbpDdd/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hant", + "texts": { + "MaxResultCountExceededExceptionMessage": "{0}禁止超過{1}! 請在伺服器端增加{2}.{3}以獲得更多結果." + } +} diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs index 0de23c826b..0145e2c763 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Aspects; using Volo.Abp.Auditing; -using Volo.Abp.Authorization; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; using Volo.Abp.Guids; @@ -146,7 +145,7 @@ namespace Volo.Abp.Application.Services return; } - await AuthorizationService.CheckAsync(policyName); + await AuthorizationService.CheckAsync(policyName).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs index 237e89aa53..e5febca25b 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs @@ -93,24 +93,24 @@ namespace Volo.Abp.Application.Services public virtual async Task GetAsync(TKey id) { - await CheckGetPolicyAsync(); + await CheckGetPolicyAsync().ConfigureAwait(false); - var entity = await GetEntityByIdAsync(id); + var entity = await GetEntityByIdAsync(id).ConfigureAwait(false); return MapToGetOutputDto(entity); } public virtual async Task> GetListAsync(TGetListInput input) { - await CheckGetListPolicyAsync(); + await CheckGetListPolicyAsync().ConfigureAwait(false); var query = CreateFilteredQuery(input); - var totalCount = await AsyncQueryableExecuter.CountAsync(query); + var totalCount = await AsyncQueryableExecuter.CountAsync(query).ConfigureAwait(false); query = ApplySorting(query, input); query = ApplyPaging(query, input); - var entities = await AsyncQueryableExecuter.ToListAsync(query); + var entities = await AsyncQueryableExecuter.ToListAsync(query).ConfigureAwait(false); return new PagedResultDto( totalCount, @@ -120,34 +120,34 @@ namespace Volo.Abp.Application.Services public virtual async Task CreateAsync(TCreateInput input) { - await CheckCreatePolicyAsync(); + await CheckCreatePolicyAsync().ConfigureAwait(false); var entity = MapToEntity(input); TryToSetTenantId(entity); - await Repository.InsertAsync(entity, autoSave: true); + await Repository.InsertAsync(entity, autoSave: true).ConfigureAwait(false); return MapToGetOutputDto(entity); } public virtual async Task UpdateAsync(TKey id, TUpdateInput input) { - await CheckUpdatePolicyAsync(); + await CheckUpdatePolicyAsync().ConfigureAwait(false); - var entity = await GetEntityByIdAsync(id); + var entity = await GetEntityByIdAsync(id).ConfigureAwait(false); //TODO: Check if input has id different than given id and normalize if it's default value, throw ex otherwise MapToEntity(input, entity); - await Repository.UpdateAsync(entity, autoSave: true); + await Repository.UpdateAsync(entity, autoSave: true).ConfigureAwait(false); return MapToGetOutputDto(entity); } public virtual async Task DeleteAsync(TKey id) { - await CheckDeletePolicyAsync(); + await CheckDeletePolicyAsync().ConfigureAwait(false); - await Repository.DeleteAsync(id); + await Repository.DeleteAsync(id).ConfigureAwait(false); } protected virtual Task GetEntityByIdAsync(TKey id) @@ -157,27 +157,27 @@ namespace Volo.Abp.Application.Services protected virtual async Task CheckGetPolicyAsync() { - await CheckPolicyAsync(GetPolicyName); + await CheckPolicyAsync(GetPolicyName).ConfigureAwait(false); } protected virtual async Task CheckGetListPolicyAsync() { - await CheckPolicyAsync(GetListPolicyName); + await CheckPolicyAsync(GetListPolicyName).ConfigureAwait(false); } protected virtual async Task CheckCreatePolicyAsync() { - await CheckPolicyAsync(CreatePolicyName); + await CheckPolicyAsync(CreatePolicyName).ConfigureAwait(false); } protected virtual async Task CheckUpdatePolicyAsync() { - await CheckPolicyAsync(UpdatePolicyName); + await CheckPolicyAsync(UpdatePolicyName).ConfigureAwait(false); } protected virtual async Task CheckDeletePolicyAsync() { - await CheckPolicyAsync(DeletePolicyName); + await CheckPolicyAsync(DeletePolicyName).ConfigureAwait(false); } /// @@ -321,10 +321,12 @@ namespace Volo.Abp.Application.Services var propertyInfo = entity.GetType().GetProperty(nameof(IMultiTenant.TenantId)); - if (propertyInfo != null && propertyInfo.GetSetMethod() != null) + if (propertyInfo == null || propertyInfo.GetSetMethod(true) == null) { - propertyInfo.SetValue(entity, tenantId, null); + return; } + + propertyInfo.SetValue(entity, tenantId); } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs index cb0be46421..b2dbb8c280 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Auditing/FullAuditedAggregateRootWithUser.cs @@ -4,12 +4,12 @@ using Volo.Abp.Auditing; namespace Volo.Abp.Domain.Entities.Auditing { /// - /// Implements to be a base class for full-audited aggregate roots. + /// Implements to be a base class for full-audited aggregate roots. /// /// Type of the user [Serializable] public abstract class FullAuditedAggregateRootWithUser : FullAuditedAggregateRoot, IFullAuditedObject - where TUser : IEntity + where TUser : IEntity { /// public virtual TUser Deleter { get; set; } @@ -22,13 +22,13 @@ namespace Volo.Abp.Domain.Entities.Auditing } /// - /// Implements to be a base class for full-audited aggregate roots. + /// Implements to be a base class for full-audited aggregate roots. /// /// Type of the primary key of the entity /// Type of the user [Serializable] public abstract class FullAuditedAggregateRootWithUser : FullAuditedAggregateRoot, IFullAuditedObject - where TUser : IEntity + where TUser : IEntity { /// public virtual TUser Deleter { get; set; } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs index e72a92c14a..92ebdd4568 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs @@ -94,7 +94,7 @@ namespace Volo.Abp.Domain.Entities nameof(entity.Id) ); - if (idProperty == null) + if (idProperty == null || idProperty.GetSetMethod(true) == null) { return; } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index c9219feffc..47e3571ffd 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -36,14 +36,14 @@ namespace Volo.Abp.Domain.Entities.Events public async Task TriggerEventsAsync(EntityChangeReport changeReport) { - await TriggerEventsInternalAsync(changeReport); + await TriggerEventsInternalAsync(changeReport).ConfigureAwait(false); if (changeReport.IsEmpty() || UnitOfWorkManager.Current == null) { return; } - await UnitOfWorkManager.Current.SaveChangesAsync(); + await UnitOfWorkManager.Current.SaveChangesAsync().ConfigureAwait(false); } public virtual async Task TriggerEntityCreatingEventAsync(object entity) @@ -53,7 +53,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityCreatingEventData<>), entity, true - ); + ).ConfigureAwait(false); } public virtual async Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity) @@ -63,7 +63,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityCreatedEventData<>), entity, false - ); + ).ConfigureAwait(false); var eto = EntityToEtoMapper.Map(entity); if (eto != null) @@ -73,7 +73,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityCreatedEto<>), eto, false - ); + ).ConfigureAwait(false); } } @@ -84,7 +84,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityUpdatingEventData<>), entity, true - ); + ).ConfigureAwait(false); } public virtual async Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity) @@ -94,7 +94,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityUpdatedEventData<>), entity, false - ); + ).ConfigureAwait(false); var eto = EntityToEtoMapper.Map(entity); if (eto != null) @@ -104,7 +104,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityUpdatedEto<>), eto, false - ); + ).ConfigureAwait(false); } } @@ -115,7 +115,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityDeletingEventData<>), entity, true - ); + ).ConfigureAwait(false); } public virtual async Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity) @@ -125,7 +125,7 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityDeletedEventData<>), entity, false - ); + ).ConfigureAwait(false); var eto = EntityToEtoMapper.Map(entity); if (eto != null) @@ -135,15 +135,15 @@ namespace Volo.Abp.Domain.Entities.Events typeof(EntityDeletedEto<>), EntityToEtoMapper.Map(entity), false - ); + ).ConfigureAwait(false); } } protected virtual async Task TriggerEventsInternalAsync(EntityChangeReport changeReport) { - await TriggerEntityChangeEvents(changeReport.ChangedEntities); - await TriggerLocalEvents(changeReport.DomainEvents); - await TriggerDistributedEvents(changeReport.DistributedEvents); + await TriggerEntityChangeEvents(changeReport.ChangedEntities).ConfigureAwait(false); + await TriggerLocalEvents(changeReport.DomainEvents).ConfigureAwait(false); + await TriggerDistributedEvents(changeReport.DistributedEvents).ConfigureAwait(false); } protected virtual async Task TriggerEntityChangeEvents(List changedEntities) @@ -153,16 +153,16 @@ namespace Volo.Abp.Domain.Entities.Events switch (changedEntity.ChangeType) { case EntityChangeType.Created: - await TriggerEntityCreatingEventAsync(changedEntity.Entity); - await TriggerEntityCreatedEventOnUowCompletedAsync(changedEntity.Entity); + await TriggerEntityCreatingEventAsync(changedEntity.Entity).ConfigureAwait(false); + await TriggerEntityCreatedEventOnUowCompletedAsync(changedEntity.Entity).ConfigureAwait(false); break; case EntityChangeType.Updated: - await TriggerEntityUpdatingEventAsync(changedEntity.Entity); - await TriggerEntityUpdatedEventOnUowCompletedAsync(changedEntity.Entity); + await TriggerEntityUpdatingEventAsync(changedEntity.Entity).ConfigureAwait(false); + await TriggerEntityUpdatedEventOnUowCompletedAsync(changedEntity.Entity).ConfigureAwait(false); break; case EntityChangeType.Deleted: - await TriggerEntityDeletingEventAsync(changedEntity.Entity); - await TriggerEntityDeletedEventOnUowCompletedAsync(changedEntity.Entity); + await TriggerEntityDeletingEventAsync(changedEntity.Entity).ConfigureAwait(false); + await TriggerEntityDeletedEventOnUowCompletedAsync(changedEntity.Entity).ConfigureAwait(false); break; default: throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType); @@ -174,7 +174,7 @@ namespace Volo.Abp.Domain.Entities.Events { foreach (var localEvent in localEvents) { - await LocalEventBus.PublishAsync(localEvent.EventData.GetType(), localEvent.EventData); + await LocalEventBus.PublishAsync(localEvent.EventData.GetType(), localEvent.EventData).ConfigureAwait(false); } } @@ -182,7 +182,7 @@ namespace Volo.Abp.Domain.Entities.Events { foreach (var distributedEvent in distributedEvents) { - await DistributedEventBus.PublishAsync(distributedEvent.EventData.GetType(), distributedEvent.EventData); + await DistributedEventBus.PublishAsync(distributedEvent.EventData.GetType(), distributedEvent.EventData).ConfigureAwait(false); } } @@ -193,7 +193,7 @@ namespace Volo.Abp.Domain.Entities.Events if (triggerInCurrentUnitOfWork || UnitOfWorkManager.Current == null) { - await eventPublisher.PublishAsync(eventType, Activator.CreateInstance(eventType, entity)); + await eventPublisher.PublishAsync(eventType, Activator.CreateInstance(eventType, entity)).ConfigureAwait(false); return; } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs index 05fc760182..ae438fdd01 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs @@ -25,54 +25,28 @@ namespace Volo.Abp.Domain.Repositories CancellationTokenProvider = NullCancellationTokenProvider.Instance; } - public abstract TEntity Insert(TEntity entity, bool autoSave = false); + public abstract Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); - public virtual Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) - { - return Task.FromResult(Insert(entity, autoSave)); - } + public abstract Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); - public abstract TEntity Update(TEntity entity, bool autoSave = false); + public abstract Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); - public virtual Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) - { - return Task.FromResult(Update(entity)); - } + public abstract Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default); - public abstract void Delete(TEntity entity, bool autoSave = false); - - public virtual Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) - { - Delete(entity); - return Task.CompletedTask; - } + public abstract Task GetCountAsync(CancellationToken cancellationToken = default); - protected virtual CancellationToken GetCancellationToken(CancellationToken prefferedValue = default) + protected virtual CancellationToken GetCancellationToken(CancellationToken preferredValue = default) { - return CancellationTokenProvider.FallbackToProvider(prefferedValue); - } - - public abstract List GetList(bool includeDetails = false); - - public virtual Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) - { - return Task.FromResult(GetList(includeDetails)); - } - - public abstract long GetCount(); - - public virtual Task GetCountAsync(CancellationToken cancellationToken = default) - { - return Task.FromResult(GetCount()); + return CancellationTokenProvider.FallbackToProvider(preferredValue); } } public abstract class BasicRepositoryBase : BasicRepositoryBase, IBasicRepository where TEntity : class, IEntity { - public virtual TEntity Get(TKey id, bool includeDetails = true) + public virtual async Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - var entity = Find(id, includeDetails); + var entity = await FindAsync(id, includeDetails, cancellationToken).ConfigureAwait(false); if (entity == null) { @@ -82,33 +56,17 @@ namespace Volo.Abp.Domain.Repositories return entity; } - public virtual Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) - { - return Task.FromResult(Get(id, includeDetails)); - } - - public abstract TEntity Find(TKey id, bool includeDetails = true); - - public virtual Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) - { - return Task.FromResult(Find(id, includeDetails)); - } - - public virtual void Delete(TKey id, bool autoSave = false) + public abstract Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default); + + public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { - var entity = Find(id); + var entity = await FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); if (entity == null) { return; } - Delete(entity); - } - - public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) - { - Delete(id); - return Task.CompletedTask; + await DeleteAsync(entity, autoSave, cancellationToken).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IBasicRepository.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IBasicRepository.cs index f3644bbe4a..6b62691ed8 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IBasicRepository.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IBasicRepository.cs @@ -8,17 +8,6 @@ namespace Volo.Abp.Domain.Repositories public interface IBasicRepository : IReadOnlyBasicRepository where TEntity : class, IEntity { - /// - /// Inserts a new entity. - /// - /// Inserted entity - /// - /// Set true to automatically save entity to database. - /// This is useful for ORMs / database APIs those only save changes with an explicit method call, but you need to immediately save changes to the database. - /// - [NotNull] - TEntity Insert([NotNull] TEntity entity, bool autoSave = false); - /// /// Inserts a new entity. /// @@ -31,17 +20,6 @@ namespace Volo.Abp.Domain.Repositories [NotNull] Task InsertAsync([NotNull] TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); - /// - /// Updates an existing entity. - /// - /// Entity - /// - /// Set true to automatically save changes to database. - /// This is useful for ORMs / database APIs those only save changes with an explicit method call, but you need to immediately save changes to the database. - /// - [NotNull] - TEntity Update([NotNull] TEntity entity, bool autoSave = false); - /// /// Updates an existing entity. /// @@ -54,16 +32,6 @@ namespace Volo.Abp.Domain.Repositories [NotNull] Task UpdateAsync([NotNull] TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); - /// - /// Deletes an entity. - /// - /// Entity to be deleted - /// - /// Set true to automatically save changes to database. - /// This is useful for ORMs / database APIs those only save changes with an explicit method call, but you need to immediately save changes to the database. - /// - void Delete([NotNull] TEntity entity, bool autoSave = false); - /// /// Deletes an entity. /// @@ -79,16 +47,6 @@ namespace Volo.Abp.Domain.Repositories public interface IBasicRepository : IBasicRepository, IReadOnlyBasicRepository where TEntity : class, IEntity { - /// - /// Deletes an entity by primary key. - /// - /// Primary key of the entity - /// - /// Set true to automatically save changes to database. - /// This is useful for ORMs / database APIs those only save changes with an explicit method call, but you need to immediately save changes to the database. - /// - void Delete(TKey id, bool autoSave = false); //TODO: Return true if deleted - /// /// Deletes an entity by primary key. /// diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyBasicRepository.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyBasicRepository.cs index c67b35794b..828e305ff8 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyBasicRepository.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyBasicRepository.cs @@ -9,13 +9,6 @@ namespace Volo.Abp.Domain.Repositories public interface IReadOnlyBasicRepository : IRepository where TEntity : class, IEntity { - /// - /// Gets a list of all the entities. - /// - /// Set true to include all children of this entity - /// Entity - List GetList(bool includeDetails = false); - /// /// Gets a list of all the entities. /// @@ -24,11 +17,6 @@ namespace Volo.Abp.Domain.Repositories /// Entity Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default); - /// - /// Gets total count of all entities. - /// - long GetCount(); - /// /// Gets total count of all entities. /// @@ -38,16 +26,6 @@ namespace Volo.Abp.Domain.Repositories public interface IReadOnlyBasicRepository : IReadOnlyBasicRepository where TEntity : class, IEntity { - /// - /// Gets an entity with given primary key. - /// Throws if can not find an entity with given id. - /// - /// Primary key of the entity to get - /// Set true to include all children of this entity - /// Entity - [NotNull] - TEntity Get(TKey id, bool includeDetails = true); - /// /// Gets an entity with given primary key. /// Throws if can not find an entity with given id. @@ -59,15 +37,6 @@ namespace Volo.Abp.Domain.Repositories [NotNull] Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default); - /// - /// Gets an entity with given primary key or null if not found. - /// - /// Primary key of the entity to get - /// Set true to include all children of this entity - /// Entity or null - [CanBeNull] - TEntity Find(TKey id, bool includeDetails = true); - /// /// Gets an entity with given primary key or null if not found. /// diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs index a77dc4acb7..2ac16ec229 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs @@ -18,19 +18,6 @@ namespace Volo.Abp.Domain.Repositories public interface IRepository : IReadOnlyRepository, IBasicRepository where TEntity : class, IEntity { - /// - /// Deletes many entities by function. - /// Notice that: All entities fits to given predicate are retrieved and deleted. - /// This may cause major performance problems if there are too many entities with - /// given predicate. - /// - /// A condition to filter entities - /// - /// Set true to automatically save changes to database. - /// This is useful for ORMs / database APIs those only save changes with an explicit method call, but you need to immediately save changes to the database. - /// - void Delete([NotNull] Expression> predicate, bool autoSave = false); - /// /// Deletes many entities by function. /// Notice that: All entities fits to given predicate are retrieved and deleted. diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs index 139f4ff999..358d36733e 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs @@ -46,19 +46,7 @@ namespace Volo.Abp.Domain.Repositories protected abstract IQueryable GetQueryable(); - public virtual void Delete(Expression> predicate, bool autoSave = false) - { - foreach (var entity in GetQueryable().Where(predicate).ToList()) - { - Delete(entity, autoSave); - } - } - - public virtual Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) - { - Delete(predicate, autoSave); - return Task.CompletedTask; - } + public abstract Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default); protected virtual TQueryable ApplyDataFilters(TQueryable query) where TQueryable : IQueryable @@ -81,50 +69,19 @@ namespace Volo.Abp.Domain.Repositories public abstract class RepositoryBase : RepositoryBase, IRepository where TEntity : class, IEntity { - public virtual TEntity Find(TKey id, bool includeDetails = true) - { - return includeDetails - ? WithDetails().FirstOrDefault(EntityHelper.CreateEqualityExpressionForId(id)) - : GetQueryable().FirstOrDefault(EntityHelper.CreateEqualityExpressionForId(id)); - } + public abstract Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default); - public virtual TEntity Get(TKey id, bool includeDetails = true) - { - var entity = Find(id, includeDetails); + public abstract Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default); - if (entity == null) - { - throw new EntityNotFoundException(typeof(TEntity), id); - } - - return entity; - } - - public virtual Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) - { - return Task.FromResult(Get(id, includeDetails)); - } - - public virtual Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { - return Task.FromResult(Find(id, includeDetails)); - } - - public virtual void Delete(TKey id, bool autoSave = false) - { - var entity = Find(id, includeDetails: false); + var entity = await FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); if (entity == null) { return; } - Delete(entity, autoSave); - } - - public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) - { - Delete(id, autoSave); - return Task.CompletedTask; + await DeleteAsync(entity, autoSave, cancellationToken).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs index 40ebca015e..915b97a7d4 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryExtensions.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.Domain.Repositories var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading; if (repo != null) { - await repo.EnsureCollectionLoadedAsync(entity, propertyExpression, cancellationToken); + await repo.EnsureCollectionLoadedAsync(entity, propertyExpression, cancellationToken).ConfigureAwait(false); } } @@ -38,7 +38,7 @@ namespace Volo.Abp.Domain.Repositories var repo = ProxyHelper.UnProxy(repository) as ISupportsExplicitLoading; if (repo != null) { - await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken); + await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj b/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj index 5ed32e6961..40fe0b3610 100644 --- a/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj +++ b/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj @@ -19,7 +19,12 @@ - + + + + + + diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs index 55ec63b9ac..c2e29a7ff7 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.BackgroundJobs; +using Volo.Abp.Emailing.Localization; using Volo.Abp.Emailing.Templates; using Volo.Abp.Localization; using Volo.Abp.Modularity; @@ -30,6 +31,13 @@ namespace Volo.Abp.Emailing options.FileSets.AddEmbedded(); }); + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Emailing/Localization"); + }); + Configure(options => { options.AddJob(); diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs index f6588de9fb..aa38f874d6 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderBase.cs @@ -32,29 +32,29 @@ namespace Volo.Abp.Emailing Subject = subject, Body = body, IsBodyHtml = isBodyHtml - }); + }).ConfigureAwait(false); } public virtual async Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true) { - await SendAsync(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml }); + await SendAsync(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml }).ConfigureAwait(false); } public virtual async Task SendAsync(MailMessage mail, bool normalize = true) { if (normalize) { - await NormalizeMailAsync(mail); + await NormalizeMailAsync(mail).ConfigureAwait(false); } - await SendEmailAsync(mail); + await SendEmailAsync(mail).ConfigureAwait(false); } public virtual async Task QueueAsync(string to, string subject, string body, bool isBodyHtml = true) { if (!BackgroundJobManager.IsAvailable()) { - await SendAsync(to, subject, body, isBodyHtml); + await SendAsync(to, subject, body, isBodyHtml).ConfigureAwait(false); return; } @@ -66,7 +66,7 @@ namespace Volo.Abp.Emailing Body = body, IsBodyHtml = isBodyHtml } - ); + ).ConfigureAwait(false); } /// @@ -86,8 +86,8 @@ namespace Volo.Abp.Emailing if (mail.From == null || mail.From.Address.IsNullOrEmpty()) { mail.From = new MailAddress( - await Configuration.GetDefaultFromAddressAsync(), - await Configuration.GetDefaultFromDisplayNameAsync(), + await Configuration.GetDefaultFromAddressAsync().ConfigureAwait(false), + await Configuration.GetDefaultFromDisplayNameAsync().ConfigureAwait(false), Encoding.UTF8 ); } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs index e02b78badd..dafd5b8a4f 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSenderConfiguration.cs @@ -37,7 +37,7 @@ namespace Volo.Abp.Emailing /// Value of the setting protected async Task GetNotEmptySettingValueAsync(string name) { - var value = await SettingProvider.GetOrNullAsync(name); + var value = await SettingProvider.GetOrNullAsync(name).ConfigureAwait(false); if (value.IsNullOrEmpty()) { diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSettingProvider.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSettingProvider.cs index 32d1fb8c1c..0fb3402740 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSettingProvider.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/EmailSettingProvider.cs @@ -1,3 +1,5 @@ +using Volo.Abp.Emailing.Localization; +using Volo.Abp.Localization; using Volo.Abp.Settings; namespace Volo.Abp.Emailing @@ -11,16 +13,62 @@ namespace Volo.Abp.Emailing public override void Define(ISettingDefinitionContext context) { context.Add( - new SettingDefinition(EmailSettingNames.Smtp.Host, "127.0.0.1"), - new SettingDefinition(EmailSettingNames.Smtp.Port, "25"), - new SettingDefinition(EmailSettingNames.Smtp.UserName), - new SettingDefinition(EmailSettingNames.Smtp.Password, isEncrypted: true), - new SettingDefinition(EmailSettingNames.Smtp.Domain), - new SettingDefinition(EmailSettingNames.Smtp.EnableSsl, "false"), - new SettingDefinition(EmailSettingNames.Smtp.UseDefaultCredentials, "true"), - new SettingDefinition(EmailSettingNames.DefaultFromAddress, "noreply@abp.io"), - new SettingDefinition(EmailSettingNames.DefaultFromDisplayName, "ABP application") + new SettingDefinition( + EmailSettingNames.Smtp.Host, + "127.0.0.1", + L("DisplayName:Abp.Mailing.Smtp.Host"), + L("Description:Abp.Mailing.Smtp.Host")), + + new SettingDefinition(EmailSettingNames.Smtp.Port, + "25", + L("DisplayName:Abp.Mailing.Smtp.Port"), + L("Description:Abp.Mailing.Smtp.Port")), + + new SettingDefinition( + EmailSettingNames.Smtp.UserName, + displayName: L("DisplayName:Abp.Mailing.Smtp.UserName"), + description: L("Description:Abp.Mailing.Smtp.UserName")), + + new SettingDefinition( + EmailSettingNames.Smtp.Password, + displayName: + L("DisplayName:Abp.Mailing.Smtp.Password"), + description: L("Description:Abp.Mailing.Smtp.Password"), + isEncrypted: true), + + new SettingDefinition( + EmailSettingNames.Smtp.Domain, + displayName: L("DisplayName:Abp.Mailing.Smtp.Domain"), + description: L("Description:Abp.Mailing.Smtp.Domain")), + + new SettingDefinition( + EmailSettingNames.Smtp.EnableSsl, + "false", + L("DisplayName:Abp.Mailing.Smtp.EnableSsl"), + L("Description:Abp.Mailing.Smtp.EnableSsl")), + + new SettingDefinition( + EmailSettingNames.Smtp.UseDefaultCredentials, + "true", + L("DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials"), + L("Description:Abp.Mailing.Smtp.UseDefaultCredentials")), + + new SettingDefinition( + EmailSettingNames.DefaultFromAddress, + "noreply@abp.io", + L("DisplayName:Abp.Mailing.DefaultFromAddress"), + L("Description:Abp.Mailing.DefaultFromAddress")), + + new SettingDefinition(EmailSettingNames.DefaultFromDisplayName, + "ABP application", + L("DisplayName:Abp.Mailing.DefaultFromDisplayName"), + L("Description:Abp.Mailing.DefaultFromDisplayName")) ); } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/EmailingResource.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/EmailingResource.cs new file mode 100644 index 0000000000..3560c0db26 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/EmailingResource.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Localization; + +namespace Volo.Abp.Emailing.Localization +{ + [LocalizationResourceName("AbpEmailing")] + public class EmailingResource + { + + } +} diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json new file mode 100644 index 0000000000..c4b1aaad40 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/cs.json @@ -0,0 +1,24 @@ +{ + "culture": "cs", + "texts": { + "DisplayName:Abp.Mailing.DefaultFromAddress": "Výchozí adresa odesílatele", + "DisplayName:Abp.Mailing.DefaultFromDisplayName": "Výchozí zobrazované jméno odesilátele", + "DisplayName:Abp.Mailing.Smtp.Host": "Hostitel", + "DisplayName:Abp.Mailing.Smtp.Port": "Port", + "DisplayName:Abp.Mailing.Smtp.UserName": "Uživatelské jméno", + "DisplayName:Abp.Mailing.Smtp.Password": "Heslo", + "DisplayName:Abp.Mailing.Smtp.Domain": "Doména", + "DisplayName:Abp.Mailing.Smtp.EnableSsl": "Povolit SSL", + "DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "Použít výchozí přihlašovací údaje", + "Description:Abp.Mailing.DefaultFromAddress": "Výchozí adresa odesílatele", + "Description:Abp.Mailing.DefaultFromDisplayName": "Výchozí zobrazované jméno odesilátele", + "Description:Abp.Mailing.Smtp.Host": "Název nebo IP adresa hostitele použitého pro SMTP transakce.", + "Description:Abp.Mailing.Smtp.Port": "Port použitý pro SMTP tansakce", + "Description:Abp.Mailing.Smtp.UserName": "Uživatelské jméno spojené s přihlašovacími údaji.", + "Description:Abp.Mailing.Smtp.Password": "Heslo pro uživatelské jméno spojené s přihlašovacími údaji.", + "Description:Abp.Mailing.Smtp.Domain": "Název domény nebo počítače, který ověřuje přihlašovací údaje.", + "Description:Abp.Mailing.Smtp.EnableSsl": "Zda SmtpClient používá SSL k šifrování připojení.", + "Description:Abp.Mailing.Smtp.UseDefaultCredentials": "Zda jsou výchozí přihlašovací údaje odesílány s požadavky." + } +} + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/en.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/en.json new file mode 100644 index 0000000000..6fa4e626ff --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/en.json @@ -0,0 +1,23 @@ +{ + "culture": "en", + "texts": { + "DisplayName:Abp.Mailing.DefaultFromAddress": "Default from address", + "DisplayName:Abp.Mailing.DefaultFromDisplayName": "Default from display name", + "DisplayName:Abp.Mailing.Smtp.Host": "Host", + "DisplayName:Abp.Mailing.Smtp.Port": "Port", + "DisplayName:Abp.Mailing.Smtp.UserName": "User name", + "DisplayName:Abp.Mailing.Smtp.Password": "Password", + "DisplayName:Abp.Mailing.Smtp.Domain": "Domain", + "DisplayName:Abp.Mailing.Smtp.EnableSsl": "Enable SSL", + "DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "Use default credentials", + "Description:Abp.Mailing.DefaultFromAddress": "The default from address", + "Description:Abp.Mailing.DefaultFromDisplayName": "The default from display name", + "Description:Abp.Mailing.Smtp.Host": "The name or IP address of the host used for SMTP transactions.", + "Description:Abp.Mailing.Smtp.Port": "The port used for SMTP transactions.", + "Description:Abp.Mailing.Smtp.UserName": "User name associated with the credentials.", + "Description:Abp.Mailing.Smtp.Password": "The password for the user name associated with the credentials.", + "Description:Abp.Mailing.Smtp.Domain": "The domain or computer name that verifies the credentials.", + "Description:Abp.Mailing.Smtp.EnableSsl": "Whether the SmtpClient uses Secure Sockets Layer (SSL) to encrypt the connection.", + "Description:Abp.Mailing.Smtp.UseDefaultCredentials": "Whether the DefaultCredentials are sent with requests." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json new file mode 100644 index 0000000000..0e2d25bff1 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json @@ -0,0 +1,23 @@ +{ + "culture": "zh-Hans", + "texts": { + "DisplayName:Abp.Mailing.DefaultFromAddress": "默认发件人地址", + "DisplayName:Abp.Mailing.DefaultFromDisplayName": "默认发件人名字", + "DisplayName:Abp.Mailing.Smtp.Host": "主机", + "DisplayName:Abp.Mailing.Smtp.Port": "端口", + "DisplayName:Abp.Mailing.Smtp.UserName": "用户名", + "DisplayName:Abp.Mailing.Smtp.Password": "密码", + "DisplayName:Abp.Mailing.Smtp.Domain": "域", + "DisplayName:Abp.Mailing.Smtp.EnableSsl": "启用SSL", + "DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "使用默认凭据", + "Description:Abp.Mailing.DefaultFromAddress": "默认的发件人地址.", + "Description:Abp.Mailing.DefaultFromDisplayName": "默认的发件人名字.", + "Description:Abp.Mailing.Smtp.Host": "SMTP 事务的主机名或主机 IP 地址.", + "Description:Abp.Mailing.Smtp.Port": "SMTP 事务的端口.", + "Description:Abp.Mailing.Smtp.UserName": "凭据关联的用户名.", + "Description:Abp.Mailing.Smtp.Password": "凭据关联的用户名的密码.", + "Description:Abp.Mailing.Smtp.Domain": "验证凭据的域名或计算机名.", + "Description:Abp.Mailing.Smtp.EnableSsl": "指定 SmtpClient 是否使用安全套接字层 (SSL) 加密连接.", + "Description:Abp.Mailing.Smtp.UseDefaultCredentials": "控制默认凭据是否随请求一起发送." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hant.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hant.json new file mode 100644 index 0000000000..a66a6d2ff8 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hant.json @@ -0,0 +1,23 @@ +{ + "culture": "zh-Hant", + "texts": { + "DisplayName:Abp.Mailing.DefaultFromAddress": "預設發信者地址", + "DisplayName:Abp.Mailing.DefaultFromDisplayName": "預設發信者名稱", + "DisplayName:Abp.Mailing.Smtp.Host": "主機", + "DisplayName:Abp.Mailing.Smtp.Port": "埠號", + "DisplayName:Abp.Mailing.Smtp.UserName": "使用者名稱", + "DisplayName:Abp.Mailing.Smtp.Password": "密碼", + "DisplayName:Abp.Mailing.Smtp.Domain": "網域", + "DisplayName:Abp.Mailing.Smtp.EnableSsl": "啟用SSL", + "DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "使用預設憑證", + "Description:Abp.Mailing.DefaultFromAddress": "預設的發信者地址.", + "Description:Abp.Mailing.DefaultFromDisplayName": "預設的發信者名稱.", + "Description:Abp.Mailing.Smtp.Host": "SMTP 服務的主機名稱或主機IP位址.", + "Description:Abp.Mailing.Smtp.Port": "SMTP 服務的埠號.", + "Description:Abp.Mailing.Smtp.UserName": "憑證使用者名稱.", + "Description:Abp.Mailing.Smtp.Password": "憑證使用者密碼.", + "Description:Abp.Mailing.Smtp.Domain": "驗證憑證的網域名稱或電腦名稱.", + "Description:Abp.Mailing.Smtp.EnableSsl": "設定 SmtpClient 是否使用安全通訊協定.", + "Description:Abp.Mailing.Smtp.UseDefaultCredentials": "設定是否使用預設憑證." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs index f97fd57b18..84af1bf348 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Smtp/SmtpEmailSender.cs @@ -28,19 +28,19 @@ namespace Volo.Abp.Emailing.Smtp public async Task BuildClientAsync() { - var host = await SmtpConfiguration.GetHostAsync(); - var port = await SmtpConfiguration.GetPortAsync(); + var host = await SmtpConfiguration.GetHostAsync().ConfigureAwait(false); + var port = await SmtpConfiguration.GetPortAsync().ConfigureAwait(false); var smtpClient = new SmtpClient(host, port); try { - if (await SmtpConfiguration.GetEnableSslAsync()) + if (await SmtpConfiguration.GetEnableSslAsync().ConfigureAwait(false)) { smtpClient.EnableSsl = true; } - if (await SmtpConfiguration.GetUseDefaultCredentialsAsync()) + if (await SmtpConfiguration.GetUseDefaultCredentialsAsync().ConfigureAwait(false)) { smtpClient.UseDefaultCredentials = true; } @@ -48,11 +48,11 @@ namespace Volo.Abp.Emailing.Smtp { smtpClient.UseDefaultCredentials = false; - var userName = await SmtpConfiguration.GetUserNameAsync(); + var userName = await SmtpConfiguration.GetUserNameAsync().ConfigureAwait(false); if (!userName.IsNullOrEmpty()) { - var password = await SmtpConfiguration.GetPasswordAsync(); - var domain = await SmtpConfiguration.GetDomainAsync(); + var password = await SmtpConfiguration.GetPasswordAsync().ConfigureAwait(false); + var domain = await SmtpConfiguration.GetDomainAsync().ConfigureAwait(false); smtpClient.Credentials = !domain.IsNullOrEmpty() ? new NetworkCredential(userName, password, domain) : new NetworkCredential(userName, password); @@ -70,9 +70,9 @@ namespace Volo.Abp.Emailing.Smtp protected override async Task SendEmailAsync(MailMessage mail) { - using (var smtpClient = await BuildClientAsync()) + using (var smtpClient = await BuildClientAsync().ConfigureAwait(false)) { - await smtpClient.SendMailAsync(mail); + await smtpClient.SendMailAsync(mail).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProvider.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProvider.cs index c67af27757..61db6dec2e 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProvider.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProvider.cs @@ -27,12 +27,12 @@ namespace Volo.Abp.Emailing.Templates public async Task GetAsync(string name) { - return await GetAsync(name, CultureInfo.CurrentUICulture.Name); + return await GetAsync(name, CultureInfo.CurrentUICulture.Name).ConfigureAwait(false); } public async Task GetAsync(string name, string cultureName) { - return await GetInternalAsync(name, cultureName); + return await GetInternalAsync(name, cultureName).ConfigureAwait(false); } protected virtual async Task GetInternalAsync(string name, string cultureName) @@ -59,11 +59,11 @@ namespace Volo.Abp.Emailing.Templates { var emailTemplate = new EmailTemplate(emailTemplateString, emailTemplateDefinition); - await SetLayoutAsync(emailTemplateDefinition, emailTemplate, cultureName); + await SetLayoutAsync(emailTemplateDefinition, emailTemplate, cultureName).ConfigureAwait(false); if (emailTemplateDefinition.SingleTemplateFile) { - await LocalizeAsync(emailTemplateDefinition, emailTemplate, cultureName); + await LocalizeAsync(emailTemplateDefinition, emailTemplate, cultureName).ConfigureAwait(false); } return emailTemplate; @@ -87,7 +87,7 @@ namespace Volo.Abp.Emailing.Templates layout = Options.DefaultLayout; } - var layoutTemplate = await GetInternalAsync(layout, cultureName); + var layoutTemplate = await GetInternalAsync(layout, cultureName).ConfigureAwait(false); emailTemplate.SetLayout(layoutTemplate); } @@ -103,10 +103,10 @@ namespace Volo.Abp.Emailing.Templates var localizer = StringLocalizerFactory.Create(emailTemplateDefinition.LocalizationResource); if (cultureName != null) { - emailTemplate.SetContent( - TemplateLocalizer.Localize(localizer.WithCulture(new CultureInfo(cultureName)), - emailTemplate.Content) - ); + using (CultureHelper.Use(new CultureInfo(cultureName))) + { + emailTemplate.SetContent(TemplateLocalizer.Localize(localizer, emailTemplate.Content)); + } } else { diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/TemplateRender.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/TemplateRender.cs index 8c4e24017c..1713cf9f3f 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/TemplateRender.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/TemplateRender.cs @@ -9,7 +9,7 @@ namespace Volo.Abp.Emailing.Templates public async Task RenderAsync(string template, object model = null) { var scribanTemplate = Template.Parse(template); - return await scribanTemplate.RenderAsync(model); + return await scribanTemplate.RenderAsync(model).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj index b7f6fb276a..10f1f4e070 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.EntityFrameworkCore.MySQL Volo.Abp.EntityFrameworkCore.MySQL $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; @@ -18,7 +18,7 @@ - + diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj index 0154d1b773..13e4197209 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.EntityFrameworkCore.PostgreSql Volo.Abp.EntityFrameworkCore.PostgreSql $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj index d0d338be9d..3e3172003c 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.SqlServer/Volo.Abp.EntityFrameworkCore.SqlServer.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.EntityFrameworkCore.SqlServer Volo.Abp.EntityFrameworkCore.SqlServer $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj index d3c5313898..2ac575f23a 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Sqlite/Volo.Abp.EntityFrameworkCore.Sqlite.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.EntityFrameworkCore.Sqlite Volo.Abp.EntityFrameworkCore.Sqlite $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj b/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj index 3e83001eb2..0640cf10b9 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo.Abp.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.EntityFrameworkCore Volo.Abp.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index bfedcf2d66..7890b9b50d 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -40,44 +40,18 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore ); } - public override TEntity Insert(TEntity entity, bool autoSave = false) - { - var savedEntity = DbSet.Add(entity).Entity; - - if (autoSave) - { - DbContext.SaveChanges(); - } - - return savedEntity; - } - public override async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { var savedEntity = DbSet.Add(entity).Entity; if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } return savedEntity; } - public override TEntity Update(TEntity entity, bool autoSave = false) - { - DbContext.Attach(entity); - - var updatedEntity = DbContext.Update(entity).Entity; - - if (autoSave) - { - DbContext.SaveChanges(); - } - - return updatedEntity; - } - public override async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { DbContext.Attach(entity); @@ -86,54 +60,32 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } return updatedEntity; } - - public override void Delete(TEntity entity, bool autoSave = false) - { - DbSet.Remove(entity); - - if (autoSave) - { - DbContext.SaveChanges(); - } - } - + public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { DbSet.Remove(entity); if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } - public override List GetList(bool includeDetails = false) - { - return includeDetails - ? WithDetails().ToList() - : DbSet.ToList(); - } - public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { return includeDetails ? await WithDetails().ToListAsync(GetCancellationToken(cancellationToken)) - : await DbSet.ToListAsync(GetCancellationToken(cancellationToken)); - } - - public override long GetCount() - { - return DbSet.LongCount(); +.ConfigureAwait(false) : await DbSet.ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override async Task GetCountAsync(CancellationToken cancellationToken = default) { - return await DbSet.LongCountAsync(GetCancellationToken(cancellationToken)); + return await DbSet.LongCountAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } protected override IQueryable GetQueryable() @@ -141,21 +93,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return DbSet.AsQueryable(); } - public override void Delete(Expression> predicate, bool autoSave = false) - { - base.Delete(predicate, autoSave); - - if (autoSave) - { - DbContext.SaveChanges(); - } - } - public override async Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { var entities = await GetQueryable() .Where(predicate) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); foreach (var entity in entities) { @@ -164,7 +106,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } @@ -177,7 +119,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore await DbContext .Entry(entity) .Collection(propertyExpression) - .LoadAsync(GetCancellationToken(cancellationToken)); + .LoadAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task EnsurePropertyLoadedAsync( @@ -189,7 +131,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore await DbContext .Entry(entity) .Reference(propertyExpression) - .LoadAsync(GetCancellationToken(cancellationToken)); + .LoadAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override IQueryable WithDetails() @@ -245,7 +187,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore public virtual async Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - var entity = await FindAsync(id, includeDetails, GetCancellationToken(cancellationToken)); + var entity = await FindAsync(id, includeDetails, GetCancellationToken(cancellationToken)).ConfigureAwait(false); if (entity == null) { @@ -266,29 +208,18 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore { return includeDetails ? await WithDetails().FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)) - : await DbSet.FindAsync(new object[] { id }, GetCancellationToken(cancellationToken)); - } - - public virtual void Delete(TKey id, bool autoSave = false) - { - var entity = Find(id, includeDetails: false); - if (entity == null) - { - return; - } - - Delete(entity, autoSave); +.ConfigureAwait(false) : await DbSet.FindAsync(new object[] { id }, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { - var entity = await FindAsync(id, includeDetails: false, cancellationToken: cancellationToken); + var entity = await FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); if (entity == null) { return; } - await DeleteAsync(entity, autoSave, cancellationToken); + await DeleteAsync(entity, autoSave, cancellationToken).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 18758d98e3..422bca7d67 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -11,18 +11,17 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Newtonsoft.Json; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EntityFrameworkCore.EntityHistory; +using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.Reflection; -using Volo.Abp.Threading; using Volo.Abp.Timing; namespace Volo.Abp.EntityFrameworkCore @@ -68,6 +67,13 @@ namespace Volo.Abp.EntityFrameworkCore BindingFlags.Instance | BindingFlags.NonPublic ); + private static readonly MethodInfo ConfigureValueGeneratedMethodInfo + = typeof(AbpDbContext) + .GetMethod( + nameof(ConfigureValueGenerated), + BindingFlags.Instance | BindingFlags.NonPublic + ); + protected AbpDbContext(DbContextOptions options) : base(options) { @@ -90,48 +96,13 @@ namespace Volo.Abp.EntityFrameworkCore ConfigureValueConverterMethodInfo .MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); - } - } - - public override int SaveChanges(bool acceptAllChangesOnSuccess) - { - //TODO: Reduce duplications with SaveChangesAsync - //TODO: Instead of adding entity changes to audit log, write them to uow and add to audit log only if uow succeed - - try - { - var auditLog = AuditingManager?.Current?.Log; - List entityChangeList = null; - if (auditLog != null) - { - entityChangeList = EntityHistoryHelper.CreateChangeList(ChangeTracker.Entries().ToList()); - } - - var changeReport = ApplyAbpConcepts(); - - var result = base.SaveChanges(acceptAllChangesOnSuccess); - - AsyncHelper.RunSync(() => EntityChangeEventHelper.TriggerEventsAsync(changeReport)); - - if (auditLog != null) - { - EntityHistoryHelper.UpdateChangeList(entityChangeList); - auditLog.EntityChanges.AddRange(entityChangeList); - } - - return result; - } - catch (DbUpdateConcurrencyException ex) - { - throw new AbpDbConcurrencyException(ex.Message, ex); - } - finally - { - ChangeTracker.AutoDetectChangesEnabled = true; + ConfigureValueGeneratedMethodInfo + .MakeGenericMethod(entityType.ClrType) + .Invoke(this, new object[] { modelBuilder, entityType }); } } - + public override async Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) { try @@ -146,9 +117,9 @@ namespace Volo.Abp.EntityFrameworkCore var changeReport = ApplyAbpConcepts(); - var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken).ConfigureAwait(false); - await EntityChangeEventHelper.TriggerEventsAsync(changeReport); + await EntityChangeEventHelper.TriggerEventsAsync(changeReport).ConfigureAwait(false); if (auditLog != null) { @@ -352,147 +323,9 @@ namespace Volo.Abp.EntityFrameworkCore return; } - ConfigureConcurrencyStampProperty(modelBuilder, mutableEntityType); - ConfigureExtraProperties(modelBuilder, mutableEntityType); - ConfigureAuditProperties(modelBuilder, mutableEntityType); - ConfigureTenantIdProperty(modelBuilder, mutableEntityType); - ConfigureGlobalFilters(modelBuilder, mutableEntityType); - } - - protected virtual void ConfigureConcurrencyStampProperty(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (!typeof(IHasConcurrencyStamp).IsAssignableFrom(typeof(TEntity))) - { - return; - } - - modelBuilder.Entity(b => - { - b.Property(x => ((IHasConcurrencyStamp) x).ConcurrencyStamp) - .IsConcurrencyToken() - .HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp)); - }); - } - - protected virtual void ConfigureExtraProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (!typeof(IHasExtraProperties).IsAssignableFrom(typeof(TEntity))) - { - return; - } - - modelBuilder.Entity(b => - { - b.Property(x => ((IHasExtraProperties) x).ExtraProperties) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ) - .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)); - }); - } - - protected virtual void ConfigureAuditProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IHasCreationTime)x).CreationTime) - .IsRequired() - .HasColumnName(nameof(IHasCreationTime.CreationTime)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IMayHaveCreator)x).CreatorId) - .IsRequired(false) - .HasColumnName(nameof(IMayHaveCreator.CreatorId)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IMustHaveCreator)x).CreatorId) - .IsRequired() - .HasColumnName(nameof(IMustHaveCreator.CreatorId)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IHasModificationTime)x).LastModificationTime) - .IsRequired(false) - .HasColumnName(nameof(IHasModificationTime.LastModificationTime)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IModificationAuditedObject)x).LastModifierId) - .IsRequired(false) - .HasColumnName(nameof(IModificationAuditedObject.LastModifierId)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((ISoftDelete) x).IsDeleted) - .IsRequired() - .HasDefaultValue(false) - .HasColumnName(nameof(ISoftDelete.IsDeleted)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IHasDeletionTime)x).DeletionTime) - .IsRequired(false) - .HasColumnName(nameof(IHasDeletionTime.DeletionTime)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IDeletionAuditedObject)x).DeleterId) - .IsRequired(false) - .HasColumnName(nameof(IDeletionAuditedObject.DeleterId)); - }); - } - } + modelBuilder.Entity().ConfigureByConvention(); - protected virtual void ConfigureTenantIdProperty(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (!typeof(TEntity).IsAssignableTo()) - { - return; - } - - modelBuilder.Entity(b => - { - b.Property(x => ((IMultiTenant)x).TenantId) - .IsRequired(false) - .HasColumnName(nameof(IMultiTenant.TenantId)); - }); + ConfigureGlobalFilters(modelBuilder, mutableEntityType); } protected virtual void ConfigureGlobalFilters(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) @@ -541,6 +374,23 @@ namespace Volo.Abp.EntityFrameworkCore } } + protected virtual void ConfigureValueGenerated(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + where TEntity : class + { + if (!typeof(IEntity).IsAssignableFrom(typeof(TEntity))) + { + return; + } + + var idPropertyBuilder = modelBuilder.Entity().Property(x => ((IEntity) x).Id); + if (idPropertyBuilder.Metadata.PropertyInfo.IsDefined(typeof(DatabaseGeneratedAttribute), true)) + { + return; + } + + idPropertyBuilder.ValueGeneratedNever(); + } + protected virtual bool ShouldFilterEntity(IMutableEntityType entityType) where TEntity : class { if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity))) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs index 1a21e129f3..b9cf4e3ceb 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/AbpDbContextConfigurationContext.cs @@ -2,6 +2,8 @@ using System.Data.Common; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; namespace Volo.Abp.EntityFrameworkCore.DependencyInjection @@ -29,7 +31,8 @@ namespace Volo.Abp.EntityFrameworkCore.DependencyInjection ConnectionStringName = connectionStringName; ExistingConnection = existingConnection; - DbContextOptions = new DbContextOptionsBuilder(); + DbContextOptions = new DbContextOptionsBuilder() + .UseLoggerFactory(serviceProvider.GetRequiredService()); } } @@ -49,7 +52,8 @@ namespace Volo.Abp.EntityFrameworkCore.DependencyInjection connectionStringName, existingConnection) { - base.DbContextOptions = new DbContextOptionsBuilder(); + base.DbContextOptions = new DbContextOptionsBuilder() + .UseLoggerFactory(serviceProvider.GetRequiredService()); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs index 132e91c079..6db09d4d17 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Newtonsoft.Json; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; -using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.EntityFrameworkCore.ValueComparers; +using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.MultiTenancy; namespace Volo.Abp.EntityFrameworkCore.Modeling @@ -57,11 +57,9 @@ namespace Volo.Abp.EntityFrameworkCore.Modeling if (b.Metadata.ClrType.IsAssignableTo()) { b.Property>(nameof(IHasExtraProperties.ExtraProperties)) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ) - .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)); + .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)) + .HasConversion(new AbpJsonValueConverter>()) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/AbpDictionaryValueComparer.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/AbpDictionaryValueComparer.cs new file mode 100644 index 0000000000..c6959b0801 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/AbpDictionaryValueComparer.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace Volo.Abp.EntityFrameworkCore.ValueComparers +{ + public class AbpDictionaryValueComparer : ValueComparer> + { + public AbpDictionaryValueComparer() + : base( + (d1, d2) => d1.SequenceEqual(d2), + d => d.Aggregate(0, (k, v) => HashCode.Combine(k, v.GetHashCode())), + d => d.ToDictionary(k => k.Key, v => v.Value)) + { + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs new file mode 100644 index 0000000000..e77b2842a8 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs @@ -0,0 +1,15 @@ +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Newtonsoft.Json; + +namespace Volo.Abp.EntityFrameworkCore.ValueConverters +{ + public class AbpJsonValueConverter : ValueConverter + { + public AbpJsonValueConverter() + : base( + d => JsonConvert.SerializeObject(d, Formatting.None), + s => JsonConvert.DeserializeObject(s)) + { + } + } +} diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index c530437e6f..9df352837a 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -85,7 +85,7 @@ namespace Volo.Abp.EventBus.RabbitMq var eventData = Serializer.Deserialize(ea.Body, eventType); - await TriggerHandlersAsync(eventType, eventData); + await TriggerHandlersAsync(eventType, eventData).ConfigureAwait(false); } public IDisposable Subscribe(IDistributedEventHandler handler) where TEvent : class diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/ActionEventHandler.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/ActionEventHandler.cs index a8763edd89..3594ce3c96 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/ActionEventHandler.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/ActionEventHandler.cs @@ -32,7 +32,7 @@ namespace Volo.Abp.EventBus /// public async Task HandleEventAsync(TEvent eventData) { - await Action(eventData); + await Action(eventData).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index cb8ae75336..b77ed00945 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -89,7 +89,7 @@ namespace Volo.Abp.EventBus { var exceptions = new List(); - await TriggerHandlersAsync(eventType, eventData, exceptions); + await TriggerHandlersAsync(eventType, eventData, exceptions).ConfigureAwait(false); if (exceptions.Any()) { @@ -110,7 +110,7 @@ namespace Volo.Abp.EventBus { foreach (var handlerFactory in handlerFactories.EventHandlerFactories) { - await TriggerHandlerAsync(handlerFactory, handlerFactories.EventType, eventData, exceptions); + await TriggerHandlerAsync(handlerFactory, handlerFactories.EventType, eventData, exceptions).ConfigureAwait(false); } } @@ -126,7 +126,7 @@ namespace Volo.Abp.EventBus var baseEventType = eventType.GetGenericTypeDefinition().MakeGenericType(baseArg); var constructorArgs = ((IEventDataWithInheritableGenericArgument)eventData).GetConstructorArgs(); var baseEventData = Activator.CreateInstance(baseEventType, constructorArgs); - await PublishAsync(baseEventType, baseEventData); + await PublishAsync(baseEventType, baseEventData).ConfigureAwait(false); } } } @@ -171,7 +171,7 @@ namespace Volo.Abp.EventBus new[] { eventType } ); - await (Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData }); + await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })).ConfigureAwait(false); } else if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(IDistributedEventHandler<>))) { @@ -182,7 +182,7 @@ namespace Volo.Abp.EventBus new[] { eventType } ); - await (Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData }); + await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })).ConfigureAwait(false); } else { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index 7db5c18f01..117eeeb06f 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -119,7 +119,7 @@ namespace Volo.Abp.EventBus.Local { var exceptions = new List(); - await TriggerHandlersAsync(eventType, eventData, exceptions); + await TriggerHandlersAsync(eventType, eventData, exceptions).ConfigureAwait(false); if (exceptions.Any()) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs index 49ea1b3f4c..75c9c7ae5f 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.Features return null; } - return await FeatureStore.GetOrNullAsync(feature.Name, Name, editionId.Value.ToString()); + return await FeatureStore.GetOrNullAsync(feature.Name, Name, editionId.Value.ToString()).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs index 0c653c3448..0c90ea7573 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs @@ -46,7 +46,7 @@ namespace Volo.Abp.Features providers = providers.Where(p => featureDefinition.AllowedProviders.Contains(p.Name)); } - return await GetOrNullValueFromProvidersAsync(providers, featureDefinition); + return await GetOrNullValueFromProvidersAsync(providers, featureDefinition).ConfigureAwait(false); } protected virtual async Task GetOrNullValueFromProvidersAsync( @@ -55,7 +55,7 @@ namespace Volo.Abp.Features { foreach (var provider in providers) { - var value = await provider.GetOrNullAsync(feature); + var value = await provider.GetOrNullAsync(feature).ConfigureAwait(false); if (value != null) { return value; diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerBase.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerBase.cs index a24e0901f7..23c5c37431 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerBase.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerBase.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Features public virtual async Task IsEnabledAsync(string name) { - var value = await GetOrNullAsync(name); + var value = await GetOrNullAsync(name).ConfigureAwait(false); if (value == null) { return false; diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs index 8850408df0..d26f7be841 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureCheckerExtensions.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.Features Check.NotNull(featureChecker, nameof(featureChecker)); Check.NotNull(name, nameof(name)); - var value = await featureChecker.GetOrNullAsync(name); + var value = await featureChecker.GetOrNullAsync(name).ConfigureAwait(false); return value?.To() ?? defaultValue; } @@ -32,7 +32,7 @@ namespace Volo.Abp.Features { foreach (var featureName in featureNames) { - if (!(await featureChecker.IsEnabledAsync(featureName))) + if (!(await featureChecker.IsEnabledAsync(featureName).ConfigureAwait(false))) { return false; } @@ -43,7 +43,7 @@ namespace Volo.Abp.Features foreach (var featureName in featureNames) { - if (await featureChecker.IsEnabledAsync(featureName)) + if (await featureChecker.IsEnabledAsync(featureName).ConfigureAwait(false)) { return true; } @@ -54,7 +54,7 @@ namespace Volo.Abp.Features public static async Task CheckEnabledAsync(this IFeatureChecker featureChecker, string featureName) { - if (!(await featureChecker.IsEnabledAsync(featureName))) + if (!(await featureChecker.IsEnabledAsync(featureName).ConfigureAwait(false))) { throw new AbpAuthorizationException("Feature is not enabled: " + featureName); } @@ -71,7 +71,7 @@ namespace Volo.Abp.Features { foreach (var featureName in featureNames) { - if (!(await featureChecker.IsEnabledAsync(featureName))) + if (!(await featureChecker.IsEnabledAsync(featureName).ConfigureAwait(false))) { throw new AbpAuthorizationException( "Required features are not enabled. All of these features must be enabled: " + @@ -84,7 +84,7 @@ namespace Volo.Abp.Features { foreach (var featureName in featureNames) { - if (await featureChecker.IsEnabledAsync(featureName)) + if (await featureChecker.IsEnabledAsync(featureName).ConfigureAwait(false)) { return; } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureInterceptor.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureInterceptor.cs index 5fb7c54293..9f3d5dc356 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureInterceptor.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureInterceptor.cs @@ -2,7 +2,6 @@ using Volo.Abp.Aspects; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; -using Volo.Abp.Threading; namespace Volo.Abp.Features { @@ -16,28 +15,16 @@ namespace Volo.Abp.Features _methodInvocationFeatureCheckerService = methodInvocationFeatureCheckerService; } - public override void Intercept(IAbpMethodInvocation invocation) - { - if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.FeatureChecking)) - { - invocation.Proceed(); - return; - } - - AsyncHelper.RunSync(() => CheckFeaturesAsync(invocation)); - invocation.Proceed(); - } - public override async Task InterceptAsync(IAbpMethodInvocation invocation) { if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.FeatureChecking)) { - await invocation.ProceedAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); return; } - await CheckFeaturesAsync(invocation); - await invocation.ProceedAsync(); + await CheckFeaturesAsync(invocation).ConfigureAwait(false); + await invocation.ProceedAsync().ConfigureAwait(false); } protected virtual async Task CheckFeaturesAsync(IAbpMethodInvocation invocation) @@ -46,7 +33,7 @@ namespace Volo.Abp.Features new MethodInvocationFeatureCheckerContext( invocation.Method ) - ); + ).ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/MethodInvocationFeatureCheckerService.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/MethodInvocationFeatureCheckerService.cs index da7becc61f..bff6405d57 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/MethodInvocationFeatureCheckerService.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/MethodInvocationFeatureCheckerService.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Features foreach (var requiresFeatureAttribute in GetRequiredFeatureAttributes(context.Method)) { - await _featureChecker.CheckEnabledAsync(requiresFeatureAttribute.RequiresAll, requiresFeatureAttribute.Features); + await _featureChecker.CheckEnabledAsync(requiresFeatureAttribute.RequiresAll, requiresFeatureAttribute.Features).ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/TenantFeatureValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/TenantFeatureValueProvider.cs index 5ae4b5f876..71cdfe3f59 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/TenantFeatureValueProvider.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/TenantFeatureValueProvider.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Features public override async Task GetOrNullAsync(FeatureDefinition feature) { - return await FeatureStore.GetOrNullAsync(feature.Name, Name, CurrentTenant.Id?.ToString()); + return await FeatureStore.GetOrNullAsync(feature.Name, Name, CurrentTenant.Id?.ToString()).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj b/framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj index ffd81d0789..5510af3e25 100644 --- a/framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj +++ b/framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs b/framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs index f926782e2d..e699e0093a 100644 --- a/framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs +++ b/framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs @@ -32,7 +32,7 @@ namespace Volo.Abp.FluentValidation context.Errors.AddRange( result.Errors.Select( error => - new ValidationResult(error.ErrorMessage) + new ValidationResult(error.ErrorMessage, new[] { error.PropertyName }) ) ); } diff --git a/framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj b/framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj index 867565f395..c87b39d494 100644 --- a/framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj +++ b/framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs b/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs index 25763efbd5..efc61907dc 100644 --- a/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs +++ b/framework/src/Volo.Abp.Http.Client.IdentityModel/Volo/Abp/Http/Client/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Http.Client.IdentityModel { if (context.RemoteService.GetUseCurrentAccessToken() != false) { - var accessToken = await GetAccessTokenFromHttpContextOrNullAsync(); + var accessToken = await GetAccessTokenFromHttpContextOrNullAsync().ConfigureAwait(false); if (accessToken != null) { context.Request.SetBearerToken(accessToken); @@ -36,7 +36,7 @@ namespace Volo.Abp.Http.Client.IdentityModel await IdentityModelAuthenticationService.TryAuthenticateAsync( context.Client, context.RemoteService.GetIdentityClient() - ); + ).ConfigureAwait(false); } protected virtual async Task GetAccessTokenFromHttpContextOrNullAsync() @@ -47,7 +47,7 @@ namespace Volo.Abp.Http.Client.IdentityModel return null; } - return await httpContext.GetTokenAsync("access_token"); + return await httpContext.GetTokenAsync("access_token").ConfigureAwait(false); } } } diff --git a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs index 54387d2871..e3fd273026 100644 --- a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs +++ b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs @@ -8,6 +8,7 @@ using Volo.Abp; using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.Http.Client; using Volo.Abp.Http.Client.DynamicProxying; +using Volo.Abp.Validation; namespace Microsoft.Extensions.DependencyInjection { @@ -53,7 +54,7 @@ namespace Microsoft.Extensions.DependencyInjection foreach (var serviceType in serviceTypes) { services.AddHttpClientProxy( - serviceType, + serviceType, remoteServiceConfigurationName, asDefaultServices ); @@ -153,7 +154,10 @@ namespace Microsoft.Extensions.DependencyInjection var interceptorType = typeof(DynamicHttpProxyInterceptor<>).MakeGenericType(type); services.AddTransient(interceptorType); - var interceptorAdapterType = typeof(CastleAbpInterceptorAdapter<>).MakeGenericType(interceptorType); + var interceptorAdapterType = typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(interceptorType); + + var validationInterceptorAdapterType = + typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(typeof(ValidationInterceptor)); if (asDefaultService) { @@ -162,6 +166,7 @@ namespace Microsoft.Extensions.DependencyInjection serviceProvider => ProxyGeneratorInstance .CreateInterfaceProxyWithoutTarget( type, + (IInterceptor)serviceProvider.GetRequiredService(validationInterceptorAdapterType), (IInterceptor)serviceProvider.GetRequiredService(interceptorAdapterType) ) ); @@ -174,7 +179,8 @@ namespace Microsoft.Extensions.DependencyInjection var service = ProxyGeneratorInstance .CreateInterfaceProxyWithoutTarget( type, - (IInterceptor) serviceProvider.GetRequiredService(interceptorAdapterType) + (IInterceptor)serviceProvider.GetRequiredService(validationInterceptorAdapterType), + (IInterceptor)serviceProvider.GetRequiredService(interceptorAdapterType) ); return Activator.CreateInstance( diff --git a/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj b/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj index 8a5172db8b..e7198718b1 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj +++ b/framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj @@ -24,6 +24,7 @@ + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs index f2a7540956..e98c0738fd 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs @@ -3,6 +3,7 @@ using Volo.Abp.Castle; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; +using Volo.Abp.Validation; namespace Volo.Abp.Http.Client { @@ -10,7 +11,8 @@ namespace Volo.Abp.Http.Client typeof(AbpHttpModule), typeof(AbpCastleCoreModule), typeof(AbpThreadingModule), - typeof(AbpMultiTenancyModule) + typeof(AbpMultiTenancyModule), + typeof(AbpValidationModule) )] public class AbpHttpClientModule : AbpModule { diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs index 9d1ea2dbbe..b9932124be 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs @@ -27,12 +27,12 @@ namespace Volo.Abp.Http.Client.DynamicProxying string baseUrl, Func> factory) { - using (await _semaphore.LockAsync(CancellationTokenProvider.Token)) + using (await _semaphore.LockAsync(CancellationTokenProvider.Token).ConfigureAwait(false)) { var model = _cache.GetOrDefault(baseUrl); if (model == null) { - _cache[baseUrl] = model = await factory(); + _cache[baseUrl] = model = await factory().ConfigureAwait(false); } return model; diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs index 9b9c8e804c..eb57641c28 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying public async Task FindActionAsync(string baseUrl, Type serviceType, MethodInfo method) { - var apiDescription = await GetApiDescriptionAsync(baseUrl); + var apiDescription = await GetApiDescriptionAsync(baseUrl).ConfigureAwait(false); //TODO: Cache finding? @@ -78,7 +78,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying public virtual async Task GetApiDescriptionAsync(string baseUrl) { - return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(baseUrl)); + return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(baseUrl)).ConfigureAwait(false); } protected virtual async Task GetApiDescriptionFromServerAsync(string baseUrl) @@ -88,14 +88,14 @@ namespace Volo.Abp.Http.Client.DynamicProxying var response = await client.GetAsync( baseUrl.EnsureEndsWith('/') + "api/abp/api-definition", CancellationTokenProvider.Token - ); + ).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { throw new AbpException("Remote service returns error! StatusCode = " + response.StatusCode); } - var content = await response.Content.ReadAsStringAsync(); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var result = JsonConvert.DeserializeObject( content, diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs index d2b57d32ef..d60b79b3a5 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -74,48 +74,38 @@ namespace Volo.Abp.Http.Client.DynamicProxying Logger = NullLogger>.Instance; } - public override void Intercept(IAbpMethodInvocation invocation) + public override async Task InterceptAsync(IAbpMethodInvocation invocation) { - if (invocation.Method.ReturnType == typeof(void)) + if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) { - AsyncHelper.RunSync(() => MakeRequestAsync(invocation)); + await MakeRequestAsync(invocation).ConfigureAwait(false); } else { - var responseAsString = AsyncHelper.RunSync(() => MakeRequestAsync(invocation)); - - //TODO: Think on that - if (TypeHelper.IsPrimitiveExtended(invocation.Method.ReturnType, true)) - { - invocation.ReturnValue = Convert.ChangeType(responseAsString, invocation.Method.ReturnType); - } - else - { - invocation.ReturnValue = JsonSerializer.Deserialize( - invocation.Method.ReturnType, - responseAsString - ); - } + var result = (Task)GenericInterceptAsyncMethod + .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) + .Invoke(this, new object[] { invocation }); + + invocation.ReturnValue = await GetResultAsync( + result, + invocation.Method.ReturnType.GetGenericArguments()[0] + ).ConfigureAwait(false); } + } - public override Task InterceptAsync(IAbpMethodInvocation invocation) + private async Task GetResultAsync(Task task, Type resultType) { - if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) - { - return MakeRequestAsync(invocation); - } - - invocation.ReturnValue = GenericInterceptAsyncMethod - .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) - .Invoke(this, new object[] { invocation }); - - return Task.CompletedTask; + await task.ConfigureAwait(false); + return typeof(Task<>) + .MakeGenericType(resultType) + .GetProperty(nameof(Task.Result), BindingFlags.Instance | BindingFlags.Public) + .GetValue(task); } private async Task MakeRequestAndGetResultAsync(IAbpMethodInvocation invocation) { - var responseAsString = await MakeRequestAsync(invocation); + var responseAsString = await MakeRequestAsync(invocation).ConfigureAwait(false); //TODO: Think on that if (TypeHelper.IsPrimitiveExtended(typeof(T), true)) @@ -133,7 +123,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying var client = HttpClientFactory.Create(clientConfig.RemoteServiceName); - var action = await ApiDescriptionFinder.FindActionAsync(remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method); + var action = await ApiDescriptionFinder.FindActionAsync(remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method).ConfigureAwait(false); var apiVersion = GetApiVersionInfo(action); var url = remoteServiceConfig.BaseUrl.EnsureEndsWith('/') + UrlBuilder.GenerateUrlWithParameters(action, invocation.ArgumentsDictionary, apiVersion); @@ -151,19 +141,18 @@ namespace Volo.Abp.Http.Client.DynamicProxying remoteServiceConfig, clientConfig.RemoteServiceName ) - ); + ).ConfigureAwait(false); - var response = await client.SendAsync(requestMessage, GetCancellationToken()); + var response = await client.SendAsync(requestMessage, GetCancellationToken()).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { - await ThrowExceptionForResponseAsync(response); + await ThrowExceptionForResponseAsync(response).ConfigureAwait(false); } - return await response.Content.ReadAsStringAsync(); + return await response.Content.ReadAsStringAsync().ConfigureAwait(false); } - private ApiVersionInfo GetApiVersionInfo(ActionApiDescriptionModel action) { var apiVersion = FindBestApiVersion(action); @@ -251,7 +240,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying { var errorResponse = JsonSerializer.Deserialize( await response.Content.ReadAsStringAsync() - ); +.ConfigureAwait(false)); throw new AbpRemoteCallException(errorResponse.Error); } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptManager.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptManager.cs index 858b78a57f..a3df2c70a2 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptManager.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptManager.cs @@ -18,21 +18,18 @@ namespace Volo.Abp.Http.ProxyScripting private readonly IJsonSerializer _jsonSerializer; private readonly IProxyScriptManagerCache _cache; private readonly AbpApiProxyScriptingOptions _options; - private readonly IJavascriptMinifier _javascriptMinifier; public ProxyScriptManager( IApiDescriptionModelProvider modelProvider, IServiceProvider serviceProvider, IJsonSerializer jsonSerializer, IProxyScriptManagerCache cache, - IOptions options, - IJavascriptMinifier javascriptMinifier) + IOptions options) { _modelProvider = modelProvider; _serviceProvider = serviceProvider; _jsonSerializer = jsonSerializer; _cache = cache; - _javascriptMinifier = javascriptMinifier; _options = options.Value; } @@ -67,8 +64,7 @@ namespace Volo.Abp.Http.ProxyScripting using (var scope = _serviceProvider.CreateScope()) { - var script = scope.ServiceProvider.GetRequiredService(generatorType).As().CreateScript(apiModel); - return scriptingModel.Minify ? _javascriptMinifier.Minify(script) : script; + return scope.ServiceProvider.GetRequiredService(generatorType).As().CreateScript(apiModel); } } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs index 6815c01ce5..5ab85a781b 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/ProxyScriptingModel.cs @@ -8,8 +8,6 @@ namespace Volo.Abp.Http.ProxyScripting public bool UseCache { get; set; } - public bool Minify { get; set; } - public string[] Modules { get; set; } public string[] Controllers { get; set; } @@ -18,11 +16,10 @@ namespace Volo.Abp.Http.ProxyScripting public IDictionary Properties { get; set; } - public ProxyScriptingModel(string generatorType, bool useCache = true, bool minify = false) + public ProxyScriptingModel(string generatorType, bool useCache = true) { GeneratorType = generatorType; UseCache = useCache; - Minify = minify; Properties = new Dictionary(); } diff --git a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj index 0d8ef11967..886e092fdd 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj +++ b/framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs index ca6e41d60d..488745836e 100644 --- a/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs +++ b/framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs @@ -35,7 +35,7 @@ namespace Volo.Abp.IdentityModel [NotNull] HttpClient client, string identityClientName = null) { - var accessToken = await GetAccessTokenOrNullAsync(identityClientName); + var accessToken = await GetAccessTokenOrNullAsync(identityClientName).ConfigureAwait(false); if (accessToken == null) { return false; @@ -55,18 +55,18 @@ namespace Volo.Abp.IdentityModel return null; } - return await GetAccessTokenAsync(configuration); + return await GetAccessTokenAsync(configuration).ConfigureAwait(false); } public virtual async Task GetAccessTokenAsync(IdentityClientConfiguration configuration) { - var discoveryResponse = await GetDiscoveryResponse(configuration); + var discoveryResponse = await GetDiscoveryResponse(configuration).ConfigureAwait(false); if (discoveryResponse.IsError) { throw new AbpException($"Could not retrieve the OpenId Connect discovery document! ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}"); } - var tokenResponse = await GetTokenResponse(discoveryResponse, configuration); + var tokenResponse = await GetTokenResponse(discoveryResponse, configuration).ConfigureAwait(false); if (tokenResponse.IsError) { throw new AbpException($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}"); @@ -104,7 +104,7 @@ namespace Volo.Abp.IdentityModel { RequireHttps = configuration.RequireHttps } - }); + }).ConfigureAwait(false); } } @@ -118,14 +118,14 @@ namespace Volo.Abp.IdentityModel { case OidcConstants.GrantTypes.ClientCredentials: return await httpClient.RequestClientCredentialsTokenAsync( - await CreateClientCredentialsTokenRequestAsync(discoveryResponse, configuration), + await CreateClientCredentialsTokenRequestAsync(discoveryResponse, configuration).ConfigureAwait(false), CancellationTokenProvider.Token - ); + ).ConfigureAwait(false); case OidcConstants.GrantTypes.Password: return await httpClient.RequestPasswordTokenAsync( - await CreatePasswordTokenRequestAsync(discoveryResponse, configuration), + await CreatePasswordTokenRequestAsync(discoveryResponse, configuration).ConfigureAwait(false), CancellationTokenProvider.Token - ); + ).ConfigureAwait(false); default: throw new AbpException("Grant type was not implemented: " + configuration.GrantType); } diff --git a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj index 8964f2f4fe..d5407991c1 100644 --- a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj +++ b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj @@ -1,4 +1,4 @@ - + @@ -14,7 +14,7 @@ - + diff --git a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj index 65ceed101e..aad9dcf58d 100644 --- a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj +++ b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj @@ -14,11 +14,12 @@ + - + diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index b1741d0ca0..79c164eb5f 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -31,8 +31,7 @@ namespace Volo.Abp.Localization includeParentCultures ); } - - + public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers) { return GetAllStrings( @@ -42,6 +41,7 @@ namespace Volo.Abp.Localization ); } + [Obsolete("This method is obsolete. Use `CurrentCulture` and `CurrentUICulture` instead.")] public IStringLocalizer WithCulture(CultureInfo culture) { return new CultureWrapperStringLocalizer(culture.Name, this); @@ -71,10 +71,13 @@ namespace Volo.Abp.Localization { foreach (var baseLocalizer in BaseLocalizers) { - var baseLocalizedString = baseLocalizer.WithCulture(CultureInfo.GetCultureInfo(cultureName))[name]; - if (baseLocalizedString != null && !baseLocalizedString.ResourceNotFound) + using (CultureHelper.Use(CultureInfo.GetCultureInfo(cultureName))) { - return baseLocalizedString; + var baseLocalizedString = baseLocalizer[name]; + if (baseLocalizedString != null && !baseLocalizedString.ResourceNotFound) + { + return baseLocalizedString; + } } } @@ -133,20 +136,23 @@ namespace Volo.Abp.Localization if (includeBaseLocalizers) { - foreach (var baseLocalizer in BaseLocalizers.Select(l => l.WithCulture(CultureInfo.GetCultureInfo(cultureName)))) + foreach (var baseLocalizer in BaseLocalizers.Select(l => l)) { - //TODO: Try/catch is a workaround here! - try + using (CultureHelper.Use(CultureInfo.GetCultureInfo(cultureName))) { - var baseLocalizedString = baseLocalizer.GetAllStrings(includeParentCultures); - foreach (var localizedString in baseLocalizedString) + //TODO: Try/catch is a workaround here! + try { - allStrings[localizedString.Name] = localizedString; + var baseLocalizedString = baseLocalizer.GetAllStrings(includeParentCultures); + foreach (var localizedString in baseLocalizedString) + { + allStrings[localizedString.Name] = localizedString; + } } - } - catch (MissingManifestResourceException) - { + catch (MissingManifestResourceException) + { + } } } } @@ -199,6 +205,7 @@ namespace Volo.Abp.Localization return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures); } + [Obsolete("This method is obsolete. Use `CurrentCulture` and `CurrentUICulture` instead.")] public IStringLocalizer WithCulture(CultureInfo culture) { return new CultureWrapperStringLocalizer(culture.Name, _innerLocalizer); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 60df66feec..be39960b4f 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -1,4 +1,4 @@ -using Volo.Abp.Localization.Resources.AbpValidation; +using Volo.Abp.Localization.Resources.AbpLocalization; using Volo.Abp.Modularity; using Volo.Abp.Settings; using Volo.Abp.VirtualFileSystem; @@ -29,8 +29,8 @@ namespace Volo.Abp.Localization options .Resources - .Add("en") - .AddVirtualJson("/Localization/Resources/AbpValidation"); + .Add("en") + .AddVirtualJson("/Localization/Resources/AbpLocalization"); }); } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs index c748156506..127d2550dd 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Settings; +using Volo.Abp.Localization.Resources.AbpLocalization; +using Volo.Abp.Settings; namespace Volo.Abp.Localization { @@ -7,8 +8,17 @@ namespace Volo.Abp.Localization public override void Define(ISettingDefinitionContext context) { context.Add( - new SettingDefinition(LocalizationSettingNames.DefaultLanguage, "en", isVisibleToClients: true) + new SettingDefinition(LocalizationSettingNames.DefaultLanguage, + "en", + L("DisplayName:Abp.Localization.DefaultLanguage"), + L("Description:Abp.Localization.DefaultLanguage"), + isVisibleToClients: true) ); } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/AbpLocalizationResource.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/AbpLocalizationResource.cs new file mode 100644 index 0000000000..7e3b5400c9 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/AbpLocalizationResource.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.Localization.Resources.AbpLocalization +{ + [LocalizationResourceName("AbpLocalization")] + public class AbpLocalizationResource + { + + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json new file mode 100644 index 0000000000..bea8d0379b --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/cs.json @@ -0,0 +1,7 @@ +{ + "culture": "cs", + "texts": { + "DisplayName:Abp.Localization.DefaultLanguage": "Výchozí jazyk", + "Description:Abp.Localization.DefaultLanguage": "Váchozí jazyk aplikace." + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/en.json b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/en.json new file mode 100644 index 0000000000..aee47a44b6 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/en.json @@ -0,0 +1,7 @@ +{ + "culture": "en", + "texts": { + "DisplayName:Abp.Localization.DefaultLanguage": "Default language", + "Description:Abp.Localization.DefaultLanguage": "The default language of the application." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/zh-Hans.json b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/zh-Hans.json new file mode 100644 index 0000000000..7167aac9fd --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hans", + "texts": { + "DisplayName:Abp.Localization.DefaultLanguage": "默认语言", + "Description:Abp.Localization.DefaultLanguage": "应用程序的默认语言." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/zh-Hant.json b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/zh-Hant.json new file mode 100644 index 0000000000..9ff62f43bb --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpLocalization/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "DisplayName:Abp.Localization.DefaultLanguage": "預設語系", + "Description:Abp.Localization.DefaultLanguage": "應用程式的預設語系." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs index da99e7d4de..f798ebf01e 100644 --- a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs @@ -30,11 +30,11 @@ namespace Volo.Abp.MailKit protected override async Task SendEmailAsync(MailMessage mail) { - using (var client = await BuildClientAsync()) + using (var client = await BuildClientAsync().ConfigureAwait(false)) { var message = MimeMessage.CreateFromMailMessage(mail); - await client.SendAsync(message); - await client.DisconnectAsync(true); + await client.SendAsync(message).ConfigureAwait(false); + await client.DisconnectAsync(true).ConfigureAwait(false); } } @@ -44,7 +44,7 @@ namespace Volo.Abp.MailKit try { - await ConfigureClient(client); + await ConfigureClient(client).ConfigureAwait(false); return client; } catch @@ -57,20 +57,20 @@ namespace Volo.Abp.MailKit protected virtual async Task ConfigureClient(SmtpClient client) { client.Connect( - await SmtpConfiguration.GetHostAsync(), - await SmtpConfiguration.GetPortAsync(), + await SmtpConfiguration.GetHostAsync().ConfigureAwait(false), + await SmtpConfiguration.GetPortAsync().ConfigureAwait(false), await GetSecureSocketOption() - ); +.ConfigureAwait(false)); - if (await SmtpConfiguration.GetUseDefaultCredentialsAsync()) + if (await SmtpConfiguration.GetUseDefaultCredentialsAsync().ConfigureAwait(false)) { return; } client.Authenticate( - await SmtpConfiguration.GetUserNameAsync(), + await SmtpConfiguration.GetUserNameAsync().ConfigureAwait(false), await SmtpConfiguration.GetPasswordAsync() - ); +.ConfigureAwait(false)); } protected virtual async Task GetSecureSocketOption() @@ -81,7 +81,7 @@ namespace Volo.Abp.MailKit } return await SmtpConfiguration.GetEnableSslAsync() - ? SecureSocketOptions.SslOnConnect +.ConfigureAwait(false) ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTlsWhenAvailable; } } diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 68b9beeb6e..d554e09de1 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Entities; @@ -25,40 +26,52 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb DatabaseProvider = databaseProvider; } - public override TEntity Insert(TEntity entity, bool autoSave = false) + protected override IQueryable GetQueryable() { - Collection.Add(entity); - return entity; + return ApplyDataFilters(Collection.AsQueryable()); } - public override TEntity Update(TEntity entity, bool autoSave = false) + public override Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { - Collection.Update(entity); - return entity; + var entities = Collection.AsQueryable().Where(predicate).ToList(); + foreach (var entity in entities) + { + Collection.Remove(entity); + } + + return Task.CompletedTask; } - public override void Delete(TEntity entity, bool autoSave = false) + public override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - Collection.Remove(entity); + Collection.Add(entity); + return Task.FromResult(entity); + } + + public override Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + { + Collection.Update(entity); + return Task.FromResult(entity); } - public override List GetList(bool includeDetails = false) + public override Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - return Collection.ToList(); + Collection.Remove(entity); + return Task.CompletedTask; } - public override long GetCount() + public override Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { - return Collection.Count(); + return Task.FromResult(Collection.ToList()); } - protected override IQueryable GetQueryable() + public override Task GetCountAsync(CancellationToken cancellationToken = default) { - return ApplyDataFilters(Collection.AsQueryable()); + return Task.FromResult(Collection.LongCount()); } } - public class MemoryDbRepository : MemoryDbRepository, IMemoryDbRepository + public class MemoryDbRepository : MemoryDbRepository, IMemoryDbRepository where TMemoryDbContext : MemoryDbContext where TEntity : class, IEntity { @@ -67,16 +80,16 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { } - public override TEntity Insert(TEntity entity, bool autoSave = false) + public override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { SetIdIfNeeded(entity); - return base.Insert(entity, autoSave); + return base.InsertAsync(entity, autoSave, cancellationToken); } protected virtual void SetIdIfNeeded(TEntity entity) { - if (typeof(TKey) == typeof(int) || - typeof(TKey) == typeof(long) || + if (typeof(TKey) == typeof(int) || + typeof(TKey) == typeof(long) || typeof(TKey) == typeof(Guid)) { if (EntityHelper.HasDefaultId(entity)) @@ -86,14 +99,9 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb } } - public virtual TEntity Find(TKey id, bool includeDetails = true) - { - return GetQueryable().FirstOrDefault(e => e.Id.Equals(id)); - } - - public virtual TEntity Get(TKey id, bool includeDetails = true) + public virtual async Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - var entity = Find(id, includeDetails); + var entity = await FindAsync(id, includeDetails, cancellationToken).ConfigureAwait(false); if (entity == null) { @@ -103,31 +111,20 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return entity; } - public virtual Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) - { - return Task.FromResult(Get(id, includeDetails)); - } - public virtual Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - return Task.FromResult(Find(id, includeDetails)); + return Task.FromResult(GetQueryable().FirstOrDefault(e => e.Id.Equals(id))); } - public virtual void Delete(TKey id, bool autoSave = false) + public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { - var entity = Find(id); + var entity = await FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); if (entity == null) { return; } - Delete(entity); - } - - public virtual Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) - { - Delete(id); - return Task.CompletedTask; + await DeleteAsync(entity, autoSave, cancellationToken).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj b/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj index 9f07fb9346..5cf143f99a 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj +++ b/framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 057f72bbb5..1ee3cbf80d 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -53,62 +53,17 @@ namespace Volo.Abp.Domain.Repositories.MongoDB EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; } - public override TEntity Insert(TEntity entity, bool autoSave = false) - { - /* EntityCreatedEvent (OnUowCompleted) is triggered as the first because it should be - * triggered before other events triggered inside an EntityCreating event handler. - * This is also true for other "ed" & "ing" events. - */ - - AsyncHelper.RunSync(() => ApplyAbpConceptsForAddedEntityAsync(entity)); - - Collection.InsertOne(entity); - - return entity; - } - public override async Task InsertAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - await ApplyAbpConceptsForAddedEntityAsync(entity); + await ApplyAbpConceptsForAddedEntityAsync(entity).ConfigureAwait(false); await Collection.InsertOneAsync( entity, cancellationToken: GetCancellationToken(cancellationToken) - ); - - return entity; - } - - public override TEntity Update(TEntity entity, bool autoSave = false) - { - SetModificationAuditProperties(entity); - - if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted) - { - SetDeletionAuditProperties(entity); - AsyncHelper.RunSync(() => TriggerEntityDeleteEventsAsync(entity)); - } - else - { - AsyncHelper.RunSync(() => TriggerEntityUpdateEventsAsync(entity)); - } - - AsyncHelper.RunSync(() => TriggerDomainEventsAsync(entity)); - - var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); - - var result = Collection.ReplaceOne( - CreateEntityFilter(entity, true, oldConcurrencyStamp), - entity - ); - - if (result.MatchedCount <= 0) - { - ThrowOptimisticConcurrencyException(); - } + ).ConfigureAwait(false); return entity; } @@ -123,14 +78,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); + await TriggerEntityDeleteEventsAsync(entity).ConfigureAwait(false); } else { - await TriggerEntityUpdateEventsAsync(entity); + await TriggerEntityUpdateEventsAsync(entity).ConfigureAwait(false); } - await TriggerDomainEventsAsync(entity); + await TriggerDomainEventsAsync(entity).ConfigureAwait(false); var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); @@ -138,7 +93,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB CreateEntityFilter(entity, true, oldConcurrencyStamp), entity, cancellationToken: GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); if (result.MatchedCount <= 0) { @@ -148,43 +103,12 @@ namespace Volo.Abp.Domain.Repositories.MongoDB return entity; } - public override void Delete(TEntity entity, bool autoSave = false) - { - AsyncHelper.RunSync(() => ApplyAbpConceptsForDeletedEntityAsync(entity)); - var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); - - if (entity is ISoftDelete softDeleteEntity) - { - softDeleteEntity.IsDeleted = true; - var result = Collection.ReplaceOne( - CreateEntityFilter(entity, true, oldConcurrencyStamp), - entity - ); - - if (result.MatchedCount <= 0) - { - ThrowOptimisticConcurrencyException(); - } - } - else - { - var result = Collection.DeleteOne( - CreateEntityFilter(entity, true, oldConcurrencyStamp) - ); - - if (result.DeletedCount <= 0) - { - ThrowOptimisticConcurrencyException(); - } - } - } - public override async Task DeleteAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - await ApplyAbpConceptsForDeletedEntityAsync(entity); + await ApplyAbpConceptsForDeletedEntityAsync(entity).ConfigureAwait(false); var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); if (entity is ISoftDelete softDeleteEntity) @@ -194,7 +118,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB CreateEntityFilter(entity, true, oldConcurrencyStamp), entity, cancellationToken: GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); if (result.MatchedCount <= 0) { @@ -206,7 +130,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB var result = await Collection.DeleteOneAsync( CreateEntityFilter(entity, true, oldConcurrencyStamp), GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); if (result.DeletedCount <= 0) { @@ -215,36 +139,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } } - public override List GetList(bool includeDetails = false) - { - return GetMongoQueryable().ToList(); - } - public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().ToListAsync(GetCancellationToken(cancellationToken)); - } - - public override long GetCount() - { - return GetMongoQueryable().LongCount(); + return await GetMongoQueryable().ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override async Task GetCountAsync(CancellationToken cancellationToken = default) { - return await GetMongoQueryable().LongCountAsync(GetCancellationToken(cancellationToken)); - } - - public override void Delete(Expression> predicate, bool autoSave = false) - { - var entities = GetMongoQueryable() - .Where(predicate) - .ToList(); - - foreach (var entity in entities) - { - Delete(entity, autoSave); - } + return await GetMongoQueryable().LongCountAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override async Task DeleteAsync( @@ -254,11 +156,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { var entities = await GetMongoQueryable() .Where(predicate) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); foreach (var entity in entities) { - await DeleteAsync(entity, autoSave, cancellationToken); + await DeleteAsync(entity, autoSave, cancellationToken).ConfigureAwait(false); } } @@ -285,33 +187,33 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { CheckAndSetId(entity); SetCreationAuditProperties(entity); - await TriggerEntityCreateEvents(entity); - await TriggerDomainEventsAsync(entity); + await TriggerEntityCreateEvents(entity).ConfigureAwait(false); + await TriggerDomainEventsAsync(entity).ConfigureAwait(false); } private async Task TriggerEntityCreateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity); - await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity).ConfigureAwait(false); + await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity).ConfigureAwait(false); } protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity); - await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity).ConfigureAwait(false); + await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity).ConfigureAwait(false); } protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); - await TriggerDomainEventsAsync(entity); + await TriggerEntityDeleteEventsAsync(entity).ConfigureAwait(false); + await TriggerDomainEventsAsync(entity).ConfigureAwait(false); } protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity); - await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity).ConfigureAwait(false); + await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity).ConfigureAwait(false); } protected virtual void CheckAndSetId(TEntity entity) @@ -364,7 +266,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { foreach (var localEvent in localEvents) { - await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent); + await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent).ConfigureAwait(false); } generatesDomainEventsEntity.ClearLocalEvents(); @@ -375,7 +277,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { foreach (var distributedEvent in distributedEvents) { - await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent); + await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent).ConfigureAwait(false); } generatesDomainEventsEntity.ClearDistributedEvents(); @@ -417,24 +319,12 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } - public virtual TEntity Get(TKey id, bool includeDetails = true) - { - var entity = Find(id, includeDetails); - - if (entity == null) - { - throw new EntityNotFoundException(typeof(TEntity), id); - } - - return entity; - } - public virtual async Task GetAsync( TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - var entity = await FindAsync(id, includeDetails, cancellationToken); + var entity = await FindAsync(id, includeDetails, cancellationToken).ConfigureAwait(false); if (entity == null) { @@ -451,17 +341,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { return await Collection .Find(CreateEntityFilter(id, true)) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); - } - - public virtual TEntity Find(TKey id, bool includeDetails = true) - { - return Collection.Find(CreateEntityFilter(id, true)).FirstOrDefault(); - } - - public virtual void Delete(TKey id, bool autoSave = false) - { - Collection.DeleteOne(CreateEntityFilter(id)); + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual Task DeleteAsync( diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfiguration.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfiguration.cs index 37ad3c74da..0ba64417a3 100644 --- a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfiguration.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/TenantConfiguration.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.MultiTenancy public string Name { get; set; } - public ConnectionStrings ConnectionStrings { get; } + public ConnectionStrings ConnectionStrings { get; set; } public TenantConfiguration() { diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs index 1214a82a99..8e136fc2ac 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs @@ -63,13 +63,13 @@ namespace Volo.Abp.RabbitMQ public virtual async Task BindAsync(string routingKey) { QueueBindCommands.Enqueue(new QueueBindCommand(QueueBindType.Bind, routingKey)); - await TrySendQueueBindCommandsAsync(); + await TrySendQueueBindCommandsAsync().ConfigureAwait(false); } public virtual async Task UnbindAsync(string routingKey) { QueueBindCommands.Enqueue(new QueueBindCommand(QueueBindType.Unbind, routingKey)); - await TrySendQueueBindCommandsAsync(); + await TrySendQueueBindCommandsAsync().ConfigureAwait(false); } protected virtual void TrySendQueueBindCommands() @@ -166,7 +166,7 @@ namespace Volo.Abp.RabbitMQ var consumer = new EventingBasicConsumer(channel); consumer.Received += async (model, basicDeliverEventArgs) => { - await HandleIncomingMessage(channel, basicDeliverEventArgs); + await HandleIncomingMessage(channel, basicDeliverEventArgs).ConfigureAwait(false); }; channel.BasicConsume( @@ -189,7 +189,7 @@ namespace Volo.Abp.RabbitMQ { foreach (var callback in Callbacks) { - await callback(channel, basicDeliverEventArgs); + await callback(channel, basicDeliverEventArgs).ConfigureAwait(false); } channel.BasicAck(basicDeliverEventArgs.DeliveryTag, multiple: false); diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs index 6f5372a4cf..7694ca219f 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.Settings //TODO: How to implement setting.IsInherited? - var value = await GetOrNullValueFromProvidersAsync(providers, setting); + var value = await GetOrNullValueFromProvidersAsync(providers, setting).ConfigureAwait(false); if (setting.IsEncrypted) { value = SettingEncryptionService.Decrypt(setting, value); @@ -52,7 +52,7 @@ namespace Volo.Abp.Settings { foreach (var setting in settingDefinitions) { - var value = await provider.GetOrNullAsync(setting); + var value = await provider.GetOrNullAsync(setting).ConfigureAwait(false); if (value != null) { if (setting.IsEncrypted) @@ -74,7 +74,7 @@ namespace Volo.Abp.Settings { foreach (var provider in providers) { - var value = await provider.GetOrNullAsync(setting); + var value = await provider.GetOrNullAsync(setting).ConfigureAwait(false); if (value != null) { return value; diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProviderExtensions.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProviderExtensions.cs index fb67c4ae77..eb7e3c341c 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProviderExtensions.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProviderExtensions.cs @@ -12,7 +12,7 @@ namespace Volo.Abp.Settings Check.NotNull(name, nameof(name)); return string.Equals( - await settingProvider.GetOrNullAsync(name), + await settingProvider.GetOrNullAsync(name).ConfigureAwait(false), "true", StringComparison.OrdinalIgnoreCase ); @@ -24,7 +24,7 @@ namespace Volo.Abp.Settings Check.NotNull(settingProvider, nameof(settingProvider)); Check.NotNull(name, nameof(name)); - var value = await settingProvider.GetOrNullAsync(name); + var value = await settingProvider.GetOrNullAsync(name).ConfigureAwait(false); return value?.To() ?? defaultValue; } } diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs index eab23b7258..408f70aac9 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Settings public override async Task GetOrNullAsync(SettingDefinition setting) { - return await SettingStore.GetOrNullAsync(setting.Name, Name, CurrentTenant.Id?.ToString()); + return await SettingStore.GetOrNullAsync(setting.Name, Name, CurrentTenant.Id?.ToString()).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs index 01125f3201..a3df714c00 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.Settings return null; } - return await SettingStore.GetOrNullAsync(setting.Name, Name, CurrentUser.Id.ToString()); + return await SettingStore.GetOrNullAsync(setting.Name, Name, CurrentUser.Id.ToString()).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.TestBase/Volo/Abp/AbpIntegratedTest.cs b/framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/AbpIntegratedTest.cs similarity index 96% rename from framework/src/Volo.Abp.TestBase/Volo/Abp/AbpIntegratedTest.cs rename to framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/AbpIntegratedTest.cs index 587d0d52db..96043f8220 100644 --- a/framework/src/Volo.Abp.TestBase/Volo/Abp/AbpIntegratedTest.cs +++ b/framework/src/Volo.Abp.TestBase/Volo/Abp/Testing/AbpIntegratedTest.cs @@ -2,10 +2,8 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; -namespace Volo.Abp +namespace Volo.Abp.Testing { - //TODO: Move to "Testing" namespace - public abstract class AbpIntegratedTest : AbpTestBaseWithServiceProvider, IDisposable where TStartupModule : IAbpModule { diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/zh-Hant.json b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/zh-Hant.json new file mode 100644 index 0000000000..a592b42fff --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hant", + "texts": { + "Menu:Administration": "管理" + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index 5c33866aa2..7ca2baa6b0 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -30,7 +30,7 @@ namespace Volo.Abp.UI.Navigation foreach (var contributor in Options.MenuContributors) { - await contributor.ConfigureMenuAsync(context); + await contributor.ConfigureMenuAsync(context).ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs index ffa31e66a2..fed4235087 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Urls/AppUrlProvider.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.UI.Navigation.Urls appName, urlName ) - ); +.ConfigureAwait(false)).ConfigureAwait(false); } protected virtual Task GetConfiguredUrl(string appName, string urlName) @@ -89,7 +89,7 @@ namespace Volo.Abp.UI.Navigation.Urls if (CurrentTenant.Id.HasValue) { - url = url.Replace(tenantNamePlaceHolder, await GetCurrentTenantNameAsync()); + url = url.Replace(tenantNamePlaceHolder, await GetCurrentTenantNameAsync().ConfigureAwait(false)); } else { @@ -103,7 +103,7 @@ namespace Volo.Abp.UI.Navigation.Urls { if (CurrentTenant.Id.HasValue && CurrentTenant.Name.IsNullOrEmpty()) { - var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value); + var tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value).ConfigureAwait(false); return tenantConfiguration.Name; } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json index b67fc568b3..28c9a5e33f 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json @@ -46,6 +46,13 @@ "DatatableActionDropdownDefaultText": "Akce", "ChangePassword": "Změnit heslo", "PersonalInfo": "Můj profil", - "AreYouSureYouWantToCancelEditingWarningMessage": "Máte neuložené změny." + "AreYouSureYouWantToCancelEditingWarningMessage": "Máte neuložené změny.", + "UnhandledException": "Neošetřená výjimka!", + "401Message": "Neoprávněno", + "403Message": "Zakázáno", + "404Message": "Stránka nenalezena", + "500Message": "Interní chyba serveru", + "GoHomePage": "Přejít na domovskou stránku", + "GoBack": "Jít zpět" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json new file mode 100644 index 0000000000..d19dc7cbc6 --- /dev/null +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json @@ -0,0 +1,58 @@ +{ + "culture": "zh-Hant", + "texts": { + "InternalServerErrorMessage": "對不起,在處理你的請求期間,產生了一個伺服器內部錯誤!", + "ValidationErrorMessage": "你的請求無效!", + "ValidationNarrativeErrorMessageTitle": "驗證時發現以下錯誤.", + "DefaultErrorMessage": "發生錯誤!", + "DefaultErrorMessageDetail": "伺服器未發送錯誤的詳細信息.", + "DefaultErrorMessage401": "未通過身份驗證!", + "DefaultErrorMessage401Detail": "你需要進行身份認證(登入)後再執行此操作.", + "DefaultErrorMessage403": "你沒有權限!", + "DefaultErrorMessage403Detail": "你不能執行此操作!", + "DefaultErrorMessage404": "未找到資源!", + "DefaultErrorMessage404Detail": "未在服務中找到請求的資源!", + "EntityNotFoundErrorMessage": "實體 {0} 不存在,id = {1}!", + "Error": "錯誤", + "AreYouSure": "你確定嗎?", + "Cancel": "取消", + "Yes": "是", + "No": "否", + "Close": "關閉", + "Save": "保存", + "SavingWithThreeDot": "保存中...", + "Actions": "操作", + "Delete": "刪除", + "Edit": "修改", + "Refresh": "刷新", + "ProcessingWithThreeDot": "處理中...", + "LoadingWithThreeDot": "載入中...", + "Welcome": "歡迎", + "Login": "登入", + "Register": "註冊", + "Logout": "登出", + "Submit": "提交", + "Back": "返回", + "PagerSearch": "搜尋", + "PagerNext": "下一頁", + "PagerPrevious": "上一頁", + "PagerFirst": "首頁", + "PagerLast": "末頁", + "PagerInfo": "顯示 _TOTAL_ 個紀錄的 _START_ 到 _END_ 個.", + "PagerInfoEmpty": "顯示0個紀錄中的0到0", + "PagerInfoFiltered": "(從 _MAX_ 所有紀錄中過濾掉)", + "NoDataAvailableInDatatable": "資料表中沒有資料", + "PagerShowMenuEntries": "顯示 _MENU_ 實體", + "DatatableActionDropdownDefaultText": "操作", + "ChangePassword": "修改密碼", + "PersonalInfo": "個人資料", + "AreYouSureYouWantToCancelEditingWarningMessage": "你有未保存的更改.", + "UnhandledException": "未處理的異常!", + "401Message": "未授權", + "403Message": "禁止訪問", + "404Message": "網頁未找到", + "500Message": "內部伺服器錯誤", + "GoHomePage": "返回首頁", + "GoBack": "返回" + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkDefaultOptions.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkDefaultOptions.cs index 789e4f8e58..02d80e82a5 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkDefaultOptions.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkDefaultOptions.cs @@ -10,7 +10,10 @@ namespace Volo.Abp.Uow /// public class AbpUnitOfWorkDefaultOptions { - public UnitOfWorkTransactionBehavior TransactionBehavior { get; set; } + /// + /// Default value: . + /// + public UnitOfWorkTransactionBehavior TransactionBehavior { get; set; } = UnitOfWorkTransactionBehavior.Auto; public IsolationLevel? IsolationLevel { get; set; } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkOptions.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkOptions.cs index dd39612921..a8f3f75a11 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkOptions.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkOptions.cs @@ -14,6 +14,18 @@ namespace Volo.Abp.Uow public TimeSpan? Timeout { get; set; } + public AbpUnitOfWorkOptions() + { + + } + + public AbpUnitOfWorkOptions(bool isTransactional = false, IsolationLevel? isolationLevel = null, TimeSpan? timeout = null) + { + IsTransactional = isTransactional; + IsolationLevel = isolationLevel; + Timeout = timeout; + } + public AbpUnitOfWorkOptions Clone() { return new AbpUnitOfWorkOptions diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs index 0d2686cdfe..d1d90b6f6f 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -53,31 +53,16 @@ namespace Volo.Abp.Uow _parent.Reserve(reservationName); } - public void SaveChanges() - { - _parent.SaveChanges(); - } - public Task SaveChangesAsync(CancellationToken cancellationToken = default) { return _parent.SaveChangesAsync(cancellationToken); } - public void Complete() - { - - } - public Task CompleteAsync(CancellationToken cancellationToken = default) { return Task.CompletedTask; } - public void Rollback() - { - _parent.Rollback(); - } - public Task RollbackAsync(CancellationToken cancellationToken = default) { return _parent.RollbackAsync(cancellationToken); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs index cf65ca69e7..32ef781133 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs @@ -32,16 +32,10 @@ namespace Volo.Abp.Uow void Reserve([NotNull] string reservationName); - void SaveChanges(); - Task SaveChangesAsync(CancellationToken cancellationToken = default); - void Complete(); - Task CompleteAsync(CancellationToken cancellationToken = default); - void Rollback(); - Task RollbackAsync(CancellationToken cancellationToken = default); void OnCompleted(Func handler); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index 5b857e8828..18010136b2 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; -using Volo.Abp.Threading; namespace Volo.Abp.Uow { @@ -75,21 +74,13 @@ namespace Volo.Abp.Uow Outer = outer; } - public virtual void SaveChanges() - { - foreach (var databaseApi in GetAllActiveDatabaseApis()) - { - (databaseApi as ISupportsSavingChanges)?.SaveChanges(); - } - } - public virtual async Task SaveChangesAsync(CancellationToken cancellationToken = default) { foreach (var databaseApi in GetAllActiveDatabaseApis()) { if (databaseApi is ISupportsSavingChanges) { - await (databaseApi as ISupportsSavingChanges).SaveChangesAsync(cancellationToken); + await (databaseApi as ISupportsSavingChanges).SaveChangesAsync(cancellationToken).ConfigureAwait(false); } } } @@ -104,30 +95,6 @@ namespace Volo.Abp.Uow return _transactionApis.Values.ToImmutableList(); } - public virtual void Complete() - { - if (_isRolledback) - { - return; - } - - PreventMultipleComplete(); - - try - { - _isCompleting = true; - SaveChanges(); - CommitTransactions(); - IsCompleted = true; - OnCompleted(); - } - catch (Exception ex) - { - _exception = ex; - throw; - } - } - public virtual async Task CompleteAsync(CancellationToken cancellationToken = default) { if (_isRolledback) @@ -140,10 +107,10 @@ namespace Volo.Abp.Uow try { _isCompleting = true; - await SaveChangesAsync(cancellationToken); - await CommitTransactionsAsync(); + await SaveChangesAsync(cancellationToken).ConfigureAwait(false); + await CommitTransactionsAsync().ConfigureAwait(false); IsCompleted = true; - await OnCompletedAsync(); + await OnCompletedAsync().ConfigureAwait(false); } catch (Exception ex) { @@ -152,18 +119,6 @@ namespace Volo.Abp.Uow } } - public virtual void Rollback() - { - if (_isRolledback) - { - return; - } - - _isRolledback = true; - - RollbackAll(); - } - public virtual async Task RollbackAsync(CancellationToken cancellationToken = default) { if (_isRolledback) @@ -173,7 +128,7 @@ namespace Volo.Abp.Uow _isRolledback = true; - await RollbackAllAsync(cancellationToken); + await RollbackAllAsync(cancellationToken).ConfigureAwait(false); } public IDatabaseApi FindDatabaseApi(string key) @@ -235,24 +190,11 @@ namespace Volo.Abp.Uow CompletedHandlers.Add(handler); } - public void OnFailed(Func handler) - { - throw new NotImplementedException(); - } - - protected virtual void OnCompleted() - { - foreach (var handler in CompletedHandlers) - { - AsyncHelper.RunSync(handler); - } - } - protected virtual async Task OnCompletedAsync() { foreach (var handler in CompletedHandlers) { - await handler.Invoke(); + await handler.Invoke().ConfigureAwait(false); } } @@ -336,7 +278,7 @@ namespace Volo.Abp.Uow { try { - await (databaseApi as ISupportsRollback).RollbackAsync(cancellationToken); + await (databaseApi as ISupportsRollback).RollbackAsync(cancellationToken).ConfigureAwait(false); } catch { } } @@ -348,7 +290,7 @@ namespace Volo.Abp.Uow { try { - await (transactionApi as ISupportsRollback).RollbackAsync(cancellationToken); + await (transactionApi as ISupportsRollback).RollbackAsync(cancellationToken).ConfigureAwait(false); } catch { } } @@ -367,7 +309,7 @@ namespace Volo.Abp.Uow { foreach (var transaction in GetAllActiveTransactionApis()) { - await transaction.CommitAsync(); + await transaction.CommitAsync().ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs index 1ca6681189..d08c9b943e 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs @@ -18,33 +18,18 @@ namespace Volo.Abp.Uow _defaultOptions = options.Value; } - public override void Intercept(IAbpMethodInvocation invocation) - { - if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.Method, out var unitOfWorkAttribute)) - { - invocation.Proceed(); - return; - } - - using (var uow = _unitOfWorkManager.Begin(CreateOptions(invocation, unitOfWorkAttribute))) - { - invocation.Proceed(); - uow.Complete(); - } - } - public override async Task InterceptAsync(IAbpMethodInvocation invocation) { if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.Method, out var unitOfWorkAttribute)) { - await invocation.ProceedAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); return; } using (var uow = _unitOfWorkManager.Begin(CreateOptions(invocation, unitOfWorkAttribute))) { - await invocation.ProceedAsync(); - await uow.CompleteAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); + await uow.CompleteAsync().ConfigureAwait(false); } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManagerExtensions.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManagerExtensions.cs index bf8859d6ac..a0c52a49f4 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManagerExtensions.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManagerExtensions.cs @@ -1,15 +1,27 @@ -using JetBrains.Annotations; +using System; +using System.Data; +using JetBrains.Annotations; namespace Volo.Abp.Uow { public static class UnitOfWorkManagerExtensions { [NotNull] - public static IUnitOfWork Begin([NotNull] this IUnitOfWorkManager unitOfWorkManager, bool requiresNew = false) + public static IUnitOfWork Begin( + [NotNull] this IUnitOfWorkManager unitOfWorkManager, + bool requiresNew = false, + bool isTransactional = false, + IsolationLevel? isolationLevel = null, + TimeSpan? timeout = null) { Check.NotNull(unitOfWorkManager, nameof(unitOfWorkManager)); - return unitOfWorkManager.Begin(new AbpUnitOfWorkOptions(), requiresNew); + return unitOfWorkManager.Begin(new AbpUnitOfWorkOptions + { + IsTransactional = isTransactional, + IsolationLevel = isolationLevel, + Timeout = timeout + }, requiresNew); } public static void BeginReserved([NotNull] this IUnitOfWorkManager unitOfWorkManager, [NotNull] string reservationName) diff --git a/framework/src/Volo.Abp.Validation/Volo.Abp.Validation.csproj b/framework/src/Volo.Abp.Validation/Volo.Abp.Validation.csproj index c8cc738e98..86017b9628 100644 --- a/framework/src/Volo.Abp.Validation/Volo.Abp.Validation.csproj +++ b/framework/src/Volo.Abp.Validation/Volo.Abp.Validation.csproj @@ -1,4 +1,4 @@ - + @@ -14,7 +14,12 @@ - + + + + + + diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs index bb2d41f927..ad2be911de 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs @@ -1,10 +1,16 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.Validation.Localization; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Validation { + [DependsOn( + typeof(AbpLocalizationModule) + )] public class AbpValidationModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) @@ -12,6 +18,20 @@ namespace Volo.Abp.Validation context.Services.OnRegistred(ValidationInterceptorRegistrar.RegisterIfNeeded); AutoAddObjectValidationContributors(context.Services); } + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Validation/Localization"); + }); + } private static void AutoAddObjectValidationContributors(IServiceCollection services) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/AbpValidationResource.cs similarity index 53% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/AbpValidationResource.cs index 667244886c..0de105747d 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/AbpValidationResource.cs @@ -1,7 +1,7 @@ -namespace Volo.Abp.Localization.Resources.AbpValidation -{ - //TODO: Move to Volo.Abp.Validation! +using Volo.Abp.Localization; +namespace Volo.Abp.Validation.Localization +{ [LocalizationResourceName("AbpValidation")] public class AbpValidationResource { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/cs.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/cs.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/es.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/es.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/pl.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/pl.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/pt-BR.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/pt-BR.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/tr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/tr.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/vi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json similarity index 100% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/vi.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/zh-Hans.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json similarity index 94% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/zh-Hans.json rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json index d56c893c38..282423a44a 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/zh-Hans.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json @@ -8,7 +8,7 @@ "The {0} field only accepts files with the following extensions: {1}": "{0}字段只允许以下扩展名的文件: {1}", "The field {0} must be a string or array type with a maximum length of '{1}'.": "字段{0}必须是最大长度为'{1}'的字符串或数组.", "The field {0} must be a string or array type with a minimum length of '{1}'.": "字段{0}必须是最小长度为'{1}'的字符串或数组.", - "The {0} field is not a valid phone number.": "字段{0}不是有效的身份证号码.", + "The {0} field is not a valid phone number.": "字段{0}不是有效的手机号码.", "The field {0} must be between {1} and {2}.": "字段{0}值必须在{1}和{2}范围内.", "The field {0} must match the regular expression '{1}'.": "字段{0}必须匹配正则表达式'{1}'.", "The {0} field is required.": "字段{0}不可为空.", @@ -22,13 +22,13 @@ "ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "字段只允许以下扩展名的文件: {0}", "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthoOf{0}": "字段必须是最大长度为'{0}'的字符串或数组.", "ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}": "字段必须是最小长度为'{0}'的字符串或数组.", - "ThisFieldIsNotAValidPhoneNumber.": "字段不是有效的身份证号码.", + "ThisFieldIsNotAValidPhoneNumber.": "字段不是有效的手机号码.", "ThisFieldMustBeBetween{0}And{1}": "字段值必须在{0}和{1}范围内.", "ThisFieldMustMatchTheRegularExpression{0}": "字段必须匹配正则表达式'{0}'.", "ThisFieldIsRequired.": "字段不可为空.", "ThisFieldMustBeAStringWithAMaximumLengthOf{0}": "字段必须是长度为{0}的字符串.", "ThisFieldMustBeAStringWithAMinimumLengthOf{1}AndAMaximumLengthOf{0}": "字段必须是最小长度为{1}并且最大长度{*}的字符串.", "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "字段{0}不是有效的完全限定的http,https或ftp URL.", - "ThisFieldIsInvalid.": "字段是无效值." + "ThisFieldIsInvalid.": "该字段无效." } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json new file mode 100644 index 0000000000..1e7e419625 --- /dev/null +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json @@ -0,0 +1,34 @@ +{ + "culture": "zh-Hant", + "texts": { + "'{0}' and '{1}' do not match.": "'{0}'與'{1}'不匹配.", + "The {0} field is not a valid credit card number.": "欄位{0}不是有效的信用卡號碼.", + "{0} is not valid.": "{0}驗證未通過.", + "The {0} field is not a valid e-mail address.": "欄位{0}不是有效的電子郵件地址.", + "The {0} field only accepts files with the following extensions: {1}": "{0}欄位只允許以下副檔名的文件: {1}", + "The field {0} must be a string or array type with a maximum length of '{1}'.": "欄位{0}必須是最大長度為'{1}'的字串或陣列.", + "The field {0} must be a string or array type with a minimum length of '{1}'.": "欄位{0}必須是最小長度為'{1}'的字串或陣列.", + "The {0} field is not a valid phone number.": "欄位{0}不是有效的電話號碼.", + "The field {0} must be between {1} and {2}.": "欄位{0}值必須在{1}和{2}範圍內.", + "The field {0} must match the regular expression '{1}'.": "欄位{0}必須匹配正規表示式'{1}'.", + "The {0} field is required.": "欄位{0}不可為空.", + "The field {0} must be a string with a maximum length of {1}.": "欄位{0}必須是長度為{1}的字串.", + "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "欄位{0}必須是最小長度為{2}並且最大長度{1}的字串.", + "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "欄位{0}不是有效的完全限定的http,https或ftp URL.", + "The field {0} is invalid.": "此欄位{0}是無效值.", + "ThisFieldIsNotAValidCreditCardNumber.": "此欄位不是有效的信用卡號碼.", + "ThisFieldIsNotValid.": "此驗證未通過.", + "ThisFieldIsNotAValidEmailAddress.": "此欄位不是有效的郵箱地址.", + "ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "此欄位只允許以下副檔名的文件: {0}", + "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthoOf{0}": "此欄位必須是最大長度為'{0}'的字串或陣列.", + "ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}": "此欄位必須是最小長度為'{0}'的字串或陣列.", + "ThisFieldIsNotAValidPhoneNumber.": "此欄位不是有效的電話號碼.", + "ThisFieldMustBeBetween{0}And{1}": "此欄位值必須在{0}和{1}範圍內.", + "ThisFieldMustMatchTheRegularExpression{0}": "此欄位必須匹配正規表示式'{0}'.", + "ThisFieldIsRequired.": "此欄位不可為空.", + "ThisFieldMustBeAStringWithAMaximumLengthOf{0}": "此欄位必須是長度為{0}的字串.", + "ThisFieldMustBeAStringWithAMinimumLengthOf{1}AndAMaximumLengthOf{0}": "此欄位必須是最小長度為{1}並且最大長度{0}的字串.", + "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "此欄位不是有效的完全限定的http,https或ftp URL.", + "ThisFieldIsInvalid.": "此欄位是無效值." + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHandler.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHelper.cs similarity index 94% rename from framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHandler.cs rename to framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHelper.cs index 5570f04e7d..d46281d2e9 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHandler.cs +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHelper.cs @@ -2,7 +2,7 @@ namespace Volo.Abp.Validation { - public class ValidationHandler + public class ValidationHelper { private const string EmailRegEx = @"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"; diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs index ed8c107005..24581c54d9 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs @@ -13,16 +13,10 @@ namespace Volo.Abp.Validation _methodInvocationValidator = methodInvocationValidator; } - public override void Intercept(IAbpMethodInvocation invocation) - { - Validate(invocation); - invocation.Proceed(); - } - public override async Task InterceptAsync(IAbpMethodInvocation invocation) { Validate(invocation); - await invocation.ProceedAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); } protected virtual void Validate(IAbpMethodInvocation invocation) diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Microsoft/Extensions/FileProviders/AbpFileInfoExtensions.cs b/framework/src/Volo.Abp.VirtualFileSystem/Microsoft/Extensions/FileProviders/AbpFileInfoExtensions.cs index 7d3505d616..9186e4d9e2 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Microsoft/Extensions/FileProviders/AbpFileInfoExtensions.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Microsoft/Extensions/FileProviders/AbpFileInfoExtensions.cs @@ -56,7 +56,7 @@ namespace Microsoft.Extensions.FileProviders using (var stream = fileInfo.CreateReadStream()) { - return await stream.GetAllBytesAsync(); + return await stream.GetAllBytesAsync().ConfigureAwait(false); } } diff --git a/framework/test/AbpTestBase/AbpTestBase.csproj b/framework/test/AbpTestBase/AbpTestBase.csproj index 082da83b39..566bfde770 100644 --- a/framework/test/AbpTestBase/AbpTestBase.csproj +++ b/framework/test/AbpTestBase/AbpTestBase.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/test/SimpleConsoleDemo/Program.cs b/framework/test/SimpleConsoleDemo/Program.cs index 82e6d0a660..3ac0c8b23b 100644 --- a/framework/test/SimpleConsoleDemo/Program.cs +++ b/framework/test/SimpleConsoleDemo/Program.cs @@ -10,7 +10,7 @@ namespace SimpleConsoleDemo { class Program { - static async Task Main(string[] args) + static void Main(string[] args) { using (var application = AbpApplicationFactory.Create(options => { @@ -42,7 +42,6 @@ namespace SimpleConsoleDemo writer.Write(); } - Console.WriteLine(); Console.WriteLine("Press ENTER to exit!"); Console.ReadLine(); diff --git a/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo.Abp.AspNetCore.Authentication.OAuth.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo.Abp.AspNetCore.Authentication.OAuth.Tests.csproj index ff7db73875..2e6a7187fd 100644 --- a/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo.Abp.AspNetCore.Authentication.OAuth.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo.Abp.AspNetCore.Authentication.OAuth.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo.Abp.AspNetCore.MultiTenancy.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo.Abp.AspNetCore.MultiTenancy.Tests.csproj index bcaf6a68f2..06b6fbcd94 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo.Abp.AspNetCore.MultiTenancy.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo.Abp.AspNetCore.MultiTenancy.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs index 44e2e38380..8ec04b23a6 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/App/AppModule.cs @@ -41,7 +41,7 @@ namespace Volo.Abp.AspNetCore.App }; var result = jsonSerializer.Serialize(dictionary, camelCase: false); - await ctx.Response.WriteAsync(result); + await ctx.Response.WriteAsync(result).ConfigureAwait(false); }); } } diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs index e2ac111f5d..437240971d 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_WithDomainResolver_Tests.cs @@ -46,14 +46,14 @@ namespace Volo.Abp.AspNetCore.MultiTenancy [Fact] public async Task Should_Use_Host_If_Tenant_Is_Not_Specified() { - var result = await GetResponseAsObjectAsync>("http://abp.io"); + var result = await GetResponseAsObjectAsync>("http://abp.io").ConfigureAwait(false); result["TenantId"].ShouldBe(""); } [Fact] public async Task Should_Use_Domain_If_Specified() { - var result = await GetResponseAsObjectAsync>("http://acme.abp.io"); + var result = await GetResponseAsObjectAsync>("http://acme.abp.io").ConfigureAwait(false); result["TenantId"].ShouldBe(_testTenantId.ToString()); } @@ -62,7 +62,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { Client.DefaultRequestHeaders.Add(_options.TenantKey, Guid.NewGuid().ToString()); - var result = await GetResponseAsObjectAsync>("http://acme.abp.io"); + var result = await GetResponseAsObjectAsync>("http://acme.abp.io").ConfigureAwait(false); result["TenantId"].ShouldBe(_testTenantId.ToString()); } } diff --git a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs index 37365089af..64f7ed2892 100644 --- a/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_Without_DomainResolver_Tests.cs @@ -42,7 +42,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy [Fact] public async Task Should_Use_Host_If_Tenant_Is_Not_Specified() { - var result = await GetResponseAsObjectAsync>("http://abp.io"); + var result = await GetResponseAsObjectAsync>("http://abp.io").ConfigureAwait(false); result["TenantId"].ShouldBe(""); } @@ -50,7 +50,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy public async Task Should_Use_QueryString_Tenant_Id_If_Specified() { - var result = await GetResponseAsObjectAsync>($"http://abp.io?{_options.TenantKey}={_testTenantName}"); + var result = await GetResponseAsObjectAsync>($"http://abp.io?{_options.TenantKey}={_testTenantName}").ConfigureAwait(false); result["TenantId"].ShouldBe(_testTenantId.ToString()); } @@ -59,7 +59,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { Client.DefaultRequestHeaders.Add(_options.TenantKey, _testTenantId.ToString()); - var result = await GetResponseAsObjectAsync>("http://abp.io"); + var result = await GetResponseAsObjectAsync>("http://abp.io").ConfigureAwait(false); result["TenantId"].ShouldBe(_testTenantId.ToString()); } @@ -68,7 +68,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy { Client.DefaultRequestHeaders.Add("Cookie", new CookieHeaderValue(_options.TenantKey, _testTenantId.ToString()).ToString()); - var result = await GetResponseAsObjectAsync>("http://abp.io"); + var result = await GetResponseAsObjectAsync>("http://abp.io").ConfigureAwait(false); result["TenantId"].ShouldBe(_testTenantId.ToString()); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj index ae4730d930..4dad128d56 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs index 97055d1e9a..5e74ec4bfa 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs @@ -8,10 +8,10 @@ using Volo.Abp.AspNetCore.Mvc.Localization.Resource; using Volo.Abp.AspNetCore.TestBase; using Volo.Abp.Autofac; using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.MemoryDb; using Volo.Abp.Modularity; using Volo.Abp.TestApp; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.AspNetCore.Mvc diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController_Tests.cs index 44b206e462..f141cf89c1 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController_Tests.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApiExploring [Fact] public async Task GetAsync() { - var model = await GetResponseAsObjectAsync("/api/abp/api-definition"); + var model = await GetResponseAsObjectAsync("/api/abp/api-definition").ConfigureAwait(false); model.ShouldNotBeNull(); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs index c5f53e4721..590aa1a142 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { var applicationConfigurationBuilder = GetRequiredService(); - var config = await applicationConfigurationBuilder.GetAsync(); + var config = await applicationConfigurationBuilder.GetAsync().ConfigureAwait(false); config.Auth.ShouldNotBeNull(); config.Localization.ShouldNotBeNull(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs index 8caf59d0c0..2937fd6759 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs @@ -29,7 +29,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization [Fact] public async Task Should_Call_Anonymous_Method_Without_Authentication() { - var result = await GetResponseAsStringAsync("/AuthTest/AnonymousTest"); + var result = await GetResponseAsStringAsync("/AuthTest/AnonymousTest").ConfigureAwait(false); result.ShouldBe("OK"); } @@ -41,7 +41,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization new Claim(AbpClaimTypes.UserId, AuthTestController.FakeUserId.ToString()) }); - var result = await GetResponseAsStringAsync("/AuthTest/SimpleAuthorizationTest"); + var result = await GetResponseAsStringAsync("/AuthTest/SimpleAuthorizationTest").ConfigureAwait(false); result.ShouldBe("OK"); } @@ -54,7 +54,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization new Claim("MyCustomClaimType", "42") }); - var result = await GetResponseAsStringAsync("/AuthTest/CustomPolicyTest"); + var result = await GetResponseAsStringAsync("/AuthTest/CustomPolicyTest").ConfigureAwait(false); result.ShouldBe("OK"); } @@ -70,7 +70,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization //TODO: We can get a real exception if we properly configure authentication schemas for this project await Assert.ThrowsAsync(async () => await GetResponseAsStringAsync("/AuthTest/CustomPolicyTest") - ); +.ConfigureAwait(false)).ConfigureAwait(false); } [Fact] @@ -81,7 +81,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization new Claim(AbpClaimTypes.UserId, AuthTestController.FakeUserId.ToString()) }); - var result = await GetResponseAsStringAsync("/AuthTest/PermissionTest"); + var result = await GetResponseAsStringAsync("/AuthTest/PermissionTest").ConfigureAwait(false); result.ShouldBe("OK"); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs index b9caa1d7cb..1952ef22b9 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization }); } - await next(context); + await next(context).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs index 5243307116..1d11103c6f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionTestController_Tests.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling [Fact] public async Task Should_Return_RemoteServiceErrorResponse_For_UserFriendlyException_For_Void_Return_Value() { - var result = await GetResponseAsObjectAsync("/api/exception-test/UserFriendlyException1", HttpStatusCode.Forbidden); + var result = await GetResponseAsObjectAsync("/api/exception-test/UserFriendlyException1", HttpStatusCode.Forbidden).ConfigureAwait(false); result.Error.ShouldNotBeNull(); result.Error.Message.ShouldBe("This is a sample exception!"); } @@ -23,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling async () => await GetResponseAsObjectAsync( "/api/exception-test/UserFriendlyException2" ) - ); +.ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestController_Tests.cs index 637dbe3d2b..52ff323be6 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Features/FeatureTestController_Tests.cs @@ -10,8 +10,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Features public async Task Should_Allow_Enabled_Features() { await GetResponseAsStringAsync( - "/api/feature-test/allowed-feature" - ); + "/api/feature-test/allowed-feature", HttpStatusCode.NoContent + ).ConfigureAwait(false); } [Fact] @@ -20,7 +20,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Features await GetResponseAsStringAsync( "/api/feature-test/not-allowed-feature", HttpStatusCode.Unauthorized - ); + ).ConfigureAwait(false); } [Fact] @@ -28,7 +28,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Features { await GetResponseAsStringAsync( "/api/feature-test/no-feature" - ); + ).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs index 3e365cde3e..eeb47ea0a3 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json { var time = await GetResponseAsStringAsync( "/api/json-result-test/json-result-action" - ); + ).ConfigureAwait(false); time.ShouldContain("2019*01*01"); } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs index 16057c3f07..2f5ad74df9 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/MvcLocalization_Tests.cs @@ -27,22 +27,22 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization [Fact] public async Task Should_Get_Same_Text_If_Not_Defined_In_Razor_View() { - var result = await GetResponseAsStringAsync("/LocalizationTest/HelloJohn"); + var result = await GetResponseAsStringAsync("/LocalizationTest/HelloJohn").ConfigureAwait(false); result.ShouldBe("Hello John."); } [Fact] public async Task Should_Localize_Display_Attribute() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { - var result = await GetResponseAsStringAsync("/LocalizationTest/PersonForm"); + var result = await GetResponseAsStringAsync("/LocalizationTest/PersonForm").ConfigureAwait(false); result.ShouldContain(""); } - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { - var result = await GetResponseAsStringAsync("/LocalizationTest/PersonForm"); + var result = await GetResponseAsStringAsync("/LocalizationTest/PersonForm").ConfigureAwait(false); result.ShouldContain(""); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/zh-Hant.json b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/zh-Hant.json new file mode 100644 index 0000000000..c70842f0b2 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "BirthDate": "生日", + "Value1": "值1" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index 632a02194f..45f8410eee 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -21,10 +21,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding [Fact] public async Task DateTimeKind_Test() { - var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2010-01-01T00:00:00Z"); + var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2010-01-01T00:00:00Z").ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); resultAsString.ShouldBe(DateTimeKind.ToString().ToLower()); } @@ -32,10 +32,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding public async Task NullableDateTimeKind_Test() { var response = - await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2010-01-01T00:00:00Z"); + await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2010-01-01T00:00:00Z").ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); resultAsString.ShouldBe(DateTimeKind.ToString().ToLower()); } @@ -44,10 +44,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding { var response = await Client.GetAsync( - "/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2010-01-01T00:00:00Z"); + "/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2010-01-01T00:00:00Z").ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local. resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower()); } @@ -57,10 +57,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding { var response = await Client.GetAsync( - "/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2010-01-01T00:00:00Z"); + "/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2010-01-01T00:00:00Z").ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local. resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower()); } @@ -72,10 +72,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding "Time1=2010-01-01T00:00:00Z&" + "Time2=2010-01-01T00:00:00Z&" + "Time3=2010-01-01T00:00:00Z&" + - "InnerModel.Time4=2010-01-01T00:00:00Z"); + "InnerModel.Time4=2010-01-01T00:00:00Z").ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local. resultAsString.ShouldBe( $"local_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_local"); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleAppService_Tests.cs similarity index 76% rename from framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs rename to framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleAppService_Tests.cs index 8bf86a3ace..c3c90d02f7 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleAppService_Tests.cs @@ -19,13 +19,13 @@ namespace Volo.Abp.AspNetCore.Mvc { //TODO: Refactor to make tests easier. - public class PersonAppService_Tests : AspNetCoreMvcTestBase + public class PeopleAppService_Tests : AspNetCoreMvcTestBase { private readonly IRepository _personRepository; private readonly IJsonSerializer _jsonSerializer; private readonly IObjectMapper _objectMapper; - public PersonAppService_Tests() + public PeopleAppService_Tests() { _personRepository = ServiceProvider.GetRequiredService>(); _jsonSerializer = ServiceProvider.GetRequiredService(); @@ -35,27 +35,27 @@ namespace Volo.Abp.AspNetCore.Mvc [Fact] public async Task GetAll_Test() { - var result = await GetResponseAsObjectAsync>("/api/app/people"); + var result = await GetResponseAsObjectAsync>("/api/app/people").ConfigureAwait(false); result.Items.Count.ShouldBeGreaterThan(0); } [Fact] public async Task Get_Test() { - var firstPerson = _personRepository.First(); + var firstPerson = (await _personRepository.GetListAsync()).First(); - var result = await GetResponseAsObjectAsync($"/api/app/people/{firstPerson.Id}"); + var result = await GetResponseAsObjectAsync($"/api/app/people/{firstPerson.Id}").ConfigureAwait(false); result.Name.ShouldBe(firstPerson.Name); } [Fact] public async Task Delete_Test() { - var firstPerson = _personRepository.First(); + var firstPerson = (await _personRepository.GetListAsync()).First(); - await Client.DeleteAsync($"/api/app/people/{firstPerson.Id}"); + await Client.DeleteAsync($"/api/app/people/{firstPerson.Id}").ConfigureAwait(false); - (await _personRepository.FindAsync(firstPerson.Id)).ShouldBeNull(); + (await _personRepository.FindAsync(firstPerson.Id).ConfigureAwait(false)).ShouldBeNull(); } [Fact] @@ -68,10 +68,10 @@ namespace Volo.Abp.AspNetCore.Mvc var response = await Client.PostAsync( "/api/app/people", new StringContent(postData, Encoding.UTF8, MimeTypes.Application.Json) - ); + ).ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); PersonDto resultDto = _jsonSerializer.Deserialize(resultAsString); //Assert @@ -80,7 +80,7 @@ namespace Volo.Abp.AspNetCore.Mvc resultDto.Name.ShouldBe("John"); resultDto.Age.ShouldBe(33); - (await _personRepository.FindAsync(resultDto.Id)).ShouldNotBeNull(); + (await _personRepository.FindAsync(resultDto.Id).ConfigureAwait(false)).ShouldNotBeNull(); } @@ -89,7 +89,7 @@ namespace Volo.Abp.AspNetCore.Mvc { //Arrange - var firstPerson = _personRepository.First(); + var firstPerson = (await _personRepository.GetListAsync()).First(); var firstPersonAge = firstPerson.Age; //Persist to a variable since we are using in-memory database which shares same entity. var updateDto = _objectMapper.Map(firstPerson); updateDto.Age = updateDto.Age + 1; @@ -100,10 +100,10 @@ namespace Volo.Abp.AspNetCore.Mvc var response = await Client.PutAsync( $"/api/app/people/{updateDto.Id}", new StringContent(putData, Encoding.UTF8, MimeTypes.Application.Json) - ); + ).ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); PersonDto resultDto = _jsonSerializer.Deserialize(resultAsString); //Assert @@ -112,7 +112,7 @@ namespace Volo.Abp.AspNetCore.Mvc resultDto.Name.ShouldBe(firstPerson.Name); resultDto.Age.ShouldBe(firstPersonAge + 1); - var personInDb = (await _personRepository.FindAsync(resultDto.Id)); + var personInDb = (await _personRepository.FindAsync(resultDto.Id).ConfigureAwait(false)); personInDb.ShouldNotBeNull(); personInDb.Name.ShouldBe(firstPerson.Name); personInDb.Age.ShouldBe(firstPersonAge + 1); @@ -123,7 +123,7 @@ namespace Volo.Abp.AspNetCore.Mvc { //Arrange - var personToAddNewPhone = _personRepository.First(); + var personToAddNewPhone = (await _personRepository.GetListAsync()).First(); var phoneNumberToAdd = RandomHelper.GetRandom(1000000, 9000000).ToString(); //Act @@ -133,10 +133,10 @@ namespace Volo.Abp.AspNetCore.Mvc var response = await Client.PostAsync( $"/api/app/people/{personToAddNewPhone.Id}/phones", new StringContent(postData, Encoding.UTF8, MimeTypes.Application.Json) - ); + ).ConfigureAwait(false); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var resultDto = _jsonSerializer.Deserialize(resultAsString); //Assert @@ -144,7 +144,7 @@ namespace Volo.Abp.AspNetCore.Mvc resultDto.Type.ShouldBe(PhoneType.Mobile); resultDto.Number.ShouldBe(phoneNumberToAdd); - var personInDb = await _personRepository.FindAsync(personToAddNewPhone.Id); + var personInDb = await _personRepository.FindAsync(personToAddNewPhone.Id).ConfigureAwait(false); personInDb.ShouldNotBeNull(); personInDb.Phones.Any(p => p.Number == phoneNumberToAdd).ShouldBeTrue(); } @@ -152,21 +152,21 @@ namespace Volo.Abp.AspNetCore.Mvc [Fact] public async Task GetPhones_Test() { - var douglas = _personRepository.First(p => p.Name == "Douglas"); + var douglas = (await _personRepository.GetListAsync()).First(p => p.Name == "Douglas"); - var result = await GetResponseAsObjectAsync>($"/api/app/people/{douglas.Id}/phones"); + var result = await GetResponseAsObjectAsync>($"/api/app/people/{douglas.Id}/phones").ConfigureAwait(false); result.Items.Count.ShouldBe(douglas.Phones.Count); } [Fact] public async Task DeletePhone_Test() { - var douglas = _personRepository.First(p => p.Name == "Douglas"); + var douglas = (await _personRepository.GetListAsync()).First(p => p.Name == "Douglas"); var firstPhone = douglas.Phones.First(); - await Client.DeleteAsync($"/api/app/people/{douglas.Id}/phones?number={firstPhone.Number}"); + await Client.DeleteAsync($"/api/app/people/{douglas.Id}/phones?number={firstPhone.Number}").ConfigureAwait(false); - douglas = _personRepository.First(p => p.Name == "Douglas"); + douglas = (await _personRepository.GetListAsync()).First(p => p.Name == "Douglas"); douglas.Phones.Any(p => p.Number == firstPhone.Number).ShouldBeFalse(); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxiesController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxiesController_Tests.cs index bd7366b931..2af719ae4d 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxiesController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxiesController_Tests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Shouldly; using Xunit; @@ -9,15 +10,18 @@ namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting [Fact] public async Task GetAll() { - var script = await GetResponseAsStringAsync("/Abp/ServiceProxyScript?minify=true"); + var script = await GetResponseAsStringAsync("/Abp/ServiceProxyScript?minify=true").ConfigureAwait(false); script.Length.ShouldBeGreaterThan(0); } [Fact] public async Task GetAllWithMinify() { - var script = await GetResponseAsStringAsync("/Abp/ServiceProxyScript"); - var minifyScript = await GetResponseAsStringAsync("/Abp/ServiceProxyScript?minify=true"); + GetRequiredService>().Value.MinifyGeneratedScript = false; + var script = await GetResponseAsStringAsync("/Abp/ServiceProxyScript").ConfigureAwait(false); + + GetRequiredService>().Value.MinifyGeneratedScript = true; + var minifyScript = await GetResponseAsStringAsync("/Abp/ServiceProxyScript?minify=true").ConfigureAwait(false); script.Length.ShouldBeGreaterThan(0); minifyScript.Length.ShouldBeGreaterThan(0); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Response/NoContentTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Response/NoContentTestController.cs new file mode 100644 index 0000000000..dc0ae30d71 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Response/NoContentTestController.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.AspNetCore.Mvc.Response +{ + [Route("api/NoContent-Test")] + public class NoContentTestController : AbpController + { + [HttpGet] + [Route("TestMethod")] + public void TestMethod() + { + } + + [HttpGet] + [Route("TestMethodWithReturn")] + public string TestMethodWithReturn() + { + return "TestReturn"; + } + + [HttpGet] + [Route("TestCustomHttpStatusCodeMethod")] + public void TestCustomHttpStatusCodeMethod() + { + Response.Redirect("/"); + } + + [HttpGet] + [Route("TestAsyncMethod")] + public async Task TestAsyncMethod() + { + await Task.CompletedTask; + } + + [HttpGet] + [Route("TestAsyncMethodWithReturn")] + public async Task TestAsyncMethodWithReturn() + { + return await Task.FromResult("TestReturn"); + } + + [HttpGet] + [Route("TestAsyncCustomHttpStatusCodeMethod")] + public async Task TestAsyncCustomHttpStatusCodeMethod() + { + Response.Redirect("/"); + await Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Response/NoContentTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Response/NoContentTestController_Tests.cs new file mode 100644 index 0000000000..6c68c13f07 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Response/NoContentTestController_Tests.cs @@ -0,0 +1,58 @@ +using System.Net; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Response +{ + public class NoContentTestController_Tests : AspNetCoreMvcTestBase + { + [Fact] + public async Task Should_Set_No_Content_For_Void_Action() + { + var result = await GetResponseAsync("/api/NoContent-Test/TestMethod", HttpStatusCode.NoContent) + .ConfigureAwait(false); + result.StatusCode.ShouldBe(HttpStatusCode.NoContent); + } + + [Fact] + public async Task Should_Not_Set_No_Content_For_Not_Void_Action() + { + var result = await GetResponseAsync("/api/NoContent-Test/TestMethodWithReturn") + .ConfigureAwait(false); + result.StatusCode.ShouldBe(HttpStatusCode.OK); + } + + [Fact] + public async Task Should_Not_Set_No_Content_For_Custom_Http_Status_Code_Action() + { + var result = await GetResponseAsync("/api/NoContent-Test/TestCustomHttpStatusCodeMethod", HttpStatusCode.Redirect) + .ConfigureAwait(false); + result.StatusCode.ShouldBe(HttpStatusCode.Redirect); + } + + [Fact] + public async Task Should_Set_No_Content_For_Task_Action() + { + var result = await GetResponseAsync("/api/NoContent-Test/TestAsyncMethod", HttpStatusCode.NoContent) + .ConfigureAwait(false); + result.StatusCode.ShouldBe(HttpStatusCode.NoContent); + } + + [Fact] + public async Task Should_Not_Set_No_Content_For_Not_Task_Action() + { + var result = await GetResponseAsync("/api/NoContent-Test/TestAsyncMethodWithReturn") + .ConfigureAwait(false); + result.StatusCode.ShouldBe(HttpStatusCode.OK); + } + + [Fact] + public async Task Should_Not_Set_No_Content_For_Custom_Http_Status_Code_Async_Action() + { + var result = await GetResponseAsync("/api/NoContent-Test/TestAsyncCustomHttpStatusCodeMethod", HttpStatusCode.Redirect) + .ConfigureAwait(false); + result.StatusCode.ShouldBe(HttpStatusCode.Redirect); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/SimpleController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/SimpleController_Tests.cs index cda64b2323..aa111be2f8 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/SimpleController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/SimpleController_Tests.cs @@ -13,7 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc { var result = await GetResponseAsStringAsync( GetUrl(nameof(SimpleController.Index)) - ); + ).ConfigureAwait(false); result.ShouldBe("Index-Result"); } @@ -23,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc { var result = await GetResponseAsStringAsync( GetUrl(nameof(SimpleController.About)) - ); + ).ConfigureAwait(false); result.Trim().ShouldBe("

    About

    "); } @@ -35,8 +35,8 @@ namespace Volo.Abp.AspNetCore.Mvc { await GetResponseAsStringAsync( GetUrl(nameof(SimpleController.ExceptionOnRazor)) - ); - }); + ).ConfigureAwait(false); + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs index 079120e8d3..3b9ec55e75 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs @@ -19,12 +19,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow _config = config; } - public override void Complete() - { - ThrowExceptionIfRequested(); - base.Complete(); - } - public override Task CompleteAsync(CancellationToken cancellationToken = default(CancellationToken)) { ThrowExceptionIfRequested(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs index 6400ecb88e..81d1c88bee 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Exception_Rollback_Tests.cs @@ -14,7 +14,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow [Fact] public async Task Should_Rollback_Transaction_For_Handled_Exceptions() { - var result = await GetResponseAsObjectAsync("/api/unitofwork-test/HandledException", HttpStatusCode.Forbidden); + var result = await GetResponseAsObjectAsync("/api/unitofwork-test/HandledException", HttpStatusCode.Forbidden).ConfigureAwait(false); result.Error.ShouldNotBeNull(); result.Error.Message.ShouldBe("This is a sample exception!"); } @@ -22,11 +22,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow [Fact] public async Task Should_Gracefully_Handle_Exceptions_On_Complete() { - var response = await GetResponseAsync("/api/unitofwork-test/ExceptionOnComplete", HttpStatusCode.Forbidden); + var response = await GetResponseAsync("/api/unitofwork-test/ExceptionOnComplete", HttpStatusCode.Forbidden).ConfigureAwait(false); response.Headers.GetValues(AbpHttpConsts.AbpErrorFormat).FirstOrDefault().ShouldBe("true"); - var resultAsString = await response.Content.ReadAsStringAsync(); + var resultAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var result = ServiceProvider.GetRequiredService().Deserialize(resultAsString); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs index abd666e3f5..192d1f0e06 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkMiddleware_Tests.cs @@ -9,13 +9,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow [Fact] public async Task Get_Actions_Should_Not_Be_Transactional() { - await GetResponseAsStringAsync("/api/unitofwork-test/ActionRequiresUow"); + await GetResponseAsStringAsync("/api/unitofwork-test/ActionRequiresUow").ConfigureAwait(false); } [Fact] public async Task Non_Get_Actions_Should_Be_Transactional() { - var result = await Client.PostAsync("/api/unitofwork-test/ActionRequiresUowPost", null); + var result = await Client.PostAsync("/api/unitofwork-test/ActionRequiresUowPost", null).ConfigureAwait(false); result.IsSuccessStatusCode.ShouldBeTrue(); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestController.cs index 4d8d51c3c8..705a9a7212 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/UnitOfWorkTestController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Mvc; using Shouldly; -using Volo.Abp.UI; using Volo.Abp.Uow; namespace Volo.Abp.AspNetCore.Mvc.Uow diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs index 5177868843..9d5cbfa012 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Validation/ValidationTestController_Tests.cs @@ -12,23 +12,23 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation [Fact] public async Task Should_Validate_Object_Result_Success() { - var result = await GetResponseAsStringAsync("/api/validation-test/object-result-action?value1=hello"); + var result = await GetResponseAsStringAsync("/api/validation-test/object-result-action?value1=hello").ConfigureAwait(false); result.ShouldBe("hello"); } [Fact] public async Task Should_Validate_Object_Result_Failing() { - var result = await GetResponseAsObjectAsync("/api/validation-test/object-result-action?value1=a", HttpStatusCode.BadRequest); //value1 has min length of 2 chars. + var result = await GetResponseAsObjectAsync("/api/validation-test/object-result-action?value1=a", HttpStatusCode.BadRequest).ConfigureAwait(false); //value1 has min length of 2 chars. result.Error.ValidationErrors.Length.ShouldBeGreaterThan(0); } [Fact] public async Task Should_Return_Localized_Validation_Errors() { - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { - var result = await GetResponseAsObjectAsync("/api/validation-test/object-result-action?value1=a", HttpStatusCode.BadRequest); //value1 has min length of 2 chars. + var result = await GetResponseAsObjectAsync("/api/validation-test/object-result-action?value1=a", HttpStatusCode.BadRequest).ConfigureAwait(false); //value1 has min length of 2 chars. result.Error.ValidationErrors.Length.ShouldBeGreaterThan(0); result.Error.ValidationErrors[0].Message.ShouldBe("Değer Bir alanı en az '2' uzunluğunda bir metin ya da dizi olmalıdır."); } @@ -37,14 +37,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation [Fact] public async Task Should_Not_Validate_Action_Result_Success() { - var result = await GetResponseAsStringAsync("/api/validation-test/action-result-action?value1=hello"); + var result = await GetResponseAsStringAsync("/api/validation-test/action-result-action?value1=hello").ConfigureAwait(false); result.ShouldBe("ModelState.IsValid: true"); } [Fact] public async Task Should_Not_Validate_Action_Result_Failing() { - var result = await GetResponseAsStringAsync("/api/validation-test/action-result-action"); //Missed the value1 + var result = await GetResponseAsStringAsync("/api/validation-test/action-result-action").ConfigureAwait(false); //Missed the value1 result.ShouldBe("ModelState.IsValid: false"); } @@ -52,7 +52,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Validation public async Task Should_Return_Custom_Validate_Errors() { var result = await GetResponseAsObjectAsync( - "/api/validation-test/object-result-action-with-custom_validate?value1=abc", HttpStatusCode.BadRequest); //value1 should be hello. + "/api/validation-test/object-result-action-with-custom_validate?value1=abc", HttpStatusCode.BadRequest).ConfigureAwait(false); //value1 should be hello. result.Error.ValidationErrors.Length.ShouldBeGreaterThan(0); result.Error.ValidationErrors.ShouldContain(x => x.Message == "Value1 should be hello"); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.csproj index 8db66c0178..8a76a15f5d 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.csproj @@ -19,7 +19,7 @@ - +
    diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/Demo/Components/Card_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/Demo/Components/Card_Tests.cs index 9fcac03459..89d9028fc4 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/Demo/Components/Card_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo/Abp/AspNetCore/Mvc/UI/Bootstrap/Demo/Components/Card_Tests.cs @@ -9,7 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Components [Fact(Skip = "This test project is not completed yet")] public async Task Index() { - var result = await GetResponseAsStringAsync("/Components/Cards"); + var result = await GetResponseAsStringAsync("/Components/Cards").ConfigureAwait(false); result.ShouldNotBeNullOrEmpty(); } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj index 3384fcf332..931eb63088 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj @@ -9,7 +9,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj index 909cdbd25e..0a19e5dbdf 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Tests/Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj index 91171a08d3..9ed9312919 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/ITodoAppService.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/ITodoAppService.cs index 3e82da0329..7ed6be1ac2 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/ITodoAppService.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/ITodoAppService.cs @@ -1,9 +1,10 @@ +using System.Threading.Tasks; using Volo.Abp.Application.Services; namespace Volo.Abp.AspNetCore.Mvc.Versioning.App.v1 { public interface ITodoAppService : IApplicationService { - string Get(int id); + Task GetAsync(int id); } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/TodoAppService.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/TodoAppService.cs index f3f900148d..eee0248a61 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/TodoAppService.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v1/TodoAppService.cs @@ -1,4 +1,5 @@ -using Volo.Abp.ApiVersioning; +using System.Threading.Tasks; +using Volo.Abp.ApiVersioning; using Volo.Abp.Application.Services; namespace Volo.Abp.AspNetCore.Mvc.Versioning.App.v1 @@ -12,9 +13,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Versioning.App.v1 _requestedApiVersion = requestedApiVersion; } - public string Get(int id) + public Task GetAsync(int id) { - return $"Compat-{id}-{GetVersionOrNone()}"; + return Task.FromResult($"Compat-{id}-{GetVersionOrNone()}"); } private string GetVersionOrNone() diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/ITodoAppService.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/ITodoAppService.cs index ae4afea6e1..196cc82503 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/ITodoAppService.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/ITodoAppService.cs @@ -1,9 +1,10 @@ +using System.Threading.Tasks; using Volo.Abp.Application.Services; namespace Volo.Abp.AspNetCore.Mvc.Versioning.App.v2 { public interface ITodoAppService : IApplicationService { - string Get(int id); + Task GetAsync(int id); } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/TodoAppService.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/TodoAppService.cs index b97af873b7..24f8604227 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/TodoAppService.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/App/v2/TodoAppService.cs @@ -1,4 +1,5 @@ -using Volo.Abp.ApiVersioning; +using System.Threading.Tasks; +using Volo.Abp.ApiVersioning; using Volo.Abp.Application.Services; namespace Volo.Abp.AspNetCore.Mvc.Versioning.App.v2 @@ -12,9 +13,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Versioning.App.v2 _requestedApiVersion = requestedApiVersion; } - public string Get(int id) + public Task GetAsync(int id) { - return id + "-" + GetVersionOrNone(); + return Task.FromResult(id + "-" + GetVersionOrNone()); } private string GetVersionOrNone() diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/HelloController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/HelloController_Tests.cs index 0dc4057bde..a5db492a39 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/HelloController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/HelloController_Tests.cs @@ -18,19 +18,19 @@ namespace Volo.Abp.AspNetCore.Mvc.Versioning.Test [Fact] public async Task GetAsync() { - (await _helloController.GetAsync()).ShouldBe("Get-2.0"); + (await _helloController.GetAsync().ConfigureAwait(false)).ShouldBe("Get-2.0"); } [Fact] public async Task PostAsyncV1() { - (await _helloController.PostAsyncV1()).ShouldBe("Post-1.0"); + (await _helloController.PostAsyncV1().ConfigureAwait(false)).ShouldBe("Post-1.0"); } [Fact] public async Task PostAsyncV2() { - (await _helloController.PostAsyncV2()).ShouldBe("Post-2.0"); + (await _helloController.PostAsyncV2().ConfigureAwait(false)).ShouldBe("Post-2.0"); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v1/TodoAppService_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v1/TodoAppService_Tests.cs index 7b461a3902..4db9f235be 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v1/TodoAppService_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v1/TodoAppService_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.AspNetCore.Mvc.Versioning.App.v1; using Xunit; @@ -15,9 +16,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Versioning.Test.v1 } [Fact] - public void Get() + public async Task GetAsync() { - _todoAppService.Get(42).ShouldBe("Compat-42-1.0"); + (await _todoAppService.GetAsync(42).ConfigureAwait(false)).ShouldBe("Compat-42-1.0"); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v2/TodoAppService_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v2/TodoAppService_Tests.cs index f4cd122afc..2bfecc2664 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v2/TodoAppService_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Versioning.Tests/Volo/Abp/AspNetCore/Mvc/Versioning/Test/v2/TodoAppService_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.AspNetCore.Mvc.Versioning.App.v2; using Xunit; @@ -15,9 +16,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Versioning.Test.v2 } [Fact] - public void Get() + public async Task GetAsync() { - _todoAppService.Get(42).ShouldBe("42-2.0"); + (await _todoAppService.GetAsync(42).ConfigureAwait(false)).ShouldBe("42-2.0"); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo.Abp.AspNetCore.Serilog.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo.Abp.AspNetCore.Serilog.Tests.csproj new file mode 100644 index 0000000000..740c57949d --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo.Abp.AspNetCore.Serilog.Tests.csproj @@ -0,0 +1,24 @@ + + + + + + netcoreapp3.1 + Volo.Abp.AspNetCore.Serilog.Tests + Volo.Abp.AspNetCore.Serilog.Tests + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/AbpSerilogTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/AbpSerilogTestModule.cs new file mode 100644 index 0000000000..557288cd7d --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/AbpSerilogTestModule.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Serilog; +using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.AspNetCore.App +{ + [DependsOn( + typeof(AbpAspNetCoreTestBaseModule), + typeof(AbpAspNetCoreMvcModule), + typeof(AbpAspNetCoreMultiTenancyModule), + typeof(AbpAspNetCoreSerilogModule), + typeof(AbpAutofacModule) + )] + public class AbpSerilogTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => { options.IsEnabled = true; }); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + + app.UseCorrelationId(); + app.UseRouting(); + app.UseAuthorization(); + app.UseMultiTenancy(); + app.UseAuditing(); + app.UseAbpSerilogEnrichers(); + app.UseMvcWithDefaultRouteAndArea(); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/CollectingSink.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/CollectingSink.cs new file mode 100644 index 0000000000..fe403e02ef --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/CollectingSink.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; +using Serilog.Core; +using Serilog.Events; + +namespace Volo.Abp.AspNetCore.App +{ + public class CollectingSink : ILogEventSink + { + public List Events { get; } = new List(); + + public LogEvent SingleEvent => Events.Single(); + + public void Emit(LogEvent logEvent) + { + Events.Add(logEvent); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/SerilogTestController.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/SerilogTestController.cs new file mode 100644 index 0000000000..972af4c801 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/SerilogTestController.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Tracing; + +namespace Volo.Abp.AspNetCore.App +{ + public class SerilogTestController : AbpController + { + private readonly ICorrelationIdProvider _correlationIdProvider; + + public SerilogTestController(ICorrelationIdProvider correlationIdProvider) + { + _correlationIdProvider = correlationIdProvider; + } + + public ActionResult Index() + { + return Content("Index-Result"); + } + + public ActionResult CorrelationId() + { + return Content(_correlationIdProvider.Get()); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Startup.cs new file mode 100644 index 0000000000..a1a58100d5 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/App/Startup.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Volo.Abp.AspNetCore.App +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddApplication(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ILoggerFactory loggerFactory) + { + app.InitializeApplication(); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs new file mode 100644 index 0000000000..96a13ac45b --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/AbpSerilogTestBase.cs @@ -0,0 +1,31 @@ +using System.Linq; +using Microsoft.Extensions.Hosting; +using Serilog; +using Serilog.Events; +using Volo.Abp.AspNetCore.App; + +namespace Volo.Abp.AspNetCore.Serilog +{ + public class AbpSerilogTestBase : AbpAspNetCoreTestBase + { + protected readonly CollectingSink CollectingSink = new CollectingSink(); + + protected override IHostBuilder CreateHostBuilder() + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .Enrich.FromLogContext() + .WriteTo.Sink(CollectingSink) + .CreateLogger(); + + return base.CreateHostBuilder() + .UseSerilog(); + } + + protected LogEvent GetLogEvent(string text) + { + return CollectingSink.Events.FirstOrDefault(m => m.MessageTemplate.Text == text); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs new file mode 100644 index 0000000000..0a7a189a35 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs @@ -0,0 +1,97 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Serilog.Events; +using Shouldly; +using Volo.Abp.AspNetCore.App; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.MultiTenancy; +using Volo.Abp.MultiTenancy.ConfigurationStore; +using Xunit; + +namespace Volo.Abp.AspNetCore.Serilog +{ + public class Serilog_Enrichers_Tests : AbpSerilogTestBase + { + private const string ExecutedEndpointLogEventText = "Executed endpoint '{EndpointName}'"; + + private readonly Guid _testTenantId = Guid.NewGuid(); + private readonly string _testTenantName = "acme"; + + private readonly AbpAspNetCoreMultiTenancyOptions _tenancyOptions; + private readonly AbpAspNetCoreSerilogOptions _serilogOptions; + private readonly ILogger _logger; + + public Serilog_Enrichers_Tests() + { + _tenancyOptions = ServiceProvider.GetRequiredService>().Value; + _serilogOptions = + ServiceProvider.GetRequiredService>().Value; + _logger = ServiceProvider.GetRequiredService>(); + } + + protected override IHostBuilder CreateHostBuilder() + { + return base.CreateHostBuilder().ConfigureServices(services => + { + services.Configure(options => + { + options.Tenants = new[] + { + new TenantConfiguration(_testTenantId, _testTenantName) + }; + }); + }); + } + + [Fact] + public async Task TenantId_Not_Set_Test() + { + var url = GetUrl(nameof(SerilogTestController.Index)); + var result = await GetResponseAsStringAsync(url).ConfigureAwait(false); + + var executedLogEvent = GetLogEvent(ExecutedEndpointLogEventText); + + executedLogEvent.ShouldNotBeNull(); + executedLogEvent.Properties.ContainsKey(_serilogOptions.EnricherPropertyNames.TenantId) + .ShouldBe(false); + } + + [Fact] + public async Task TenantId_Set_Test() + { + var url = + GetUrl(nameof(SerilogTestController.Index)) + + $"?{_tenancyOptions.TenantKey}={_testTenantName}"; + var result = await GetResponseAsStringAsync(url).ConfigureAwait(false); + + var executedLogEvent = GetLogEvent(ExecutedEndpointLogEventText); + + executedLogEvent.ShouldNotBeNull(); + executedLogEvent.Properties.ContainsKey(_serilogOptions.EnricherPropertyNames.TenantId) + .ShouldBe(true); + ((ScalarValue) executedLogEvent.Properties[_serilogOptions.EnricherPropertyNames.TenantId]).Value + .ShouldBe(_testTenantId); + } + + [Fact] + public async Task CorrelationId_Enrichers_Test() + { + var url = GetUrl(nameof(SerilogTestController.CorrelationId)); + var result = await GetResponseAsStringAsync(url).ConfigureAwait(false); + + var executedLogEvent = GetLogEvent(ExecutedEndpointLogEventText); + + executedLogEvent.ShouldNotBeNull(); + + executedLogEvent.Properties.ContainsKey(_serilogOptions.EnricherPropertyNames.CorrelationId) + .ShouldNotBeNull(); + + ((ScalarValue) executedLogEvent.Properties[_serilogOptions.EnricherPropertyNames.CorrelationId]).Value + .ShouldBe(result); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.csproj index 789b8ba6df..dd8b1fc805 100644 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.csproj @@ -25,7 +25,7 @@ - + diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs index dd5edff807..2c647d0556 100644 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs @@ -26,15 +26,15 @@ namespace Volo.Abp.AspNetCore protected virtual async Task GetResponseAsObjectAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { - var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode); + var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode).ConfigureAwait(false); return JsonConvert.DeserializeObject(strResponse, SharedJsonSerializerSettings); } protected virtual async Task GetResponseAsStringAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { - using (var response = await GetResponseAsync(url, expectedStatusCode)) + using (var response = await GetResponseAsync(url, expectedStatusCode).ConfigureAwait(false)) { - return await response.Content.ReadAsStringAsync(); + return await response.Content.ReadAsStringAsync().ConfigureAwait(false); } } @@ -43,7 +43,7 @@ namespace Volo.Abp.AspNetCore using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, url)) { requestMessage.Headers.Add("Accept-Language", CultureInfo.CurrentUICulture.Name); - var response = await Client.SendAsync(requestMessage); + var response = await Client.SendAsync(requestMessage).ConfigureAwait(false); response.StatusCode.ShouldBe(expectedStatusCode); return response; } diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/VirtualFileSystem/VirtualFileSystem_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/VirtualFileSystem/VirtualFileSystem_Tests.cs index 142d44baec..88399bd9a7 100644 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/VirtualFileSystem/VirtualFileSystem_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/VirtualFileSystem/VirtualFileSystem_Tests.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.AspNetCore.VirtualFileSystem { var result = await GetResponseAsStringAsync( "/SampleFiles/test1.js" - ); + ).ConfigureAwait(false); result.ShouldBe("test1.js-content"); } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj b/framework/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj index b8b1033e51..770ad82870 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs index 23eba6c53b..516310b781 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs @@ -5,6 +5,7 @@ using NSubstitute; using Volo.Abp.Autofac; using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Auditing @@ -37,8 +38,8 @@ namespace Volo.Abp.Auditing using (var scope = _auditingManager.BeginScope()) { - await myAuditedObject1.DoItAsync(new InputObject { Value1 = "forty-two", Value2 = 42 }); - await scope.SaveAsync(); + await myAuditedObject1.DoItAsync(new InputObject { Value1 = "forty-two", Value2 = 42 }).ConfigureAwait(false); + await scope.SaveAsync().ConfigureAwait(false); } #pragma warning disable 4014 diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo.Abp.Authorization.Tests.csproj b/framework/test/Volo.Abp.Authorization.Tests/Volo.Abp.Authorization.Tests.csproj index b137b0a2db..5abc0fc670 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo.Abp.Authorization.Tests.csproj +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo.Abp.Authorization.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthorizationTestBase.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthorizationTestBase.cs index e30565bcf2..8ab051d97e 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthorizationTestBase.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthorizationTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.Authorization +using Volo.Abp.Testing; + +namespace Volo.Abp.Authorization { public class AuthorizationTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs index fa069348cd..2950c7c92a 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs @@ -18,12 +18,12 @@ namespace Volo.Abp.Authorization } [Fact] - public void Should_Not_Allow_To_Call_Method_If_Has_No_Permission_ProtectedByClass() + public async Task Should_Not_Allow_To_Call_Method_If_Has_No_Permission_ProtectedByClass() { - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - _myAuthorizedService1.ProtectedByClass(); - }); + await _myAuthorizedService1.ProtectedByClass().ConfigureAwait(false); + }).ConfigureAwait(false); } [Fact] @@ -31,20 +31,20 @@ namespace Volo.Abp.Authorization { await Assert.ThrowsAsync(async () => { - await _myAuthorizedService1.ProtectedByClassAsync(); - }); + await _myAuthorizedService1.ProtectedByClassAsync().ConfigureAwait(false); + }).ConfigureAwait(false); } [Fact] - public void Should_Allow_To_Call_Anonymous_Method() + public async Task Should_Allow_To_Call_Anonymous_Method() { - _myAuthorizedService1.Anonymous().ShouldBe(42); + (await _myAuthorizedService1.Anonymous().ConfigureAwait(false)).ShouldBe(42); } [Fact] public async Task Should_Allow_To_Call_Anonymous_Method_Async() { - (await _myAuthorizedService1.AnonymousAsync()).ShouldBe(42); + (await _myAuthorizedService1.AnonymousAsync().ConfigureAwait(false)).ShouldBe(42); } [Fact] diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/IMyAuthorizedService1.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/IMyAuthorizedService1.cs index 0ef6bde8a0..b3841c4fed 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/IMyAuthorizedService1.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/IMyAuthorizedService1.cs @@ -4,11 +4,11 @@ namespace Volo.Abp.Authorization.TestServices { public interface IMyAuthorizedService1 { - int Anonymous(); + Task Anonymous(); Task AnonymousAsync(); - int ProtectedByClass(); + Task ProtectedByClass(); Task ProtectedByClassAsync(); } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/MyAuthorizedService1.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/MyAuthorizedService1.cs index 0b33dd0c98..6d64ed80dd 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/MyAuthorizedService1.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/MyAuthorizedService1.cs @@ -8,26 +8,26 @@ namespace Volo.Abp.Authorization.TestServices public class MyAuthorizedService1 : IMyAuthorizedService1, ITransientDependency { [AllowAnonymous] - public virtual int Anonymous() + public virtual Task Anonymous() { - return 42; + return Task.FromResult(42); } [AllowAnonymous] public virtual async Task AnonymousAsync() { - await Task.Delay(10); + await Task.Delay(10).ConfigureAwait(false); return 42; } - public virtual int ProtectedByClass() + public virtual Task ProtectedByClass() { - return 42; + return Task.FromResult(42); } public virtual async Task ProtectedByClassAsync() { - await Task.Delay(10); + await Task.Delay(10).ConfigureAwait(false); return 42; } } diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj b/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj index 171f67c481..4bf0661800 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs index 436c0402d8..3ac2246dcc 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.AutoMapper.SampleClasses; using Volo.Abp.ObjectMapping; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.AutoMapper diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs index cfc846f3b7..1c3b0bf1be 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.AutoMapper.SampleClasses; using Volo.Abp.ObjectMapping; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.AutoMapper diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_ConfigurationValidation_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_ConfigurationValidation_Tests.cs index 7504bd7209..50daf2cc0b 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_ConfigurationValidation_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_ConfigurationValidation_Tests.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; using IObjectMapper = Volo.Abp.ObjectMapping.IObjectMapper; diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/ObjectMapperExtensions_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/ObjectMapperExtensions_Tests.cs index 3958041817..737731fd22 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/ObjectMapperExtensions_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/ObjectMapperExtensions_Tests.cs @@ -3,6 +3,7 @@ using Shouldly; using System; using Volo.Abp.AutoMapper.SampleClasses; using Volo.Abp.ObjectMapping; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.AutoMapper diff --git a/framework/test/Volo.Abp.Autofac.Tests/Volo.Abp.Autofac.Tests.csproj b/framework/test/Volo.Abp.Autofac.Tests/Volo.Abp.Autofac.Tests.csproj index 4f8f97807d..bbbee3bbbb 100644 --- a/framework/test/Volo.Abp.Autofac.Tests/Volo.Abp.Autofac.Tests.csproj +++ b/framework/test/Volo.Abp.Autofac.Tests/Volo.Abp.Autofac.Tests.csproj @@ -14,7 +14,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo.Abp.BackgroundJobs.Tests.csproj b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo.Abp.BackgroundJobs.Tests.csproj index e9a9fbd131..b352c05455 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo.Abp.BackgroundJobs.Tests.csproj +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo.Abp.BackgroundJobs.Tests.csproj @@ -13,7 +13,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs index 566c69c318..50d90d0196 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Shouldly; using Xunit; @@ -23,7 +23,7 @@ namespace Volo.Abp.BackgroundJobs //Act - _backgroundJobExecuter.Execute( + await _backgroundJobExecuter.ExecuteAsync( new JobExecutionContext( ServiceProvider, typeof(MyJob), @@ -35,5 +35,28 @@ namespace Volo.Abp.BackgroundJobs jobObject.ExecutedValues.ShouldContain("42"); } + + [Fact] + public async Task Should_Execute_Async_Tasks() + { + //Arrange + + var jobObject = GetRequiredService(); + jobObject.ExecutedValues.ShouldBeEmpty(); + + //Act + + await _backgroundJobExecuter.ExecuteAsync( + new JobExecutionContext( + ServiceProvider, + typeof(MyAsyncJob), + new MyAsyncJobArgs("42") + ) + ); + + //Assert + + jobObject.ExecutedValues.ShouldContain("42"); + } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs index 2c00573bc7..2cd76620ff 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobManager_Tests.cs @@ -19,9 +19,17 @@ namespace Volo.Abp.BackgroundJobs [Fact] public async Task Should_Store_Jobs() { - var jobIdAsString = await _backgroundJobManager.EnqueueAsync(new MyJobArgs("42")); + var jobIdAsString = await _backgroundJobManager.EnqueueAsync(new MyJobArgs("42")).ConfigureAwait(false); jobIdAsString.ShouldNotBe(default); - (await _backgroundJobStore.FindAsync(Guid.Parse(jobIdAsString))).ShouldNotBeNull(); + (await _backgroundJobStore.FindAsync(Guid.Parse(jobIdAsString)).ConfigureAwait(false)).ShouldNotBeNull(); + } + + [Fact] + public async Task Should_Store_Async_Jobs() + { + var jobIdAsString = await _backgroundJobManager.EnqueueAsync(new MyAsyncJobArgs("42")).ConfigureAwait(false); + jobIdAsString.ShouldNotBe(default); + (await _backgroundJobStore.FindAsync(Guid.Parse(jobIdAsString)).ConfigureAwait(false)).ShouldNotBeNull(); } } } diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs index 6351320242..c2aedce98a 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.BackgroundJobs +using Volo.Abp.Testing; + +namespace Volo.Abp.BackgroundJobs { public abstract class BackgroundJobsTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs new file mode 100644 index 0000000000..a728d85deb --- /dev/null +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.BackgroundJobs +{ + public class MyAsyncJob : AsyncBackgroundJob, ISingletonDependency + { + public List ExecutedValues { get; } = new List(); + + public override Task ExecuteAsync(MyAsyncJobArgs args) + { + ExecutedValues.Add(args.Value); + + return Task.CompletedTask; + } + } +} diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJobArgs.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJobArgs.cs new file mode 100644 index 0000000000..7a12d2a925 --- /dev/null +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJobArgs.cs @@ -0,0 +1,17 @@ +namespace Volo.Abp.BackgroundJobs +{ + public class MyAsyncJobArgs + { + public string Value { get; set; } + + public MyAsyncJobArgs() + { + + } + + public MyAsyncJobArgs(string value) + { + Value = value; + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj b/framework/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj index 0b127786ed..4301d8c1f4 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj +++ b/framework/test/Volo.Abp.Caching.Tests/Volo.Abp.Caching.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs index adb0b01bfc..d3afb3addf 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs @@ -3,6 +3,7 @@ using Shouldly; using System; using System.Reflection; using System.Threading.Tasks; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Caching @@ -25,7 +26,7 @@ namespace Volo.Abp.Caching var cacheKey = Guid.NewGuid().ToString(); //Get (not exists yet) - var cacheItem = await personCache.GetAsync(cacheKey); + var cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); GetDefaultCachingOptions(personCache).SlidingExpiration.ShouldBe(TimeSpan.FromMinutes(20)); diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs index 927448463a..50a4a76763 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Shouldly; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Caching @@ -16,28 +17,28 @@ namespace Volo.Abp.Caching const string personName = "john nash"; //Get (not exists yet) - var cacheItem = await personCache.GetAsync(cacheKey); + var cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); //Set cacheItem = new PersonCacheItem(personName); - await personCache.SetAsync(cacheKey, cacheItem); + await personCache.SetAsync(cacheKey, cacheItem).ConfigureAwait(false); //Get (it should be available now - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); //Remove - await personCache.RemoveAsync(cacheKey); + await personCache.RemoveAsync(cacheKey).ConfigureAwait(false); //Get (not exists since removed) - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); } [Fact] - public async Task GetOrAddAsync() + public void GetOrAdd() { var personCache = GetRequiredService>(); @@ -48,8 +49,8 @@ namespace Volo.Abp.Caching bool factoryExecuted = false; - var cacheItem = await personCache.GetOrAddAsync(cacheKey, - async () => + var cacheItem = personCache.GetOrAdd(cacheKey, + () => { factoryExecuted = true; return new PersonCacheItem(personName); @@ -62,8 +63,8 @@ namespace Volo.Abp.Caching factoryExecuted = false; - cacheItem = await personCache.GetOrAddAsync(cacheKey, - async () => + cacheItem = personCache.GetOrAdd(cacheKey, + () => { factoryExecuted = true; return new PersonCacheItem(personName); @@ -84,41 +85,41 @@ namespace Volo.Abp.Caching const string personName = "john nash"; //Get (not exists yet) - var cacheItem = await personCache.GetAsync(cacheKey); + var cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); - var cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + var cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldBeNull(); //Set cacheItem = new PersonCacheItem(personName); - await personCache.SetAsync(cacheKey, cacheItem); + await personCache.SetAsync(cacheKey, cacheItem).ConfigureAwait(false); //Get (it should be available now, but otherPersonCache not exists now. - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); - cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldBeNull(); //set other person cache cacheItem1 = new Sail.Testing.Caching.PersonCacheItem(personName); - await otherPersonCache.SetAsync(cacheKey, cacheItem1); + await otherPersonCache.SetAsync(cacheKey, cacheItem1).ConfigureAwait(false); - cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldNotBeNull(); cacheItem1.Name.ShouldBe(personName); //Remove - await personCache.RemoveAsync(cacheKey); + await personCache.RemoveAsync(cacheKey).ConfigureAwait(false); //Get (not exists since removed) - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); - cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldNotBeNull(); } @@ -132,23 +133,23 @@ namespace Volo.Abp.Caching const string personName = "john nash"; //Get (not exists yet) - var cacheItem = await personCache.GetAsync(cacheKey); + var cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); //Set cacheItem = new PersonCacheItem(personName); - await personCache.SetAsync(cacheKey, cacheItem); + await personCache.SetAsync(cacheKey, cacheItem).ConfigureAwait(false); //Get (it should be available now - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); //Remove - await personCache.RemoveAsync(cacheKey); + await personCache.RemoveAsync(cacheKey).ConfigureAwait(false); //Get (not exists since removed) - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); } @@ -164,8 +165,8 @@ namespace Volo.Abp.Caching bool factoryExecuted = false; - var cacheItem = await personCache.GetOrAddAsync(cacheKey, - async () => + var cacheItem = personCache.GetOrAdd(cacheKey, + () => { factoryExecuted = true; return new PersonCacheItem(personName); @@ -183,7 +184,7 @@ namespace Volo.Abp.Caching { factoryExecuted = true; return new PersonCacheItem(personName); - }); + }).ConfigureAwait(false); factoryExecuted.ShouldBeFalse(); cacheItem.Name.ShouldBe(personName); @@ -200,41 +201,41 @@ namespace Volo.Abp.Caching const string personName = "john nash"; //Get (not exists yet) - var cacheItem = await personCache.GetAsync(cacheKey); + var cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); - var cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + var cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldBeNull(); //Set cacheItem = new PersonCacheItem(personName); - await personCache.SetAsync(cacheKey, cacheItem); + await personCache.SetAsync(cacheKey, cacheItem).ConfigureAwait(false); //Get (it should be available now, but otherPersonCache not exists now. - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); - cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldBeNull(); //set other person cache cacheItem1 = new Sail.Testing.Caching.PersonCacheItem(personName); - await otherPersonCache.SetAsync(cacheKey, cacheItem1); + await otherPersonCache.SetAsync(cacheKey, cacheItem1).ConfigureAwait(false); - cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldNotBeNull(); cacheItem1.Name.ShouldBe(personName); //Remove - await personCache.RemoveAsync(cacheKey); + await personCache.RemoveAsync(cacheKey).ConfigureAwait(false); //Get (not exists since removed) - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); - cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1 = await otherPersonCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem1.ShouldNotBeNull(); } @@ -248,23 +249,23 @@ namespace Volo.Abp.Caching const string personName = "john nash"; //Get (not exists yet) - var cacheItem = await personCache.GetAsync(cacheKey); + var cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); //Set cacheItem = new PersonCacheItem(personName); - await personCache.SetAsync(cacheKey, cacheItem); + await personCache.SetAsync(cacheKey, cacheItem).ConfigureAwait(false); //Get (it should be available now - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldNotBeNull(); cacheItem.Name.ShouldBe(personName); //Remove - await personCache.RemoveAsync(cacheKey); + await personCache.RemoveAsync(cacheKey).ConfigureAwait(false); //Get (not exists since removed) - cacheItem = await personCache.GetAsync(cacheKey); + cacheItem = await personCache.GetAsync(cacheKey).ConfigureAwait(false); cacheItem.ShouldBeNull(); } @@ -278,34 +279,34 @@ namespace Volo.Abp.Caching const string personName = "john nash"; //Get (not exists yet) - var cacheItem1 = await personCache.GetAsync(cache1Key); - var cacheItem2 = await personCache.GetAsync(cache2Key); + var cacheItem1 = await personCache.GetAsync(cache1Key).ConfigureAwait(false); + var cacheItem2 = await personCache.GetAsync(cache2Key).ConfigureAwait(false); cacheItem1.ShouldBeNull(); cacheItem2.ShouldBeNull(); //Set cacheItem1 = new PersonCacheItem(personName); cacheItem2 = new PersonCacheItem(personName); - await personCache.SetAsync(cache1Key, cacheItem1); - await personCache.SetAsync(cache2Key, cacheItem2); + await personCache.SetAsync(cache1Key, cacheItem1).ConfigureAwait(false); + await personCache.SetAsync(cache2Key, cacheItem2).ConfigureAwait(false); //Get (it should be available now - cacheItem1 = await personCache.GetAsync(cache1Key); + cacheItem1 = await personCache.GetAsync(cache1Key).ConfigureAwait(false); cacheItem1.ShouldNotBeNull(); cacheItem1.Name.ShouldBe(personName); - cacheItem2 = await personCache.GetAsync(cache2Key); + cacheItem2 = await personCache.GetAsync(cache2Key).ConfigureAwait(false); cacheItem2.ShouldNotBeNull(); cacheItem2.Name.ShouldBe(personName); //Remove - await personCache.RemoveAsync(cache1Key); - await personCache.RemoveAsync(cache2Key); + await personCache.RemoveAsync(cache1Key).ConfigureAwait(false); + await personCache.RemoveAsync(cache2Key).ConfigureAwait(false); //Get (not exists since removed) - cacheItem1 = await personCache.GetAsync(cache1Key); + cacheItem1 = await personCache.GetAsync(cache1Key).ConfigureAwait(false); cacheItem1.ShouldBeNull(); - cacheItem2 = await personCache.GetAsync(cache2Key); + cacheItem2 = await personCache.GetAsync(cache2Key).ConfigureAwait(false); cacheItem2.ShouldBeNull(); } diff --git a/framework/test/Volo.Abp.Castle.Core.Tests/Volo.Abp.Castle.Core.Tests.csproj b/framework/test/Volo.Abp.Castle.Core.Tests/Volo.Abp.Castle.Core.Tests.csproj index 8c7129239d..9911775a60 100644 --- a/framework/test/Volo.Abp.Castle.Core.Tests/Volo.Abp.Castle.Core.Tests.csproj +++ b/framework/test/Volo.Abp.Castle.Core.Tests/Volo.Abp.Castle.Core.Tests.csproj @@ -10,7 +10,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.Cli.Core.Tests/Volo.Abp.Cli.Core.Tests.csproj b/framework/test/Volo.Abp.Cli.Core.Tests/Volo.Abp.Cli.Core.Tests.csproj index ef7fc3e52d..76de07406a 100644 --- a/framework/test/Volo.Abp.Cli.Core.Tests/Volo.Abp.Cli.Core.Tests.csproj +++ b/framework/test/Volo.Abp.Cli.Core.Tests/Volo.Abp.Cli.Core.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Cli.Core.Tests/Volo/Abp/Cli/AbpCliTestBase.cs b/framework/test/Volo.Abp.Cli.Core.Tests/Volo/Abp/Cli/AbpCliTestBase.cs index 6f6393b7ae..dd93bde1ca 100644 --- a/framework/test/Volo.Abp.Cli.Core.Tests/Volo/Abp/Cli/AbpCliTestBase.cs +++ b/framework/test/Volo.Abp.Cli.Core.Tests/Volo/Abp/Cli/AbpCliTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.Cli +using Volo.Abp.Testing; + +namespace Volo.Abp.Cli { public class AbpCliTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs index 64057659b6..680cb607f7 100644 --- a/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs @@ -4,6 +4,7 @@ using Shouldly; using Volo.Abp; using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Microsoft.Extensions.DependencyInjection diff --git a/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs b/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs index 0720a492aa..23d961dfa7 100644 --- a/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs @@ -11,7 +11,7 @@ namespace System public StringExtensions_Tests() { - _cultureScope = AbpCultureHelper.Use("en-US"); + _cultureScope = CultureHelper.Use("en-US"); } [Fact] @@ -31,7 +31,7 @@ namespace System [Fact] public void EnsureEndsWith_CultureSpecific_Test() { - using (AbpCultureHelper.Use("tr-TR")) + using (CultureHelper.Use("tr-TR")) { "Kırmızı".EnsureEndsWith('I', StringComparison.CurrentCultureIgnoreCase).ShouldBe("Kırmızı"); } @@ -59,7 +59,7 @@ namespace System [Fact] public void ToPascalCase_CurrentCulture_Test() { - using (AbpCultureHelper.Use("tr-TR")) + using (CultureHelper.Use("tr-TR")) { "istanbul".ToPascalCase(true).ShouldBe("İstanbul"); } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo.Abp.Core.Tests.csproj b/framework/test/Volo.Abp.Core.Tests/Volo.Abp.Core.Tests.csproj index 1171b49e52..5a5d49e9e0 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo.Abp.Core.Tests.csproj +++ b/framework/test/Volo.Abp.Core.Tests/Volo.Abp.Core.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs index 27b3bf5d81..781a128191 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.DynamicProxy @@ -12,7 +13,6 @@ namespace Volo.Abp.DynamicProxy protected override void BeforeAddApplication(IServiceCollection services) { services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -24,7 +24,6 @@ namespace Volo.Abp.DynamicProxy if (typeof(SimpleInterceptionTargetClass) == registration.ImplementationType) { registration.Interceptors.Add(); - registration.Interceptors.Add(); registration.Interceptors.Add(); } @@ -40,24 +39,22 @@ namespace Volo.Abp.DynamicProxy { //Arrange - var target = ServiceProvider.GetService(); - - //Act - - await target.DoItAsync(); + var target = ServiceProvider.GetService(); + + //Act + + await target.DoItAsync().ConfigureAwait(false); //Assert - target.Logs.Count.ShouldBe(9); + target.Logs.Count.ShouldBe(7); target.Logs[0].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_BeforeInvocation"); - target.Logs[1].ShouldBe("SimpleSyncInterceptor_Intercept_BeforeInvocation"); - target.Logs[2].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_BeforeInvocation"); - target.Logs[3].ShouldBe("EnterDoItAsync"); - target.Logs[4].ShouldBe("MiddleDoItAsync"); - target.Logs[5].ShouldBe("ExitDoItAsync"); - target.Logs[6].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_AfterInvocation"); - target.Logs[7].ShouldBe("SimpleSyncInterceptor_Intercept_AfterInvocation"); - target.Logs[8].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_AfterInvocation"); + target.Logs[1].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_BeforeInvocation"); + target.Logs[2].ShouldBe("EnterDoItAsync"); + target.Logs[3].ShouldBe("MiddleDoItAsync"); + target.Logs[4].ShouldBe("ExitDoItAsync"); + target.Logs[5].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_AfterInvocation"); + target.Logs[6].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_AfterInvocation"); } [Fact] @@ -69,81 +66,19 @@ namespace Volo.Abp.DynamicProxy //Act - var result = await target.GetValueAsync(); - - //Assert - - result.ShouldBe(42); - target.Logs.Count.ShouldBe(9); - target.Logs[0].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_BeforeInvocation"); - target.Logs[1].ShouldBe("SimpleSyncInterceptor_Intercept_BeforeInvocation"); - target.Logs[2].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_BeforeInvocation"); - target.Logs[3].ShouldBe("EnterGetValueAsync"); - target.Logs[4].ShouldBe("MiddleGetValueAsync"); - target.Logs[5].ShouldBe("ExitGetValueAsync"); - target.Logs[6].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_AfterInvocation"); - target.Logs[7].ShouldBe("SimpleSyncInterceptor_Intercept_AfterInvocation"); - target.Logs[8].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_AfterInvocation"); - } - - [Fact] - public void Should_Intercept_Sync_Method_Without_Return_Value() - { - //Arrange - - var target = ServiceProvider.GetService(); - - //Act - - target.DoIt(); - - //Assert - target.Logs.Count.ShouldBe(7); - target.Logs[0].ShouldBe("SimpleAsyncInterceptor_Intercept_BeforeInvocation"); - target.Logs[1].ShouldBe("SimpleSyncInterceptor_Intercept_BeforeInvocation"); - target.Logs[2].ShouldBe("SimpleAsyncInterceptor2_Intercept_BeforeInvocation"); - target.Logs[3].ShouldBe("ExecutingDoIt"); - target.Logs[4].ShouldBe("SimpleAsyncInterceptor2_Intercept_AfterInvocation"); - target.Logs[5].ShouldBe("SimpleSyncInterceptor_Intercept_AfterInvocation"); - target.Logs[6].ShouldBe("SimpleAsyncInterceptor_Intercept_AfterInvocation"); - } - - [Fact] - public void Should_Intercept_Sync_Method_With_Return_Value() - { - //Arrange - - var target = ServiceProvider.GetService(); - - //Act - - var result = target.GetValue(); + var result = await target.GetValueAsync().ConfigureAwait(false); //Assert result.ShouldBe(42); target.Logs.Count.ShouldBe(7); - target.Logs[0].ShouldBe("SimpleAsyncInterceptor_Intercept_BeforeInvocation"); - target.Logs[1].ShouldBe("SimpleSyncInterceptor_Intercept_BeforeInvocation"); - target.Logs[2].ShouldBe("SimpleAsyncInterceptor2_Intercept_BeforeInvocation"); - target.Logs[3].ShouldBe("ExecutingGetValue"); - target.Logs[4].ShouldBe("SimpleAsyncInterceptor2_Intercept_AfterInvocation"); - target.Logs[5].ShouldBe("SimpleSyncInterceptor_Intercept_AfterInvocation"); - target.Logs[6].ShouldBe("SimpleAsyncInterceptor_Intercept_AfterInvocation"); - } - - [Fact] - public void Should_Cache_Results() - { - //Arrange - - var target = ServiceProvider.GetService(); - - //Act & Assert - - target.GetValue(42).ShouldBe(42); //First run, not cached yet - target.GetValue(43).ShouldBe(42); //First run, cached previous value - target.GetValue(44).ShouldBe(42); //First run, cached previous value + target.Logs[0].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_BeforeInvocation"); + target.Logs[1].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_BeforeInvocation"); + target.Logs[2].ShouldBe("EnterGetValueAsync"); + target.Logs[3].ShouldBe("MiddleGetValueAsync"); + target.Logs[4].ShouldBe("ExitGetValueAsync"); + target.Logs[5].ShouldBe("SimpleAsyncInterceptor2_InterceptAsync_AfterInvocation"); + target.Logs[6].ShouldBe("SimpleAsyncInterceptor_InterceptAsync_AfterInvocation"); } [Fact] @@ -155,9 +90,9 @@ namespace Volo.Abp.DynamicProxy //Act & Assert - (await target.GetValueAsync(42)).ShouldBe(42); //First run, not cached yet - (await target.GetValueAsync(43)).ShouldBe(42); //First run, cached previous value - (await target.GetValueAsync(44)).ShouldBe(42); //First run, cached previous value + (await target.GetValueAsync(42).ConfigureAwait(false)).ShouldBe(42); //First run, not cached yet + (await target.GetValueAsync(43).ConfigureAwait(false)).ShouldBe(42); //First run, cached previous value + (await target.GetValueAsync(44).ConfigureAwait(false)).ShouldBe(42); //First run, cached previous value } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs index db06b78b6a..8c7a797c7b 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/CachedTestObject.cs @@ -12,8 +12,8 @@ namespace Volo.Abp.DynamicProxy } public virtual async Task GetValueAsync(int v) - { - await Task.Delay(5); + { + await Task.Delay(5).ConfigureAwait(false); return v; } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs index f1f868700a..41438d1543 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs @@ -5,20 +5,13 @@ namespace Volo.Abp.DynamicProxy { public class SimpleAsyncInterceptor : AbpInterceptor { - public override void Intercept(IAbpMethodInvocation invocation) - { - (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_Intercept_BeforeInvocation"); - invocation.ProceedAsync(); - (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_Intercept_AfterInvocation"); - } - - public override async Task InterceptAsync(IAbpMethodInvocation invocation) - { - await Task.Delay(5); + public override async Task InterceptAsync(IAbpMethodInvocation invocation) + { + await Task.Delay(5).ConfigureAwait(false); (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_BeforeInvocation"); - await invocation.ProceedAsync(); + await invocation.ProceedAsync().ConfigureAwait(false); (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_InterceptAsync_AfterInvocation"); - await Task.Delay(5); + await Task.Delay(5).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleInterceptionTargetClass.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleInterceptionTargetClass.cs index d1f23ea34c..e683e074d8 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleInterceptionTargetClass.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleInterceptionTargetClass.cs @@ -22,9 +22,9 @@ namespace Volo.Abp.DynamicProxy public virtual async Task GetValueAsync() { Logs.Add("EnterGetValueAsync"); - await Task.Delay(5); + await Task.Delay(5).ConfigureAwait(false); Logs.Add("MiddleGetValueAsync"); - await Task.Delay(5); + await Task.Delay(5).ConfigureAwait(false); Logs.Add("ExitGetValueAsync"); return 42; } @@ -32,9 +32,9 @@ namespace Volo.Abp.DynamicProxy public virtual async Task DoItAsync() { Logs.Add("EnterDoItAsync"); - await Task.Delay(5); + await Task.Delay(5).ConfigureAwait(false); Logs.Add("MiddleDoItAsync"); - await Task.Delay(5); + await Task.Delay(5).ConfigureAwait(false); Logs.Add("ExitDoItAsync"); } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleResultCacheTestInterceptor.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleResultCacheTestInterceptor.cs index 1712d316a8..06c3d096fe 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleResultCacheTestInterceptor.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleResultCacheTestInterceptor.cs @@ -12,25 +12,16 @@ namespace Volo.Abp.DynamicProxy { _cache = new ConcurrentDictionary(); } - - public override void Intercept(IAbpMethodInvocation invocation) - { - invocation.ReturnValue = _cache.GetOrAdd(invocation.Method, m => - { - invocation.Proceed(); - return invocation.ReturnValue; - }); - } - + public override async Task InterceptAsync(IAbpMethodInvocation invocation) { if (_cache.ContainsKey(invocation.Method)) { invocation.ReturnValue = _cache[invocation.Method]; return; - } - - await invocation.ProceedAsync(); + } + + await invocation.ProceedAsync().ConfigureAwait(false); _cache[invocation.Method] = invocation.ReturnValue; } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleSyncInterceptor.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleSyncInterceptor.cs deleted file mode 100644 index fc43e31525..0000000000 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/SimpleSyncInterceptor.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Volo.Abp.TestBase.Logging; - -namespace Volo.Abp.DynamicProxy -{ - public class SimpleSyncInterceptor : AbpInterceptor - { - public override void Intercept(IAbpMethodInvocation invocation) - { - (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_Intercept_BeforeInvocation"); - invocation.Proceed(); - (invocation.TargetObject as ICanLogOnObject)?.Logs?.Add($"{GetType().Name}_Intercept_AfterInvocation"); - } - } -} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Threading/AsyncHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Threading/AsyncHelper_Tests.cs index 1b7b7eacd2..53a4516560 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Threading/AsyncHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Threading/AsyncHelper_Tests.cs @@ -41,12 +41,12 @@ namespace Volo.Abp.Threading private static async Task MyTaskWithoutReturnValueAsync() { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); } private static async Task MyTaskWithReturnValueAsync(int aNumber) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); return aNumber; } diff --git a/framework/test/Volo.Abp.Dapper.Tests/Volo.Abp.Dapper.Tests.csproj b/framework/test/Volo.Abp.Dapper.Tests/Volo.Abp.Dapper.Tests.csproj index 8dde99ead9..33bdd870e2 100644 --- a/framework/test/Volo.Abp.Dapper.Tests/Volo.Abp.Dapper.Tests.csproj +++ b/framework/test/Volo.Abp.Dapper.Tests/Volo.Abp.Dapper.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/DapperTestBase.cs b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/DapperTestBase.cs index 3fa387cec2..2221bfd3e8 100644 --- a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/DapperTestBase.cs +++ b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/DapperTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.Dapper +using Volo.Abp.Testing; + +namespace Volo.Abp.Dapper { public abstract class DapperTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs index 3621f9301e..f7a01649de 100644 --- a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs +++ b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs @@ -17,14 +17,14 @@ namespace Volo.Abp.Dapper.Repositories public virtual async Task> GetAllPersonNames() { - return (await DbConnection.QueryAsync("select Name from People", transaction: DbTransaction)) + return (await DbConnection.QueryAsync("select Name from People", transaction: DbTransaction).ConfigureAwait(false)) .ToList(); } public virtual async Task UpdatePersonNames(string name) { - return await DbConnection.ExecuteAsync("update People set Name = @NewName", new {NewName = name}, - DbTransaction); + return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name }, + DbTransaction).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository_Tests.cs b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository_Tests.cs index 28734c1fd0..cf085b2298 100644 --- a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository_Tests.cs +++ b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository_Tests.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.Dapper.Repositories [Fact] public async Task GetAllPersonNames_Test() { - var allNames = await GetRequiredService().GetAllPersonNames(); + var allNames = await GetRequiredService().GetAllPersonNames().ConfigureAwait(false); allNames.ShouldNotBeEmpty(); allNames.ShouldContain(x => x == "Douglas"); allNames.ShouldContain(x => x == "John-Deleted"); @@ -23,9 +23,9 @@ namespace Volo.Abp.Dapper.Repositories public async Task UpdatePersonNames_Test() { var personDapperRepository = GetRequiredService(); - await personDapperRepository.UpdatePersonNames("test"); + await personDapperRepository.UpdatePersonNames("test").ConfigureAwait(false); - var allNames = await personDapperRepository.GetAllPersonNames(); + var allNames = await personDapperRepository.GetAllPersonNames().ConfigureAwait(false); allNames.ShouldNotBeEmpty(); allNames.ShouldAllBe(x => x == "test"); } @@ -41,11 +41,11 @@ namespace Volo.Abp.Dapper.Repositories IsTransactional = true })) { - await personDapperRepository.UpdatePersonNames("test"); - await uow.RollbackAsync(); + await personDapperRepository.UpdatePersonNames("test").ConfigureAwait(false); + await uow.RollbackAsync().ConfigureAwait(false); } - var allNames = await personDapperRepository.GetAllPersonNames(); + var allNames = await personDapperRepository.GetAllPersonNames().ConfigureAwait(false); allNames.ShouldAllBe(x => x != "test"); } } diff --git a/framework/test/Volo.Abp.Data.Tests/Volo.Abp.Data.Tests.csproj b/framework/test/Volo.Abp.Data.Tests/Volo.Abp.Data.Tests.csproj index fca4da8664..9e7cb21644 100644 --- a/framework/test/Volo.Abp.Data.Tests/Volo.Abp.Data.Tests.csproj +++ b/framework/test/Volo.Abp.Data.Tests/Volo.Abp.Data.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs b/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs index 4f4dabf36a..d13c89671e 100644 --- a/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs +++ b/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Data diff --git a/framework/test/Volo.Abp.Ddd.Tests/Volo.Abp.Ddd.Tests.csproj b/framework/test/Volo.Abp.Ddd.Tests/Volo.Abp.Ddd.Tests.csproj index 03179dc0aa..6c7bcc9ca5 100644 --- a/framework/test/Volo.Abp.Ddd.Tests/Volo.Abp.Ddd.Tests.csproj +++ b/framework/test/Volo.Abp.Ddd.Tests/Volo.Abp.Ddd.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs index 820a62892e..7e1dd24ae6 100644 --- a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs +++ b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -239,51 +240,47 @@ namespace Volo.Abp.Domain.Repositories public class MyTestDefaultRepository : RepositoryBase where TEntity : class, IEntity { - public override TEntity Insert(TEntity entity, bool autoSave = false) - { - throw new NotImplementedException(); - } - public override TEntity Update(TEntity entity, bool autoSave = false) + protected override IQueryable GetQueryable() { throw new NotImplementedException(); } - public override void Delete(TEntity entity, bool autoSave = false) + public override Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - public override List GetList(bool includeDetails = false) + public override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - public override long GetCount() + public override Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - protected override IQueryable GetQueryable() + public override Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - } - public class MyTestDefaultRepository : MyTestDefaultRepository, IRepository - where TEntity : class, IEntity - { - public TEntity Get(TKey id, bool includeDetails = true) + public override Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } - public Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) + public override Task GetCountAsync(CancellationToken cancellationToken = default) { throw new NotImplementedException(); } + } - public TEntity Find(TKey id, bool includeDetails = true) + public class MyTestDefaultRepository : MyTestDefaultRepository, IRepository + where TEntity : class, IEntity + { + public Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } @@ -293,11 +290,6 @@ namespace Volo.Abp.Domain.Repositories throw new NotImplementedException(); } - public void Delete(TKey id, bool autoSave = false) - { - throw new NotImplementedException(); - } - public Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { throw new NotImplementedException(); diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj b/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj index 754c635ec1..3a1b803370 100644 --- a/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj @@ -18,7 +18,7 @@ - + diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateRender_Tests.cs b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateRender_Tests.cs index 403aaad0bd..8c02b765e0 100644 --- a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateRender_Tests.cs +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateRender_Tests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Shouldly; using Volo.Abp.Emailing.Templates; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Emailing @@ -43,7 +44,7 @@ namespace Volo.Abp.Emailing } }; - var result = await _templateRender.RenderAsync(template, model); + var result = await _templateRender.RenderAsync(template, model).ConfigureAwait(false); result.ShouldBe("Hello john@abp.io 1:iphone,2:ipad,"); } diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs index 1011232e57..90aa9563ea 100644 --- a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Shouldly; using Volo.Abp.Emailing.Templates; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Emailing @@ -23,21 +24,21 @@ namespace Volo.Abp.Emailing [Fact] public async Task Should_Get_Registered_Template() { - var template = await _emailTemplateProvider.GetAsync("template1", "tr"); + var template = await _emailTemplateProvider.GetAsync("template1", "tr").ConfigureAwait(false); template.Content.ShouldContain("Lütfen aşağıdaki bağlantıya tıklayarak e-posta adresinizi onaylayın."); } [Fact] public async Task Should_Get_Default_Culture_Template() { - var template = await _emailTemplateProvider.GetAsync("template1", "zh-Hans"); + var template = await _emailTemplateProvider.GetAsync("template1", "zh-Hans").ConfigureAwait(false); template.Content.ShouldContain("Please confirm your email address by clicking the link below."); } [Fact] public async Task Should_Get_Registered_Template_With_Layout() { - var template = await _emailTemplateProvider.GetAsync("template2", "en"); + var template = await _emailTemplateProvider.GetAsync("template2", "en").ConfigureAwait(false); template.Content.ShouldContain($"{Environment.NewLine} " + "Please confirm your email address by clicking the link below."); } @@ -46,7 +47,7 @@ namespace Volo.Abp.Emailing [Fact] public async Task Should_Get_Registered_Template_With_Localize() { - var template = await _emailTemplateProvider.GetAsync("template3", "tr"); + var template = await _emailTemplateProvider.GetAsync("template3", "tr").ConfigureAwait(false); template.Content.ShouldContain("Merhaba Abp"); } } diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json index b03a2b3fb1..5f6e35488e 100644 --- a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json @@ -1,6 +1,6 @@ { "culture": "cs", "texts": { - "hello": "hello" + "hello": "ahoj" } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json new file mode 100644 index 0000000000..dd12964f70 --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hant", + "texts": { + "hello": "哈囉" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs index 02142f06d9..80ece93c07 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.EntityFrameworkCore.TestApp.SecondContext { @@ -29,9 +30,9 @@ namespace Volo.Abp.EntityFrameworkCore.TestApp.SecondContext { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondContextTestDataBuilder.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondContextTestDataBuilder.cs index 0b89576f34..1f69263f5c 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondContextTestDataBuilder.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondContextTestDataBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.Guids; @@ -16,14 +17,14 @@ namespace Volo.Abp.EntityFrameworkCore.TestApp.SecondContext _guidGenerator = guidGenerator; } - public void Build() + public async Task BuildAsync() { - _bookRepository.Insert( + await _bookRepository.InsertAsync( new BookInSecondDbContext( _guidGenerator.Create(), "TestBook1" ) - ); + ).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo.Abp.EntityFrameworkCore.Tests.csproj b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo.Abp.EntityFrameworkCore.Tests.csproj index 41c244d81d..a01e3d111a 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo.Abp.EntityFrameworkCore.Tests.csproj +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo.Abp.EntityFrameworkCore.Tests.csproj @@ -17,7 +17,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs index 8ada582fa6..5ee320742c 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs @@ -1,9 +1,11 @@ using System; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Domain.Repositories; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.EntityFrameworkCore; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.EntityFrameworkCore @@ -11,19 +13,26 @@ namespace Volo.Abp.EntityFrameworkCore public class DbContext_Replace_Tests : EntityFrameworkCoreTestBase { private readonly IBasicRepository _dummyRepository; + private readonly IUnitOfWorkManager _unitOfWorkManager; public DbContext_Replace_Tests() { _dummyRepository = ServiceProvider.GetRequiredService>(); + _unitOfWorkManager = ServiceProvider.GetRequiredService(); } [Fact] - public void Should_Replace_DbContext() + public async Task Should_Replace_DbContext() { (ServiceProvider.GetRequiredService() is TestAppDbContext).ShouldBeTrue(); - (_dummyRepository.GetDbContext() is IThirdDbContext).ShouldBeTrue(); - (_dummyRepository.GetDbContext() is TestAppDbContext).ShouldBeTrue(); + using (_unitOfWorkManager.Begin()) + { + (_dummyRepository.GetDbContext() is IThirdDbContext).ShouldBeTrue(); + (_dummyRepository.GetDbContext() is TestAppDbContext).ShouldBeTrue(); + + await _unitOfWorkManager.Current.CompleteAsync().ConfigureAwait(false); + } } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs index 87bd7cfc28..f40cfcdddf 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EntityFrameworkCoreTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.EntityFrameworkCore +using Volo.Abp.Testing; + +namespace Volo.Abp.EntityFrameworkCore { public abstract class EntityFrameworkCoreTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Queryable_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Queryable_Tests.cs index bd4859784a..d178ff7965 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Queryable_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/Repository_Queryable_Tests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Shouldly; @@ -23,32 +24,35 @@ namespace Volo.Abp.EntityFrameworkCore.Repositories } [Fact] - public void GetBookList() + public async Task GetBookList() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { _bookRepository.Any().ShouldBeTrue(); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void GetPhoneInSecondDbContextList() + public async Task GetPhoneInSecondDbContextList() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { _phoneInSecondDbContextRepository.Any().ShouldBeTrue(); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void EfCore_Include_Extension() + public async Task EfCore_Include_Extension() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var person = PersonRepository.Include(p => p.Phones).Single(p => p.Id == TestDataBuilder.UserDouglasId); person.Name.ShouldBe("Douglas"); person.Phones.Count.ShouldBe(2); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Transactions/Transaction_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Transactions/Transaction_Tests.cs index 7d89da1a08..db4a376ae4 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Transactions/Transaction_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Transactions/Transaction_Tests.cs @@ -34,16 +34,16 @@ namespace Volo.Abp.EntityFrameworkCore.Transactions { await WithUnitOfWorkAsync(new AbpUnitOfWorkOptions { IsTransactional = true }, async () => { - await _personRepository.InsertAsync(new Person(personId, "Adam", 42)); + await _personRepository.InsertAsync(new Person(personId, "Adam", 42)).ConfigureAwait(false); throw new Exception(exceptionMessage); - }); + }).ConfigureAwait(false); } catch (Exception e) when (e.Message == exceptionMessage) { } - var person = await _personRepository.FindAsync(personId); + var person = await _personRepository.FindAsync(personId).ConfigureAwait(false); person.ShouldBeNull(); } @@ -56,12 +56,12 @@ namespace Volo.Abp.EntityFrameworkCore.Transactions { _unitOfWorkManager.Current.ShouldNotBeNull(); - await _personRepository.InsertAsync(new Person(personId, "Adam", 42)); + await _personRepository.InsertAsync(new Person(personId, "Adam", 42)).ConfigureAwait(false); - await _unitOfWorkManager.Current.RollbackAsync(); - }); + await _unitOfWorkManager.Current.RollbackAsync().ConfigureAwait(false); + }).ConfigureAwait(false); - var person = await _personRepository.FindAsync(personId); + var person = await _personRepository.FindAsync(personId).ConfigureAwait(false); person.ShouldBeNull(); } @@ -79,17 +79,17 @@ namespace Volo.Abp.EntityFrameworkCore.Transactions { _unitOfWorkManager.Current.ShouldNotBeNull(); - await _personRepository.InsertAsync(new Person(personId, "Adam", 42)); - await _bookRepository.InsertAsync(new BookInSecondDbContext(bookId, bookId.ToString())); + await _personRepository.InsertAsync(new Person(personId, "Adam", 42)).ConfigureAwait(false); + await _bookRepository.InsertAsync(new BookInSecondDbContext(bookId, bookId.ToString())).ConfigureAwait(false); - await _unitOfWorkManager.Current.SaveChangesAsync(); + await _unitOfWorkManager.Current.SaveChangesAsync().ConfigureAwait(false); //Will automatically rollback since not called the Complete! } } - (await _personRepository.FindAsync(personId)).ShouldBeNull(); - (await _bookRepository.FindAsync(bookId)).ShouldBeNull(); + (await _personRepository.FindAsync(personId).ConfigureAwait(false)).ShouldBeNull(); + (await _bookRepository.FindAsync(bookId).ConfigureAwait(false)).ShouldBeNull(); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs index 027f54a03a..05becda1d3 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs @@ -18,13 +18,13 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore public async Task FindByNameAsync(string name) { - return await this.FirstOrDefaultAsync(c => c.Name == name); + return await this.FirstOrDefaultAsync(c => c.Name == name).ConfigureAwait(false); } public async Task> GetPeopleInTheCityAsync(string cityName) { - var city = await FindByNameAsync(cityName); - return await DbContext.People.Where(p => p.CityId == city.Id).ToListAsync(); + var city = await FindByNameAsync(cityName).ConfigureAwait(false); + return await DbContext.People.Where(p => p.CityId == city.Id).ToListAsync().ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs index ab8c1920a7..01b949015a 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore public async Task GetViewAsync(string name) { - return await DbContext.PersonView.Where(x => x.Name == name).FirstOrDefaultAsync(); + return await DbContext.PersonView.Where(x => x.Name == name).FirstOrDefaultAsync().ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo.Abp.EventBus.Tests.csproj b/framework/test/Volo.Abp.EventBus.Tests/Volo.Abp.EventBus.Tests.csproj index a3888064d2..6a7a017f4e 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo.Abp.EventBus.Tests.csproj +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo.Abp.EventBus.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBusTestBase.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBusTestBase.cs index d4e8df71aa..59e641d04f 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBusTestBase.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBusTestBase.cs @@ -1,3 +1,5 @@ +using Volo.Abp.Testing; + namespace Volo.Abp.EventBus.Distributed { public abstract class LocalDistributedEventBusTestBase : AbpIntegratedTest diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs index 47649ad3c3..19e61e5afb 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs @@ -10,9 +10,9 @@ namespace Volo.Abp.EventBus.Distributed { DistributedEventBus.Subscribe(); - await DistributedEventBus.PublishAsync(new MySimpleEventData(1)); - await DistributedEventBus.PublishAsync(new MySimpleEventData(2)); - await DistributedEventBus.PublishAsync(new MySimpleEventData(3)); + await DistributedEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await DistributedEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await DistributedEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); Assert.Equal(3, MySimpleDistributedTransientEventHandler.HandleCount); Assert.Equal(3, MySimpleDistributedTransientEventHandler.DisposeCount); diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/ActionBasedEventHandlerTest.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/ActionBasedEventHandlerTest.cs index 6e6bae2fae..8e41a26eae 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/ActionBasedEventHandlerTest.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/ActionBasedEventHandlerTest.cs @@ -19,10 +19,10 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(new MySimpleEventData(3)); - await LocalEventBus.PublishAsync(new MySimpleEventData(4)); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(4)).ConfigureAwait(false); Assert.Equal(10, totalData); } @@ -39,10 +39,10 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(3)); - await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(4)); + await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(3)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(typeof(MySimpleEventData), new MySimpleEventData(4)).ConfigureAwait(false); Assert.Equal(10, totalData); } @@ -59,13 +59,13 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(new MySimpleEventData(3)); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); registerDisposer.Dispose(); - await LocalEventBus.PublishAsync(new MySimpleEventData(4)); + await LocalEventBus.PublishAsync(new MySimpleEventData(4)).ConfigureAwait(false); Assert.Equal(6, totalData); } @@ -84,13 +84,13 @@ namespace Volo.Abp.EventBus.Local LocalEventBus.Subscribe(action); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(new MySimpleEventData(3)); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); LocalEventBus.Unsubscribe(action); - await LocalEventBus.PublishAsync(new MySimpleEventData(4)); + await LocalEventBus.PublishAsync(new MySimpleEventData(4)).ConfigureAwait(false); Assert.Equal(6, totalData); } @@ -103,15 +103,15 @@ namespace Volo.Abp.EventBus.Local LocalEventBus.Subscribe( async eventData => { - await Task.Delay(20); + await Task.Delay(20).ConfigureAwait(false); Interlocked.Add(ref totalData, eventData.Value); - await Task.Delay(20); + await Task.Delay(20).ConfigureAwait(false); }); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(new MySimpleEventData(3)); - await LocalEventBus.PublishAsync(new MySimpleEventData(4)); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(4)).ConfigureAwait(false); Assert.Equal(10, totalData); } diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBusTestBase.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBusTestBase.cs index b3a55c340b..f3040c1f65 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBusTestBase.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBusTestBase.cs @@ -1,3 +1,5 @@ +using Volo.Abp.Testing; + namespace Volo.Abp.EventBus.Local { public abstract class EventBusTestBase : AbpIntegratedTest diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_DI_Services_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_DI_Services_Test.cs index e66deb0e1c..4ae07d8dc6 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_DI_Services_Test.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_DI_Services_Test.cs @@ -9,10 +9,10 @@ namespace Volo.Abp.EventBus.Local [Fact] public async Task Should_Automatically_Register_EventHandlers_From_Services() { - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(new MySimpleEventData(3)); - await LocalEventBus.PublishAsync(new MySimpleEventData(4)); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(4)).ConfigureAwait(false); GetRequiredService().TotalData.ShouldBe(10); } diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Test.cs index 446825c697..951a9f841d 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Test.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_Exception_Test.cs @@ -14,8 +14,8 @@ namespace Volo.Abp.EventBus.Local var appException = await Assert.ThrowsAsync(async () => { - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - }); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + }).ConfigureAwait(false); appException.Message.ShouldBe("This exception is intentionally thrown!"); } @@ -31,8 +31,8 @@ namespace Volo.Abp.EventBus.Local var aggrException = await Assert.ThrowsAsync(async () => { - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - }); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + }).ConfigureAwait(false); aggrException.InnerExceptions.Count.ShouldBe(2); aggrException.InnerExceptions[0].Message.ShouldBe("This exception is intentionally thrown #1!"); diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultipleHandle_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultipleHandle_Test.cs index d20692fa01..5880dd3662 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultipleHandle_Test.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultipleHandle_Test.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.EventBus.Local LocalEventBus.Subscribe>(handler); LocalEventBus.Subscribe>(handler); - await LocalEventBus.PublishAsync(new EntityCreatedEventData(new MyEntity())); + await LocalEventBus.PublishAsync(new EntityCreatedEventData(new MyEntity())).ConfigureAwait(false); handler.EntityCreatedEventCount.ShouldBe(1); handler.EntityChangedEventCount.ShouldBe(1); diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/GenericInheritanceTest.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/GenericInheritanceTest.cs index eeec26b166..316de4a396 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/GenericInheritanceTest.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/GenericInheritanceTest.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(new EntityUpdatedEventData(new Person(42))); + await LocalEventBus.PublishAsync(new EntityUpdatedEventData(new Person(42))).ConfigureAwait(false); triggeredEvent.ShouldBe(true); } @@ -39,7 +39,7 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(new EntityChangedEventData(new Student(42))); + await LocalEventBus.PublishAsync(new EntityChangedEventData(new Student(42))).ConfigureAwait(false); triggeredEvent.ShouldBe(true); } diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/InheritanceTest.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/InheritanceTest.cs index c3b1dd4283..17474be1d9 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/InheritanceTest.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/InheritanceTest.cs @@ -17,10 +17,10 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); //Should handle directly registered class - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); //Should handle directly registered class - await LocalEventBus.PublishAsync(new MyDerivedEventData(3)); //Should handle derived class too - await LocalEventBus.PublishAsync(new MyDerivedEventData(4)); //Should handle derived class too + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); //Should handle directly registered class + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); //Should handle directly registered class + await LocalEventBus.PublishAsync(new MyDerivedEventData(3)).ConfigureAwait(false); //Should handle derived class too + await LocalEventBus.PublishAsync(new MyDerivedEventData(4)).ConfigureAwait(false); //Should handle derived class too Assert.Equal(10, totalData); } @@ -37,10 +37,10 @@ namespace Volo.Abp.EventBus.Local return Task.CompletedTask; }); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); //Should not handle - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); //Should not handle - await LocalEventBus.PublishAsync(new MyDerivedEventData(3)); //Should handle - await LocalEventBus.PublishAsync(new MyDerivedEventData(4)); //Should handle + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); //Should not handle + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); //Should not handle + await LocalEventBus.PublishAsync(new MyDerivedEventData(3)).ConfigureAwait(false); //Should handle + await LocalEventBus.PublishAsync(new MyDerivedEventData(4)).ConfigureAwait(false); //Should handle Assert.Equal(7, totalData); } diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/TransientDisposableEventHandlerTest.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/TransientDisposableEventHandlerTest.cs index 5ab7ed51af..bfc731f5bf 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/TransientDisposableEventHandlerTest.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/TransientDisposableEventHandlerTest.cs @@ -10,9 +10,9 @@ namespace Volo.Abp.EventBus.Local { LocalEventBus.Subscribe(); - await LocalEventBus.PublishAsync(new MySimpleEventData(1)); - await LocalEventBus.PublishAsync(new MySimpleEventData(2)); - await LocalEventBus.PublishAsync(new MySimpleEventData(3)); + await LocalEventBus.PublishAsync(new MySimpleEventData(1)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(2)).ConfigureAwait(false); + await LocalEventBus.PublishAsync(new MySimpleEventData(3)).ConfigureAwait(false); Assert.Equal(3, MySimpleTransientEventHandler.HandleCount); Assert.Equal(3, MySimpleTransientEventHandler.DisposeCount); diff --git a/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj b/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj index 37922295f7..7cf1656de6 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj +++ b/framework/test/Volo.Abp.Features.Tests/Volo.Abp.Features.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/ClassFeatureTestService.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/ClassFeatureTestService.cs index 425f69337f..13dd19da19 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/ClassFeatureTestService.cs +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/ClassFeatureTestService.cs @@ -1,4 +1,5 @@ -using Volo.Abp.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; namespace Volo.Abp.Features { @@ -10,14 +11,14 @@ namespace Volo.Abp.Features */ [RequiresFeature("BooleanTestFeature2")] - public virtual int Feature2() + public virtual Task Feature2Async() { - return 42; + return Task.FromResult(42); } - public virtual void NoAdditionalFeature() + public virtual Task NoAdditionalFeatureAsync() { - + return Task.CompletedTask; } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureChecker_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureChecker_Tests.cs index 7ea01268a0..dc849d9b50 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureChecker_Tests.cs +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureChecker_Tests.cs @@ -20,16 +20,16 @@ namespace Volo.Abp.Features public async Task IsEnabledAsync() { //Tenant is unknown - (await _featureChecker.IsEnabledAsync("BooleanTestFeature1")).ShouldBeFalse(); + (await _featureChecker.IsEnabledAsync("BooleanTestFeature1").ConfigureAwait(false)).ShouldBeFalse(); using (_currentTenant.Change(TestFeatureStore.Tenant1Id)) { - (await _featureChecker.IsEnabledAsync("BooleanTestFeature1")).ShouldBeTrue(); + (await _featureChecker.IsEnabledAsync("BooleanTestFeature1").ConfigureAwait(false)).ShouldBeTrue(); } using (_currentTenant.Change(TestFeatureStore.Tenant2Id)) { - (await _featureChecker.IsEnabledAsync("BooleanTestFeature1")).ShouldBeFalse(); + (await _featureChecker.IsEnabledAsync("BooleanTestFeature1").ConfigureAwait(false)).ShouldBeFalse(); } } @@ -37,16 +37,16 @@ namespace Volo.Abp.Features public async Task GetOrNullAsync() { //Tenant is unknown - (await _featureChecker.GetOrNullAsync("IntegerTestFeature1")).ShouldBe("1"); + (await _featureChecker.GetOrNullAsync("IntegerTestFeature1").ConfigureAwait(false)).ShouldBe("1"); using (_currentTenant.Change(TestFeatureStore.Tenant1Id)) { - (await _featureChecker.GetOrNullAsync("IntegerTestFeature1")).ShouldBe("1"); + (await _featureChecker.GetOrNullAsync("IntegerTestFeature1").ConfigureAwait(false)).ShouldBe("1"); } using (_currentTenant.Change(TestFeatureStore.Tenant2Id)) { - (await _featureChecker.GetOrNullAsync("IntegerTestFeature1")).ShouldBe("34"); + (await _featureChecker.GetOrNullAsync("IntegerTestFeature1").ConfigureAwait(false)).ShouldBe("34"); } } } diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureInterceptor_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureInterceptor_Tests.cs index 159e2ff241..eb10664239 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureInterceptor_Tests.cs +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureInterceptor_Tests.cs @@ -27,20 +27,20 @@ namespace Volo.Abp.Features { using (_currentTenant.Change(ParseNullableGuid(tenantIdValue))) { - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - _classFeatureTestService.NoAdditionalFeature(); - }); + await _classFeatureTestService.NoAdditionalFeatureAsync().ConfigureAwait(false); + }).ConfigureAwait(false); - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - _classFeatureTestService.Feature2(); - }); + await _classFeatureTestService.Feature2Async().ConfigureAwait(false); + }).ConfigureAwait(false); await Assert.ThrowsAsync(async () => { - await _methodFeatureTestService.Feature1Async(); - }); + await _methodFeatureTestService.Feature1Async().ConfigureAwait(false); + }).ConfigureAwait(false); } } @@ -50,9 +50,9 @@ namespace Volo.Abp.Features //Features were enabled for Tenant 1 using (_currentTenant.Change(TestFeatureStore.Tenant1Id)) { - _classFeatureTestService.NoAdditionalFeature(); - _classFeatureTestService.Feature2().ShouldBe(42); - (await _methodFeatureTestService.Feature1Async()).ShouldBe(42); + await _classFeatureTestService.NoAdditionalFeatureAsync().ConfigureAwait(false); + (await _classFeatureTestService.Feature2Async().ConfigureAwait(false)).ShouldBe(42); + (await _methodFeatureTestService.Feature1Async().ConfigureAwait(false)).ShouldBe(42); } } @@ -64,7 +64,7 @@ namespace Volo.Abp.Features { using (_currentTenant.Change(ParseNullableGuid(tenantIdValue))) { - await _methodFeatureTestService.NonFeatureAsync(); + await _methodFeatureTestService.NonFeatureAsync().ConfigureAwait(false); } } diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureTestBase.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureTestBase.cs index b12aa9f526..9bde61e1c4 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureTestBase.cs +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.Features +using Volo.Abp.Testing; + +namespace Volo.Abp.Features { public class FeatureTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.FluentValidation.Tests/Volo.Abp.FluentValidation.Tests.csproj b/framework/test/Volo.Abp.FluentValidation.Tests/Volo.Abp.FluentValidation.Tests.csproj index 97ee01d8a8..7f62578e7d 100644 --- a/framework/test/Volo.Abp.FluentValidation.Tests/Volo.Abp.FluentValidation.Tests.csproj +++ b/framework/test/Volo.Abp.FluentValidation.Tests/Volo.Abp.FluentValidation.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs index 0cde05efd4..ba7a424ee7 100644 --- a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs +++ b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Threading.Tasks; using FluentValidation; using Microsoft.Extensions.DependencyInjection; @@ -5,6 +6,7 @@ using Shouldly; using Volo.Abp.Autofac; using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Volo.Abp.Validation; using Xunit; @@ -27,21 +29,6 @@ namespace Volo.Abp.FluentValidation [Fact] public async Task Should_Work_Proper_With_Right_Inputs() { - // MyStringValue should be aaa, MyStringValue2 should be bbb. MyStringValue3 should be ccc - var output = _myAppService.MyMethod(new MyMethodInput - { - MyStringValue = "aaa", - MyMethodInput2 = new MyMethodInput2 - { - MyStringValue2 = "bbb" - }, - MyMethodInput3 = new MyMethodInput3 - { - MyStringValue3 = "ccc" - } - }); - output.ShouldBe("aaabbbccc"); - var asyncOutput = await _myAppService.MyMethodAsync(new MyMethodInput { MyStringValue = "aaa", @@ -53,7 +40,7 @@ namespace Volo.Abp.FluentValidation { MyStringValue3 = "ccc" } - }); + }).ConfigureAwait(false); asyncOutput.ShouldBe("aaabbbccc"); } @@ -63,20 +50,28 @@ namespace Volo.Abp.FluentValidation { // MyStringValue should be aaa, MyStringValue2 should be bbb. MyStringValue3 should be ccc - Assert.Throws(() => _myAppService.MyMethod(new MyMethodInput - { - MyStringValue = "a", - MyMethodInput2 = new MyMethodInput2 - { - MyStringValue2 = "b" - }, - MyMethodInput3 = new MyMethodInput3 - { - MyStringValue3 = "c" - } - })); - - await Assert.ThrowsAsync(async () => await _myAppService.MyMethodAsync( + var exception = await Assert.ThrowsAsync( + async () => await _myAppService.MyMethodAsync( + new MyMethodInput + { + MyStringValue = "a", + MyMethodInput2 = new MyMethodInput2 + { + MyStringValue2 = "b" + }, + MyMethodInput3 = new MyMethodInput3 + { + MyStringValue3 = "c" + } + } + ) +.ConfigureAwait(false)).ConfigureAwait(false); + + exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyStringValue")); + exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput2.MyStringValue2")); + exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput3.MyStringValue3")); + + exception = await Assert.ThrowsAsync(async () => await _myAppService.MyMethodAsync( new MyMethodInput { MyStringValue = "a", @@ -88,16 +83,19 @@ namespace Volo.Abp.FluentValidation { MyStringValue3 = "c" } - })); + }).ConfigureAwait(false)).ConfigureAwait(false); + exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyStringValue")); + exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput2.MyStringValue2")); + exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput3.MyStringValue3")); } [Fact] - public void NotValidateMyMethod_Test() + public async Task NotValidateMyMethod_Test() { - var output = _myAppService.NotValidateMyMethod(new MyMethodInput4 + var output = await _myAppService.NotValidateMyMethod(new MyMethodInput4 { MyStringValue4 = "444" - }); + }).ConfigureAwait(false); output.ShouldBe("444"); } @@ -125,29 +123,22 @@ namespace Volo.Abp.FluentValidation public interface IMyAppService { - string MyMethod(MyMethodInput input); - Task MyMethodAsync(MyMethodInput input); - string NotValidateMyMethod(MyMethodInput4 input); + Task NotValidateMyMethod(MyMethodInput4 input); } public class MyAppService : IMyAppService, ITransientDependency { - public string MyMethod(MyMethodInput input) - { - return input.MyStringValue + input.MyMethodInput2.MyStringValue2 + input.MyMethodInput3.MyStringValue3; - } - public Task MyMethodAsync(MyMethodInput input) { return Task.FromResult(input.MyStringValue + input.MyMethodInput2.MyStringValue2 + input.MyMethodInput3.MyStringValue3); } - public string NotValidateMyMethod(MyMethodInput4 input) + public Task NotValidateMyMethod(MyMethodInput4 input) { - return input.MyStringValue4; + return Task.FromResult(input.MyStringValue4); } } diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj b/framework/test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj index 8fd7c79dc6..db0f9d45bf 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj @@ -11,7 +11,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs index cd8c92c66d..0e7b9d9163 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs @@ -4,8 +4,6 @@ namespace Volo.Abp.Http.DynamicProxying { public interface IRegularTestController { - int IncrementValue(int value); - Task IncrementValueAsync(int value); Task GetException1Async(); diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs index 2df9ad62a1..4dddcd6ce8 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using NSubstitute.Extensions; using Shouldly; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; @@ -9,6 +10,7 @@ using Volo.Abp.Http.Client; using Volo.Abp.TestApp.Application; using Volo.Abp.TestApp.Application.Dto; using Volo.Abp.TestApp.Domain; +using Volo.Abp.Validation; using Xunit; namespace Volo.Abp.Http.DynamicProxying @@ -27,9 +29,9 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task Get() { - var firstPerson = _personRepository.First(); + var firstPerson = (await _personRepository.GetListAsync()).First(); - var person = await _peopleAppService.GetAsync(firstPerson.Id); + var person = await _peopleAppService.GetAsync(firstPerson.Id).ConfigureAwait(false); person.ShouldNotBeNull(); person.Id.ShouldBe(firstPerson.Id); person.Name.ShouldBe(firstPerson.Name); @@ -38,7 +40,8 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task GetList() { - var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto()); + var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto()) + .ConfigureAwait(false); people.TotalCount.ShouldBeGreaterThan(0); people.Items.Count.ShouldBe((int) people.TotalCount); } @@ -46,11 +49,11 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task Delete() { - var firstPerson = _personRepository.First(); + var firstPerson = (await _personRepository.GetListAsync()).First(); - await _peopleAppService.DeleteAsync(firstPerson.Id); + await _peopleAppService.DeleteAsync(firstPerson.Id).ConfigureAwait(false); - firstPerson = _personRepository.FirstOrDefault(p => p.Id == firstPerson.Id); + firstPerson = (await _personRepository.GetListAsync()).FirstOrDefault(p => p.Id == firstPerson.Id); firstPerson.ShouldBeNull(); } @@ -64,21 +67,34 @@ namespace Volo.Abp.Http.DynamicProxying Name = uniquePersonName, Age = 42 } - ); + ).ConfigureAwait(false); person.ShouldNotBeNull(); person.Id.ShouldNotBe(Guid.Empty); person.Name.ShouldBe(uniquePersonName); - var personInDb = _personRepository.FirstOrDefault(p => p.Name == uniquePersonName); + var personInDb = (await _personRepository.GetListAsync()).FirstOrDefault(p => p.Name == uniquePersonName); personInDb.ShouldNotBeNull(); personInDb.Id.ShouldBe(person.Id); } - + + [Fact] + public async Task Create_Validate_Exception() + { + await Assert.ThrowsAsync(async () => + { + var person = await _peopleAppService.CreateAsync(new PersonDto + { + Age = 42 + } + ).ConfigureAwait(false); + }).ConfigureAwait(false); + } + [Fact] public async Task Update() { - var firstPerson = _personRepository.First(); + var firstPerson = (await _personRepository.GetListAsync()).First(); var uniquePersonName = Guid.NewGuid().ToString(); var person = await _peopleAppService.UpdateAsync( @@ -89,14 +105,14 @@ namespace Volo.Abp.Http.DynamicProxying Name = uniquePersonName, Age = firstPerson.Age } - ); + ).ConfigureAwait(false); person.ShouldNotBeNull(); person.Id.ShouldBe(firstPerson.Id); person.Name.ShouldBe(uniquePersonName); person.Age.ShouldBe(firstPerson.Age); - var personInDb = _personRepository.FirstOrDefault(p => p.Id == firstPerson.Id); + var personInDb = (await _personRepository.GetListAsync()).FirstOrDefault(p => p.Id == firstPerson.Id); personInDb.ShouldNotBeNull(); personInDb.Id.ShouldBe(person.Id); personInDb.Name.ShouldBe(person.Name); @@ -108,8 +124,8 @@ namespace Volo.Abp.Http.DynamicProxying { await Assert.ThrowsAnyAsync(async () => { - await _peopleAppService.GetWithAuthorized(); - }); + await _peopleAppService.GetWithAuthorized().ConfigureAwait(false); + }).ConfigureAwait(false); } [Fact] @@ -128,11 +144,11 @@ namespace Volo.Abp.Http.DynamicProxying } } } - ); + ).ConfigureAwait(false); result.Value1.ShouldBe("value one"); result.Inner1.Value2.ShouldBe("value two"); result.Inner1.Inner2.Value3.ShouldBe("value three"); } } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs index 34f8c5820d..717b62701e 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs @@ -11,13 +11,6 @@ namespace Volo.Abp.Http.DynamicProxying //[ApiExplorerSettings(IgnoreApi = false)] //alternative public class RegularTestController : AbpController, IRegularTestController { - [HttpGet] - [Route("increment/{value}")] //full URL: .../api/regular-test-controller/increment/{value} - public int IncrementValue(int value) - { - return value + 1; - } - [HttpGet] [Route("increment")] public Task IncrementValueAsync(int value) diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs index 22d9354624..fdf422d585 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs @@ -17,50 +17,44 @@ namespace Volo.Abp.Http.DynamicProxying _controller = ServiceProvider.GetRequiredService(); } - [Fact] - public void IncrementValue() - { - _controller.IncrementValue(42).ShouldBe(43); - } - [Fact] public async Task IncrementValueAsync() { - (await _controller.IncrementValueAsync(42)).ShouldBe(43); + (await _controller.IncrementValueAsync(42).ConfigureAwait(false)).ShouldBe(43); } [Fact] public async Task GetException1Async() { - var exception = await Assert.ThrowsAsync(async () => await _controller.GetException1Async()); + var exception = await Assert.ThrowsAsync(async () => await _controller.GetException1Async().ConfigureAwait(false)).ConfigureAwait(false); exception.Error.Message.ShouldBe("This is an error message!"); } [Fact] public async Task PostValueWithHeaderAndQueryStringAsync() { - var result = await _controller.PostValueWithHeaderAndQueryStringAsync("myheader", "myqs"); + var result = await _controller.PostValueWithHeaderAndQueryStringAsync("myheader", "myqs").ConfigureAwait(false); result.ShouldBe("myheader#myqs"); } [Fact] public async Task PostValueWithBodyAsync() { - var result = await _controller.PostValueWithBodyAsync("mybody"); + var result = await _controller.PostValueWithBodyAsync("mybody").ConfigureAwait(false); result.ShouldBe("mybody"); } [Fact] public async Task PutValueWithBodyAsync() { - var result = await _controller.PutValueWithBodyAsync("mybody"); + var result = await _controller.PutValueWithBodyAsync("mybody").ConfigureAwait(false); result.ShouldBe("mybody"); } [Fact] public async Task PostObjectWithBodyAsync() { - var result = await _controller.PostObjectWithBodyAsync(new Car{Year = 1976, Model = "Ford"}); + var result = await _controller.PostObjectWithBodyAsync(new Car { Year = 1976, Model = "Ford" }).ConfigureAwait(false); result.Year.ShouldBe(1976); result.Model.ShouldBe("Ford"); } @@ -68,7 +62,7 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task PostObjectWithQueryAsync() { - var result = await _controller.PostObjectWithQueryAsync(new Car{Year = 1976, Model = "Ford"}); + var result = await _controller.PostObjectWithQueryAsync(new Car { Year = 1976, Model = "Ford" }).ConfigureAwait(false); result.Year.ShouldBe(1976); result.Model.ShouldBe("Ford"); } @@ -76,7 +70,7 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task GetObjectWithUrlAsync() { - var result = await _controller.GetObjectWithUrlAsync(new Car{Year = 1976, Model = "Ford"}); + var result = await _controller.GetObjectWithUrlAsync(new Car { Year = 1976, Model = "Ford" }).ConfigureAwait(false); result.Year.ShouldBe(1976); result.Model.ShouldBe("Ford"); } @@ -84,7 +78,7 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task GetObjectandIdAsync() { - var result = await _controller.GetObjectandIdAsync(42, new Car{Year = 1976, Model = "Ford"}); + var result = await _controller.GetObjectandIdAsync(42, new Car { Year = 1976, Model = "Ford" }).ConfigureAwait(false); result.Year.ShouldBe(42); result.Model.ShouldBe("Ford"); } @@ -92,7 +86,7 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task GetObjectAndIdWithQueryAsync() { - var result = await _controller.GetObjectAndIdWithQueryAsync(42, new Car{Year = 1976, Model = "Ford"}); + var result = await _controller.GetObjectAndIdWithQueryAsync(42, new Car { Year = 1976, Model = "Ford" }).ConfigureAwait(false); result.Year.ShouldBe(42); result.Model.ShouldBe("Ford"); } @@ -100,28 +94,28 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task PatchValueWithBodyAsync() { - var result = await _controller.PatchValueWithBodyAsync("mybody"); + var result = await _controller.PatchValueWithBodyAsync("mybody").ConfigureAwait(false); result.ShouldBe("mybody"); } [Fact] public async Task PutValueWithHeaderAndQueryStringAsync() { - var result = await _controller.PutValueWithHeaderAndQueryStringAsync("myheader", "myqs"); + var result = await _controller.PutValueWithHeaderAndQueryStringAsync("myheader", "myqs").ConfigureAwait(false); result.ShouldBe("myheader#myqs"); } [Fact] public async Task PatchValueWithHeaderAndQueryStringAsync() { - var result = await _controller.PatchValueWithHeaderAndQueryStringAsync("myheader", "myqs"); + var result = await _controller.PatchValueWithHeaderAndQueryStringAsync("myheader", "myqs").ConfigureAwait(false); result.ShouldBe("myheader#myqs"); } [Fact] public async Task DeleteByIdAsync() { - (await _controller.DeleteByIdAsync(42)).ShouldBe(43); + (await _controller.DeleteByIdAsync(42).ConfigureAwait(false)).ShouldBe(43); } } diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj index d427434983..8f803774b2 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs index c59dc0d9e1..bf11262a99 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs @@ -1,6 +1,7 @@ using System; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Ldap diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs index 01906c8f18..3e83d26543 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs @@ -1,6 +1,7 @@ using System; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Ldap diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo.Abp.Localization.Tests.csproj b/framework/test/Volo.Abp.Localization.Tests/Volo.Abp.Localization.Tests.csproj index db81c344da..b3afc78948 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo.Abp.Localization.Tests.csproj +++ b/framework/test/Volo.Abp.Localization.Tests/Volo.Abp.Localization.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index 24433824a3..5608ca0a80 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -7,6 +7,7 @@ using Volo.Abp.Localization.TestResources.Base.CountryNames; using Volo.Abp.Localization.TestResources.Base.Validation; using Volo.Abp.Localization.TestResources.Source; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Volo.Abp.VirtualFileSystem; using Xunit; @@ -50,24 +51,24 @@ namespace Volo.Abp.Localization [Fact] public void Should_Get_Localized_Text_If_Defined_In_Current_Culture() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { _localizer["Car"].Value.ShouldBe("Car"); _localizer["CarPlural"].Value.ShouldBe("Cars"); } - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { _localizer["Car"].Value.ShouldBe("Araba"); _localizer["CarPlural"].Value.ShouldBe("Araba"); } - using (AbpCultureHelper.Use("it")) + using (CultureHelper.Use("it")) { _localizer["Car"].Value.ShouldBe("Auto"); } - using (AbpCultureHelper.Use("es")) + using (CultureHelper.Use("es")) { _localizer["Car"].Value.ShouldBe("Auto"); } @@ -77,22 +78,22 @@ namespace Volo.Abp.Localization [Fact] public void Should_Get_Extension_Texts() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { _localizer["SeeYou"].Value.ShouldBe("See you"); } - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { _localizer["SeeYou"].Value.ShouldBe("See you"); //Not defined in tr, getting from default lang } - using (AbpCultureHelper.Use("it")) + using (CultureHelper.Use("it")) { _localizer["SeeYou"].Value.ShouldBe("Ci vediamo"); } - using (AbpCultureHelper.Use("es")) + using (CultureHelper.Use("es")) { _localizer["SeeYou"].Value.ShouldBe("Nos vemos"); } @@ -102,7 +103,7 @@ namespace Volo.Abp.Localization [Fact] public void Should_Get_From_Inherited_Texts() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { _localizer["USA"].Value.ShouldBe("United States of America"); //Inherited from CountryNames/en.json _localizer["ThisFieldIsRequired"].Value.ShouldBe("This field is required"); //Inherited from Validation/en.json @@ -110,14 +111,14 @@ namespace Volo.Abp.Localization _localizer.GetAllStrings().ShouldContain(ls => ls.Name == "USA"); } - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { _localizer["USA"].Value.ShouldBe("Amerika Birleşik Devletleri"); //Inherited from CountryNames/tr.json } - using (AbpCultureHelper.Use("es")) + using (CultureHelper.Use("es")) { - _localizer["USA"].Value.ShouldBe("Estados unidos de America"); //Inherited from CountryNames/es.json + _localizer["USA"].Value.ShouldBe("Estados unidos de América"); //Inherited from CountryNames/es.json _localizer["ThisFieldIsRequired"].Value.ShouldBe("El campo no puede estar vacío"); //Inherited from Validation/es.json _localizer.GetAllStrings().ShouldContain(ls => ls.Name == "USA"); @@ -128,12 +129,12 @@ namespace Volo.Abp.Localization [Fact] public void Should_Override_Inherited_Text() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { _localizer["MaxLenghtErrorMessage", 42].Value.ShouldBe("This field's length can be maximum of '42' chars"); //Overriden in Source/en.json } - using (AbpCultureHelper.Use("es")) + using (CultureHelper.Use("es")) { _localizer["MaxLenghtErrorMessage", 42].Value.ShouldBe("El campo puede tener un máximo de '42' caracteres"); //Overriden in Source/es.json } @@ -144,21 +145,38 @@ namespace Volo.Abp.Localization [Fact] public void Should_Get_Localized_Text_If_Defined_In_Requested_Culture() { - _localizer.WithCulture(CultureInfo.GetCultureInfo("en"))["Car"].Value.ShouldBe("Car"); - _localizer.WithCulture(CultureInfo.GetCultureInfo("en"))["CarPlural"].Value.ShouldBe("Cars"); - - _localizer.WithCulture(CultureInfo.GetCultureInfo("tr"))["Car"].Value.ShouldBe("Araba"); - _localizer.WithCulture(CultureInfo.GetCultureInfo("tr"))["CarPlural"].Value.ShouldBe("Araba"); + using (CultureHelper.Use(CultureInfo.GetCultureInfo("en"))) + { + _localizer["Car"].Value.ShouldBe("Car"); + } + using (CultureHelper.Use(CultureInfo.GetCultureInfo("en"))) + { + _localizer["CarPlural"].Value.ShouldBe("Cars"); + } - _localizer.WithCulture(CultureInfo.GetCultureInfo("es"))["Car"].Value.ShouldBe("Auto"); - _localizer.WithCulture(CultureInfo.GetCultureInfo("es"))["CarPlural"].Value.ShouldBe("Autos"); + using (CultureHelper.Use(CultureInfo.GetCultureInfo("tr"))) + { + _localizer["Car"].Value.ShouldBe("Araba"); + } + using (CultureHelper.Use(CultureInfo.GetCultureInfo("tr"))) + { + _localizer["CarPlural"].Value.ShouldBe("Araba"); + } + using (CultureHelper.Use(CultureInfo.GetCultureInfo("es"))) + { + _localizer["Car"].Value.ShouldBe("Auto"); + } + using (CultureHelper.Use(CultureInfo.GetCultureInfo("es"))) + { + _localizer["CarPlural"].Value.ShouldBe("Autos"); + } } [Fact] public void GetAllStrings_With_Parents() { - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { var localizedStrings = _localizer.GetAllStrings(true).ToList(); @@ -175,13 +193,13 @@ namespace Volo.Abp.Localization ); } - using (AbpCultureHelper.Use("es")) + using (CultureHelper.Use("es")) { var localizedStrings = _localizer.GetAllStrings(true).ToList(); localizedStrings.ShouldContain( ls => ls.Name == "FortyTwo" && - ls.Value == "Cuarenta y dos" && + ls.Value == "Curenta y dos" && ls.ResourceNotFound == false ); @@ -197,7 +215,7 @@ namespace Volo.Abp.Localization [Fact] public void GetAllStrings_Without_Parents() { - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { var localizedStrings = _localizer.GetAllStrings(false).ToList(); @@ -212,12 +230,12 @@ namespace Volo.Abp.Localization ); } - using (AbpCultureHelper.Use("es")) + using (CultureHelper.Use("es")) { var localizedStrings = _localizer.GetAllStrings(false).ToList(); localizedStrings.ShouldNotContain( - ls => ls.Name == "FortyTwo" + ls => ls.Name == "FortyThree" ); localizedStrings.ShouldContain( @@ -232,7 +250,7 @@ namespace Volo.Abp.Localization [Fact] public void GetAllStrings_With_Inheritance() { - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { var localizedStrings = _localizer .GetAllStrings(true, includeBaseLocalizers: true) @@ -261,7 +279,7 @@ namespace Volo.Abp.Localization [Fact] public void GetAllStrings_Without_Inheritance() { - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { var localizedStrings = _localizer .GetAllStrings(true, includeBaseLocalizers: false) diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TemplateLocalizer_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TemplateLocalizer_Tests.cs index 3ba7a2937b..4b31554637 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TemplateLocalizer_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TemplateLocalizer_Tests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Localization; using Shouldly; using Volo.Abp.Localization.TestResources.Source; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Volo.Abp.VirtualFileSystem; using Xunit; @@ -22,7 +23,7 @@ namespace Volo.Abp.Localization [Fact] public void Should_Localize() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { _templateLocalizer.Localize(_testResource, "

    {{#L:CarPlural}} {{#L:Universe}}

    ") .ShouldBe("

    Cars Universe

    "); @@ -32,7 +33,7 @@ namespace Volo.Abp.Localization [Fact] public void Should_Work_Even_If_No_Text_To_Localize() { - using (AbpCultureHelper.Use("en")) + using (CultureHelper.Use("en")) { _templateLocalizer.Localize(_testResource, "

    test

    ") .ShouldBe("

    test

    "); diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/zh-Hant.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/zh-Hant.json new file mode 100644 index 0000000000..8ce2ad288a --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "USA": "美國", + "Brazil": "巴西" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hant.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hant.json new file mode 100644 index 0000000000..1c0f506d34 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "ThisFieldIsRequired": "此欄位為必填欄位", + "MaxLenghtErrorMessage": "此欄位最多可包含'{0}'個字元" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hant.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hant.json new file mode 100644 index 0000000000..1aeb9cdf6f --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hant.json @@ -0,0 +1,11 @@ +{ + "culture": "zh-Hant", + "texts": { + "Hello {0}.": "您好 {0}.", + "Car": "汽車", + "CarPlural": "汽車", + "MaxLenghtErrorMessage": "此欄位的長度最多'{0}'個字元", + "Universe": "宇宙", + "FortyTwo": "四十二" + } +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/zh-Hant.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/zh-Hant.json new file mode 100644 index 0000000000..c779d77a25 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hant", + "texts": { + "SeeYou": "再會" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj b/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj index ff98717569..b8f417d384 100644 --- a/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj +++ b/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj @@ -11,7 +11,7 @@ - +
    \ No newline at end of file diff --git a/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs index de9acb3a0e..e323b1150e 100644 --- a/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs +++ b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using NSubstitute; using Volo.Abp.BackgroundJobs; using Volo.Abp.Emailing.Smtp; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.MailKit @@ -17,7 +18,7 @@ namespace Volo.Abp.MailKit var mailMessage = new MailMessage("from_mail_address@asd.com", "to_mail_address@asd.com", "subject", "body") { IsBodyHtml = true }; - await mailSender.SendAsync(mailMessage); + await mailSender.SendAsync(mailMessage).ConfigureAwait(false); } //[Fact] @@ -29,7 +30,7 @@ namespace Volo.Abp.MailKit IsBodyHtml = true }; - await mailSender.SendAsync(mailMessage); + await mailSender.SendAsync(mailMessage).ConfigureAwait(false); } private static MailKitSmtpEmailSender CreateMailKitEmailSender() diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo.Abp.MemoryDb.Tests.csproj b/framework/test/Volo.Abp.MemoryDb.Tests/Volo.Abp.MemoryDb.Tests.csproj index a1991f0dd4..ad478b062a 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo.Abp.MemoryDb.Tests.csproj +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo.Abp.MemoryDb.Tests.csproj @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/MemoryDbTestBase.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/MemoryDbTestBase.cs index 8d818bb32c..c539f66ca1 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/MemoryDbTestBase.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/MemoryDbTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.MemoryDb +using Volo.Abp.Testing; + +namespace Volo.Abp.MemoryDb { public abstract class MemoryDbTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs index b6d43dc875..c83a28871f 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.TestApp.MemoryDb public async Task> GetPeopleInTheCityAsync(string cityName) { - var city = await FindByNameAsync(cityName); + var city = await FindByNameAsync(cityName).ConfigureAwait(false); return Database.Collection().Where(p => p.CityId == city.Id).ToList(); } diff --git a/framework/test/Volo.Abp.Minify.Tests/Volo.Abp.Minify.Tests.csproj b/framework/test/Volo.Abp.Minify.Tests/Volo.Abp.Minify.Tests.csproj index d4d2e1503a..5d07377aa1 100644 --- a/framework/test/Volo.Abp.Minify.Tests/Volo.Abp.Minify.Tests.csproj +++ b/framework/test/Volo.Abp.Minify.Tests/Volo.Abp.Minify.Tests.csproj @@ -10,7 +10,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/CssMinifier_Tests.cs b/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/CssMinifier_Tests.cs index c71be3450b..59bc8cd425 100644 --- a/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/CssMinifier_Tests.cs +++ b/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/CssMinifier_Tests.cs @@ -1,5 +1,6 @@ using Shouldly; using Volo.Abp.Minify.Styles; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Minify.NUglify diff --git a/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/HtmlMinifier_Tests.cs b/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/HtmlMinifier_Tests.cs index 88da207d0c..bba7707be7 100644 --- a/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/HtmlMinifier_Tests.cs +++ b/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/HtmlMinifier_Tests.cs @@ -1,5 +1,6 @@ using Shouldly; using Volo.Abp.Minify.Html; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Minify.NUglify diff --git a/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/JavascriptMinifier_Tests.cs b/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/JavascriptMinifier_Tests.cs index 7ebcd65fc3..6526d0b483 100644 --- a/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/JavascriptMinifier_Tests.cs +++ b/framework/test/Volo.Abp.Minify.Tests/Volo/Abp/Minify/NUglify/JavascriptMinifier_Tests.cs @@ -1,5 +1,6 @@ using Shouldly; using Volo.Abp.Minify.Scripts; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Minify.NUglify diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj b/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj index ae65b55f85..cc1cb52a96 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj @@ -16,7 +16,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbTestBase.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbTestBase.cs index 22cae9b7d6..53e101647a 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbTestBase.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbTestBase.cs @@ -1,3 +1,5 @@ +using Volo.Abp.Testing; + namespace Volo.Abp.MongoDB { public abstract class MongoDbTestBase : AbpIntegratedTest diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs index 72774be545..7458f85417 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs @@ -12,24 +12,27 @@ namespace Volo.Abp.MongoDB.Repositories public class Repository_Basic_Tests : Repository_Basic_Tests { [Fact] - public void Linq_Queries() + public async Task Linq_Queries() { - PersonRepository.FirstOrDefault(p => p.Name == "Douglas").ShouldNotBeNull(); - - PersonRepository.Count().ShouldBeGreaterThan(0); + await WithUnitOfWorkAsync(() => + { + PersonRepository.FirstOrDefault(p => p.Name == "Douglas").ShouldNotBeNull(); + PersonRepository.Count().ShouldBeGreaterThan(0); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] public async Task UpdateAsync() { - var person = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + var person = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); person.ChangeName("Douglas-Updated"); person.Phones.Add(new Phone(person.Id, "6667778899", PhoneType.Office)); - await PersonRepository.UpdateAsync(person); + await PersonRepository.UpdateAsync(person).ConfigureAwait(false); - person = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + person = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); person.ShouldNotBeNull(); person.Name.ShouldBe("Douglas-Updated"); person.Phones.Count.ShouldBe(3); @@ -42,9 +45,9 @@ namespace Volo.Abp.MongoDB.Repositories var person = new Person(Guid.NewGuid(), "New Person", 35); person.Phones.Add(new Phone(person.Id, "1234567890")); - await PersonRepository.InsertAsync(person); + await PersonRepository.InsertAsync(person).ConfigureAwait(false); - person = await PersonRepository.FindAsync(person.Id); + person = await PersonRepository.FindAsync(person.Id).ConfigureAwait(false); person.ShouldNotBeNull(); person.Name.ShouldBe("New Person"); person.Phones.Count.ShouldBe(1); diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests_With_Int_Pk.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests_With_Int_Pk.cs index 58914e8e50..c5885dfb4d 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests_With_Int_Pk.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests_With_Int_Pk.cs @@ -1,4 +1,5 @@ -using Volo.Abp.TestApp.Testing; +using System.Threading.Tasks; +using Volo.Abp.TestApp.Testing; using Xunit; namespace Volo.Abp.MongoDB.Repositories @@ -6,9 +7,9 @@ namespace Volo.Abp.MongoDB.Repositories public class Repository_Basic_Tests_With_Int_Pk : Repository_Basic_Tests_With_Int_Pk { [Fact(Skip = "Int PKs are not working for MongoDb")] - public override void Get() + public override Task Get() { - + return Task.CompletedTask; } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs index bb31883010..27381a14da 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs @@ -19,13 +19,13 @@ namespace Volo.Abp.TestApp.MongoDB public async Task FindByNameAsync(string name) { - return await (await Collection.FindAsync(c => c.Name == name)).FirstOrDefaultAsync(); + return await (await Collection.FindAsync(c => c.Name == name).ConfigureAwait(false)).FirstOrDefaultAsync().ConfigureAwait(false); } public async Task> GetPeopleInTheCityAsync(string cityName) { - var city = await FindByNameAsync(cityName); - return await DbContext.People.AsQueryable().Where(p => p.CityId == city.Id).ToListAsync(); + var city = await FindByNameAsync(cityName).ConfigureAwait(false); + return await DbContext.People.AsQueryable().Where(p => p.CityId == city.Id).ToListAsync().ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.MultiTenancy.Tests/Volo.Abp.MultiTenancy.Tests.csproj b/framework/test/Volo.Abp.MultiTenancy.Tests/Volo.Abp.MultiTenancy.Tests.csproj index c29e447d5a..808b58409e 100644 --- a/framework/test/Volo.Abp.MultiTenancy.Tests/Volo.Abp.MultiTenancy.Tests.csproj +++ b/framework/test/Volo.Abp.MultiTenancy.Tests/Volo.Abp.MultiTenancy.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenancyTestBase.cs b/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenancyTestBase.cs index 7480ae01c2..a0b2d663bc 100644 --- a/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenancyTestBase.cs +++ b/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/MultiTenancy/MultiTenancyTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.MultiTenancy +using Volo.Abp.Testing; + +namespace Volo.Abp.MultiTenancy { public class MultiTenancyTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.ObjectMapping.Tests/Volo.Abp.ObjectMapping.Tests.csproj b/framework/test/Volo.Abp.ObjectMapping.Tests/Volo.Abp.ObjectMapping.Tests.csproj index a135aea89d..a77a4e3301 100644 --- a/framework/test/Volo.Abp.ObjectMapping.Tests/Volo.Abp.ObjectMapping.Tests.csproj +++ b/framework/test/Volo.Abp.ObjectMapping.Tests/Volo.Abp.ObjectMapping.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/AbpObjectMappingTestBase.cs b/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/AbpObjectMappingTestBase.cs index 9ba65b5a10..334bb99669 100644 --- a/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/AbpObjectMappingTestBase.cs +++ b/framework/test/Volo.Abp.ObjectMapping.Tests/Volo/Abp/ObjectMapping/AbpObjectMappingTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.ObjectMapping +using Volo.Abp.Testing; + +namespace Volo.Abp.ObjectMapping { public abstract class AbpObjectMappingTestBase : AbpIntegratedTest { diff --git a/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj b/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj index d757747ab3..7688e0c040 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj +++ b/framework/test/Volo.Abp.Security.Tests/Volo.Abp.Security.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Encryption/StringEncryptionService_Tests.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Encryption/StringEncryptionService_Tests.cs index 455e0863bb..53127bbe76 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Encryption/StringEncryptionService_Tests.cs +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Encryption/StringEncryptionService_Tests.cs @@ -1,4 +1,5 @@ using Shouldly; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Security.Encryption diff --git a/framework/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj b/framework/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj index eacec7ce44..c973b4fcd1 100644 --- a/framework/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj +++ b/framework/test/Volo.Abp.Serialization.Tests/Volo.Abp.Serialization.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs b/framework/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs index e2519a89d3..59dc8ce6c8 100644 --- a/framework/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs +++ b/framework/test/Volo.Abp.Serialization.Tests/Volo/Abp/Serialization/ObjectSerializer_Tests.cs @@ -1,5 +1,6 @@ using Shouldly; using Volo.Abp.Serialization.Objects; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Serialization diff --git a/framework/test/Volo.Abp.Settings.Tests/Volo.Abp.Settings.Tests.csproj b/framework/test/Volo.Abp.Settings.Tests/Volo.Abp.Settings.Tests.csproj index 11656d5a8e..183b0b6c81 100644 --- a/framework/test/Volo.Abp.Settings.Tests/Volo.Abp.Settings.Tests.csproj +++ b/framework/test/Volo.Abp.Settings.Tests/Volo.Abp.Settings.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingProvider_Tests.cs b/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingProvider_Tests.cs index c3c22f76f9..47df3f6db1 100644 --- a/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingProvider_Tests.cs +++ b/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingProvider_Tests.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Shouldly; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Settings @@ -21,14 +22,14 @@ namespace Volo.Abp.Settings [Fact] public async Task Should_Get_Null_If_No_Value_Provided_And_No_Default_Value() { - (await _settingProvider.GetOrNullAsync(TestSettingNames.TestSettingWithoutDefaultValue)) + (await _settingProvider.GetOrNullAsync(TestSettingNames.TestSettingWithoutDefaultValue).ConfigureAwait(false)) .ShouldBeNull(); } [Fact] public async Task Should_Get_Default_Value_If_No_Value_Provided_And_There_Is_A_Default_Value() { - (await _settingProvider.GetOrNullAsync(TestSettingNames.TestSettingWithDefaultValue)) + (await _settingProvider.GetOrNullAsync(TestSettingNames.TestSettingWithDefaultValue).ConfigureAwait(false)) .ShouldBe("default-value"); } } diff --git a/framework/test/Volo.Abp.Specifications.Tests/Volo.Abp.Specifications.Tests.csproj b/framework/test/Volo.Abp.Specifications.Tests/Volo.Abp.Specifications.Tests.csproj index 09d2b84dfe..6b836d2efe 100644 --- a/framework/test/Volo.Abp.Specifications.Tests/Volo.Abp.Specifications.Tests.csproj +++ b/framework/test/Volo.Abp.Specifications.Tests/Volo.Abp.Specifications.Tests.csproj @@ -10,7 +10,7 @@ - + \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp.Tests/Volo.Abp.TestApp.Tests.csproj b/framework/test/Volo.Abp.TestApp.Tests/Volo.Abp.TestApp.Tests.csproj index f5cc2747a9..1d54a745ab 100644 --- a/framework/test/Volo.Abp.TestApp.Tests/Volo.Abp.TestApp.Tests.csproj +++ b/framework/test/Volo.Abp.TestApp.Tests/Volo.Abp.TestApp.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/Application/PersonAppService_Tests.cs b/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/Application/PersonAppService_Tests.cs index 0da6d4c8dc..47fa69d64f 100644 --- a/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/Application/PersonAppService_Tests.cs +++ b/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/Application/PersonAppService_Tests.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.TestApp.Application public PersonAppService_Tests() { - _peopleAppService = ServiceProvider.GetRequiredService(); + _peopleAppService = ServiceProvider.GetRequiredService(); } protected override void AfterAddApplication(IServiceCollection services) @@ -31,17 +31,20 @@ namespace Volo.Abp.TestApp.Application [Fact] public async Task GetList() { - var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto()); + var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto()) + .ConfigureAwait(false); people.Items.Count.ShouldBeGreaterThan(0); } [Fact] public async Task Create() { - var personDto = await _peopleAppService.CreateAsync(new PersonDto()); + var uniquePersonName = Guid.NewGuid().ToString(); + var personDto = await _peopleAppService.CreateAsync(new PersonDto {Name = uniquePersonName}) + .ConfigureAwait(false); var repository = ServiceProvider.GetService>(); - var person = await repository.FindAsync(personDto.Id); + var person = await repository.FindAsync(personDto.Id).ConfigureAwait(false); person.ShouldNotBeNull(); person.TenantId.ShouldBeNull(); @@ -52,10 +55,12 @@ namespace Volo.Abp.TestApp.Application { _fakeCurrentTenant.Id.Returns(TestDataBuilder.TenantId1); - var personDto = await _peopleAppService.CreateAsync(new PersonDto()); + var uniquePersonName = Guid.NewGuid().ToString(); + var personDto = await _peopleAppService.CreateAsync(new PersonDto {Name = uniquePersonName}) + .ConfigureAwait(false); var repository = ServiceProvider.GetService>(); - var person = await repository.FindAsync(personDto.Id); + var person = await repository.FindAsync(personDto.Id).ConfigureAwait(false); person.ShouldNotBeNull(); person.TenantId.ShouldNotBeNull(); @@ -63,4 +68,4 @@ namespace Volo.Abp.TestApp.Application person.TenantId.ShouldBe(TestDataBuilder.TenantId1); } } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/TestAppTestBase.cs b/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/TestAppTestBase.cs index 589b42a21c..2903ec905a 100644 --- a/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/TestAppTestBase.cs +++ b/framework/test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/TestAppTestBase.cs @@ -1,3 +1,5 @@ +using Volo.Abp.Testing; + namespace Volo.Abp.TestApp { public class TestAppTestBase : AbpIntegratedTest diff --git a/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj b/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj index 63adeac3d2..522d166014 100644 --- a/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj +++ b/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/Dto/PersonDto.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/Dto/PersonDto.cs index b878b4f9c4..88ed3452af 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/Dto/PersonDto.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/Dto/PersonDto.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; using Volo.Abp.Application.Dtos; using Volo.Abp.MultiTenancy; @@ -6,6 +7,7 @@ namespace Volo.Abp.TestApp.Application.Dto { public class PersonDto : EntityDto, IMultiTenant { + [Required] public string Name { get; set; } public int Age { get; set; } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs index afe0f536d4..6d5c2136f3 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs @@ -13,7 +13,7 @@ namespace Volo.Abp.TestApp.Application { public class PeopleAppService : CrudAppService, IPeopleAppService { - public PeopleAppService(IRepository repository) + public PeopleAppService(IRepository repository) : base(repository) { @@ -21,7 +21,7 @@ namespace Volo.Abp.TestApp.Application public async Task> GetPhones(Guid id, GetPersonPhonesFilter filter) { - var phones = (await GetEntityByIdAsync(id)).Phones + var phones = (await GetEntityByIdAsync(id).ConfigureAwait(false)).Phones .WhereIf(filter.Type.HasValue, p => p.Type == filter.Type) .ToList(); @@ -32,19 +32,19 @@ namespace Volo.Abp.TestApp.Application public async Task AddPhone(Guid id, PhoneDto phoneDto) { - var person = await GetEntityByIdAsync(id); + var person = await GetEntityByIdAsync(id).ConfigureAwait(false); var phone = new Phone(person.Id, phoneDto.Number, phoneDto.Type); person.Phones.Add(phone); - Repository.Update(person); + await Repository.UpdateAsync(person).ConfigureAwait(false); return ObjectMapper.Map(phone); } public async Task RemovePhone(Guid id, string number) { - var person = await GetEntityByIdAsync(id); + var person = await GetEntityByIdAsync(id).ConfigureAwait(false); person.Phones.RemoveAll(p => p.Number == number); - Repository.Update(person); + await Repository.UpdateAsync(person).ConfigureAwait(false); } [Authorize] diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs index b9aef1ca2e..683c99d417 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs @@ -6,6 +6,7 @@ using Volo.Abp.TestApp.Domain; using Volo.Abp.AutoMapper; using Volo.Abp.EventBus.Distributed; using Volo.Abp.TestApp.Application.Dto; +using Volo.Abp.Threading; namespace Volo.Abp.TestApp { @@ -54,9 +55,9 @@ namespace Volo.Abp.TestApp { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestDataBuilder.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestDataBuilder.cs index 8900d8cfdf..7e2be35de0 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestDataBuilder.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestDataBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.TestApp.Domain; @@ -29,53 +30,53 @@ namespace Volo.Abp.TestApp _entityWithIntPksRepository = entityWithIntPksRepository; } - public void Build() + public async Task BuildAsync() { - AddCities(); - AddPeople(); - AddEntitiesWithPks(); + await AddCities().ConfigureAwait(false); + await AddPeople().ConfigureAwait(false); + await AddEntitiesWithPks().ConfigureAwait(false); } - private void AddCities() + private async Task AddCities() { var istanbul = new City(IstanbulCityId, "Istanbul"); istanbul.Districts.Add(new District(istanbul.Id, "Bakirkoy", 1283999)); istanbul.Districts.Add(new District(istanbul.Id, "Mecidiyeköy", 2222321)); istanbul.Districts.Add(new District(istanbul.Id, "Uskudar", 726172)); - _cityRepository.Insert(new City(Guid.NewGuid(), "Tokyo")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Madrid")); - _cityRepository.Insert(new City(LondonCityId, "London") {ExtraProperties = { { "Population", 10_470_000 } } }); - _cityRepository.Insert(istanbul); - _cityRepository.Insert(new City(Guid.NewGuid(), "Paris")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Washington")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Sao Paulo")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Berlin")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Amsterdam")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Beijing")); - _cityRepository.Insert(new City(Guid.NewGuid(), "Rome")); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Tokyo")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Madrid")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(LondonCityId, "London") { ExtraProperties = { { "Population", 10_470_000 } } }).ConfigureAwait(false); + await _cityRepository.InsertAsync(istanbul).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Paris")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Washington")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Sao Paulo")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Berlin")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Amsterdam")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Beijing")).ConfigureAwait(false); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), "Rome")).ConfigureAwait(false); } - private void AddPeople() + private async Task AddPeople() { var douglas = new Person(UserDouglasId, "Douglas", 42, cityId: LondonCityId); douglas.Phones.Add(new Phone(douglas.Id, "123456789")); douglas.Phones.Add(new Phone(douglas.Id, "123456780", PhoneType.Home)); - _personRepository.Insert(douglas); + await _personRepository.InsertAsync(douglas).ConfigureAwait(false); - _personRepository.Insert(new Person(UserJohnDeletedId, "John-Deleted", 33) { IsDeleted = true }); + await _personRepository.InsertAsync(new Person(UserJohnDeletedId, "John-Deleted", 33) { IsDeleted = true }).ConfigureAwait(false); var tenant1Person1 = new Person(Guid.NewGuid(), TenantId1 + "-Person1", 42, TenantId1); var tenant1Person2 = new Person(Guid.NewGuid(), TenantId1 + "-Person2", 43, TenantId1); - _personRepository.Insert(tenant1Person1); - _personRepository.Insert(tenant1Person2); + await _personRepository.InsertAsync(tenant1Person1).ConfigureAwait(false); + await _personRepository.InsertAsync(tenant1Person2).ConfigureAwait(false); } - private void AddEntitiesWithPks() + private async Task AddEntitiesWithPks() { - _entityWithIntPksRepository.Insert(new EntityWithIntPk("Entity1")); + await _entityWithIntPksRepository.InsertAsync(new EntityWithIntPk("Entity1")).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs index e36225e53c..782f61830a 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs @@ -28,9 +28,9 @@ namespace Volo.Abp.TestApp.Testing { Birthday = DateTime.Parse("2020-01-01 00:00:00"), LastActive = DateTime.Parse("2020-01-01 00:00:00"), - }, true); + }, true).ConfigureAwait(false); - var person = await _personRepository.GetAsync(personId); + var person = await _personRepository.GetAsync(personId).ConfigureAwait(false); person.ShouldNotBeNull(); person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); @@ -53,9 +53,9 @@ namespace Volo.Abp.TestApp.Testing { Birthday = DateTime.Parse("2020-01-01 00:00:00"), LastActive = DateTime.Parse("2020-01-01 00:00:00"), - }, true); + }, true).ConfigureAwait(false); - var person = await _personRepository.GetViewAsync(personName); + var person = await _personRepository.GetViewAsync(personName).ConfigureAwait(false); person.ShouldNotBeNull(); person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Auditing_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Auditing_Tests.cs index 41ef7ce076..dcbfdaf045 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Auditing_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Auditing_Tests.cs @@ -49,9 +49,9 @@ namespace Volo.Abp.TestApp.Testing var personId = Guid.NewGuid(); - await PersonRepository.InsertAsync(new Person(personId, "Adam", 42)); + await PersonRepository.InsertAsync(new Person(personId, "Adam", 42)).ConfigureAwait(false); - var person = await PersonRepository.FindAsync(personId); + var person = await PersonRepository.FindAsync(personId).ConfigureAwait(false); person.ShouldNotBeNull(); person.CreationTime.ShouldBeLessThanOrEqualTo(Clock.Now); @@ -68,14 +68,14 @@ namespace Volo.Abp.TestApp.Testing CurrentUserId = Guid.Parse(currentUserId); } - var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.LastModificationTime.ShouldBeNull(); douglas.Age++; - await PersonRepository.UpdateAsync(douglas); + await PersonRepository.UpdateAsync(douglas).ConfigureAwait(false); - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldNotBeNull(); douglas.LastModificationTime.ShouldNotBeNull(); @@ -93,17 +93,17 @@ namespace Volo.Abp.TestApp.Testing CurrentUserId = Guid.Parse(currentUserId); } - var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); - await PersonRepository.DeleteAsync(douglas); + await PersonRepository.DeleteAsync(douglas).ConfigureAwait(false); - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldBeNull(); using (DataFilter.Disable()) { - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldNotBeNull(); douglas.DeletionTime.ShouldNotBeNull(); diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ConcurrencyStamp_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ConcurrencyStamp_Tests.cs index 2c5a5d89ab..1f7c927251 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ConcurrencyStamp_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ConcurrencyStamp_Tests.cs @@ -20,37 +20,37 @@ namespace Volo.Abp.TestApp.Testing public async Task Should_Not_Allow_To_Update_If_The_Entity_Has_Changed() { //Got an entity from database, changed its value, but not updated in the database yet - var london1 = await CityRepository.FindByNameAsync("London"); + var london1 = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london1.Name = "London-1"; //Another user has changed it just before I update - var london2 = await CityRepository.FindByNameAsync("London"); + var london2 = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london2.Name = "London-2"; - await CityRepository.UpdateAsync(london2); + await CityRepository.UpdateAsync(london2).ConfigureAwait(false); //And updating my old entity throws exception! await Assert.ThrowsAsync(async () => { - await CityRepository.UpdateAsync(london1); - }); + await CityRepository.UpdateAsync(london1).ConfigureAwait(false); + }).ConfigureAwait(false); } [Fact] public async Task Should_Not_Allow_To_Delete_If_The_Entity_Has_Changed() { //Got an entity from database, but not deleted in the database yet - var london1 = await CityRepository.FindByNameAsync("London"); + var london1 = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); //Another user has changed it just before I delete - var london2 = await CityRepository.FindByNameAsync("London"); + var london2 = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london2.Name = "London-updated"; - await CityRepository.UpdateAsync(london2); + await CityRepository.UpdateAsync(london2).ConfigureAwait(false); //And deleting my old entity throws exception! await Assert.ThrowsAsync(async () => { - await CityRepository.DeleteAsync(london1); - }); + await CityRepository.DeleteAsync(london1).ConfigureAwait(false); + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs index 3ca7eaf8e4..2c6982de6a 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs @@ -55,8 +55,8 @@ namespace Volo.Abp.TestApp.Testing { var dougles = PersonRepository.Single(b => b.Name == "Douglas"); dougles.ChangeName("Douglas-Changed"); - await PersonRepository.UpdateAsync(dougles); - }); + await PersonRepository.UpdateAsync(dougles).ConfigureAwait(false); + }).ConfigureAwait(false); //Assert diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs index 184b7698be..bc38257683 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.TestApp.Testing } [Fact] - public void Complex_Event_Test() + public async Task Complex_Event_Test() { var personName = Guid.NewGuid().ToString("N"); @@ -75,9 +75,9 @@ namespace Volo.Abp.TestApp.Testing return Task.CompletedTask; }); - PersonRepository.Insert(new Person(Guid.NewGuid(), personName, 15)); + await PersonRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 15)).ConfigureAwait(false); - uow.Complete(); + await uow.CompleteAsync().ConfigureAwait(false); } creatingEventTriggered.ShouldBeTrue(); diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ExtraProperties_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ExtraProperties_Tests.cs index 67eff13572..a52ddbee3a 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ExtraProperties_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/ExtraProperties_Tests.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task Should_Get_An_Extra_Property() { - var london = await CityRepository.FindByNameAsync("London"); + var london = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london.HasProperty("Population").ShouldBeTrue(); london.GetProperty("Population").ShouldBe(10_470_000); } @@ -28,11 +28,11 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task Should_Add_An_Extra_Property() { - var london = await CityRepository.FindByNameAsync("London"); + var london = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london.SetProperty("AreaAsKm", 1572); - await CityRepository.UpdateAsync(london); + await CityRepository.UpdateAsync(london).ConfigureAwait(false); - var london2 = await CityRepository.FindByNameAsync("London"); + var london2 = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london2.HasProperty("AreaAsKm").ShouldBeTrue(); london2.GetProperty("AreaAsKm").ShouldBe(1572); } @@ -40,12 +40,12 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task Should_Update_An_Existing_Extra_Property() { - var london = await CityRepository.FindByNameAsync("London"); + var london = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london.ExtraProperties["Population"] = 11_000_042; - await CityRepository.UpdateAsync(london); + await CityRepository.UpdateAsync(london).ConfigureAwait(false); - var london2 = await CityRepository.FindByNameAsync("London"); + var london2 = await CityRepository.FindByNameAsync("London").ConfigureAwait(false); london2.HasProperty("Population").ShouldBeTrue(); london2.GetProperty("Population").ShouldBe(11_000_042); } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Creation_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Creation_Tests.cs index c648fc66d4..af910aefba 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Creation_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Creation_Tests.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; -using Volo.Abp.Data; using Volo.Abp.Domain.Repositories; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; @@ -45,9 +42,9 @@ namespace Volo.Abp.TestApp.Testing Id = personId, Name = "Person1", Age = 21 - }); + }).ConfigureAwait(false); - var person = await _personRepository.FindAsync(personId); + var person = await _personRepository.FindAsync(personId).ConfigureAwait(false); person.ShouldNotBeNull(); person.TenantId.ShouldNotBeNull(); @@ -66,9 +63,9 @@ namespace Volo.Abp.TestApp.Testing Id = personId, Name = "Person1", Age = 21 - }); + }).ConfigureAwait(false); - var person = await _personRepository.FindAsync(personId); + var person = await _personRepository.FindAsync(personId).ConfigureAwait(false); person.ShouldNotBeNull(); person.TenantId.ShouldBeNull(); diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Filter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Filter_Tests.cs index d763fdea5b..10ce8e1605 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Filter_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/MultiTenant_Filter_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; @@ -33,9 +34,9 @@ namespace Volo.Abp.TestApp.Testing } [Fact] - public void Should_Get_Person_For_Current_Tenant() + public async Task Should_Get_Person_For_Current_Tenant() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { //TenantId = null @@ -60,13 +61,15 @@ namespace Volo.Abp.TestApp.Testing people = _personRepository.ToList(); people.Count.ShouldBe(0); - }); + + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void Should_Get_All_People_When_MultiTenant_Filter_Is_Disabled() + public async Task Should_Get_All_People_When_MultiTenant_Filter_Is_Disabled() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { List people; @@ -80,7 +83,9 @@ namespace Volo.Abp.TestApp.Testing //Filter re-enabled automatically people = _personRepository.ToList(); people.Count.ShouldBe(1); - }); + + return Task.CompletedTask; + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests.cs index 07e6211c09..7571c4fecd 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task GetAsync() { - var person = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + var person = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); person.Name.ShouldBe("Douglas"); person.Phones.Count.ShouldBe(2); } @@ -31,29 +31,29 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task FindAsync_Should_Return_Null_For_Not_Found_Entity() { - var person = await PersonRepository.FindAsync(Guid.NewGuid()); + var person = await PersonRepository.FindAsync(Guid.NewGuid()).ConfigureAwait(false); person.ShouldBeNull(); } [Fact] public async Task DeleteAsync() { - await PersonRepository.DeleteAsync(TestDataBuilder.UserDouglasId); + await PersonRepository.DeleteAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); - (await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId)).ShouldBeNull(); + (await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task Should_Access_To_Other_Collections_In_Same_Context_In_A_Custom_Method() { - var people = await CityRepository.GetPeopleInTheCityAsync("London"); + var people = await CityRepository.GetPeopleInTheCityAsync("London").ConfigureAwait(false); people.Count.ShouldBeGreaterThan(0); } [Fact] public async Task Custom_Repository_Method() { - var city = await CityRepository.FindByNameAsync("Istanbul"); + var city = await CityRepository.FindByNameAsync("Istanbul").ConfigureAwait(false); city.ShouldNotBeNull(); city.Name.ShouldBe("Istanbul"); } @@ -63,9 +63,9 @@ namespace Volo.Abp.TestApp.Testing { var personId = Guid.NewGuid(); - await PersonRepository.InsertAsync(new Person(personId, "Adam", 42)); + await PersonRepository.InsertAsync(new Person(personId, "Adam", 42)).ConfigureAwait(false); - var person = await PersonRepository.FindAsync(personId); + var person = await PersonRepository.FindAsync(personId).ConfigureAwait(false); person.ShouldNotBeNull(); } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs index f8a2f4e8e9..0c3bc5e290 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Threading.Tasks; using Shouldly; using Volo.Abp.Domain.Repositories; using Volo.Abp.Modularity; @@ -18,25 +19,26 @@ namespace Volo.Abp.TestApp.Testing } [Fact] - public virtual void FirstOrDefault() + public virtual async Task FirstOrDefault() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var entity = EntityWithIntPkRepository.FirstOrDefault(e => e.Name == "Entity1"); entity.ShouldNotBeNull(); entity.Name.ShouldBe("Entity1"); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public virtual void Get() + public virtual async Task Get() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(async () => { - var entity = EntityWithIntPkRepository.Get(1); + var entity = await EntityWithIntPkRepository.GetAsync(1).ConfigureAwait(false); entity.ShouldNotBeNull(); entity.Name.ShouldBe("Entity1"); - }); + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs index b7436f7bc5..0e7bf2f7df 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Domain.Repositories; @@ -20,44 +21,48 @@ namespace Volo.Abp.TestApp.Testing } [Fact] - public void Any() + public async Task Any() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { PersonRepository.Any().ShouldBeTrue(); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void Single() + public async Task Single() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var person = PersonRepository.Single(p => p.Id == TestDataBuilder.UserDouglasId); person.Name.ShouldBe("Douglas"); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void WithDetails() + public async Task WithDetails() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var person = PersonRepository.WithDetails().Single(p => p.Id == TestDataBuilder.UserDouglasId); person.Name.ShouldBe("Douglas"); person.Phones.Count.ShouldBe(2); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void WithDetails_Explicit() + public async Task WithDetails_Explicit() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var person = PersonRepository.WithDetails(p => p.Phones).Single(p => p.Id == TestDataBuilder.UserDouglasId); person.Name.ShouldBe("Douglas"); person.Phones.Count.ShouldBe(2); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Specifications_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Specifications_Tests.cs index a3e7907135..49880535f2 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Specifications_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Specifications_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using System.Threading.Tasks; using Shouldly; using Volo.Abp.Domain.Repositories; using Volo.Abp.Modularity; @@ -21,12 +22,13 @@ namespace Volo.Abp.TestApp.Testing } [Fact] - public void SpecificationWithRepository_Test() + public async Task SpecificationWithRepository_Test() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { CityRepository.Count(new CitySpecification().ToExpression()).ShouldBe(1); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Filter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Filter_Tests.cs index 891691114e..6daba040a4 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Filter_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Filter_Tests.cs @@ -23,13 +23,14 @@ namespace Volo.Abp.TestApp.Testing } [Fact] - public void Should_Not_Get_Deleted_Entities_Linq() + public async Task Should_Not_Get_Deleted_Entities_Linq() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var person = PersonRepository.FirstOrDefault(p => p.Name == "John-Deleted"); person.ShouldBeNull(); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] @@ -37,26 +38,27 @@ namespace Volo.Abp.TestApp.Testing { await WithUnitOfWorkAsync(async () => { - var person = await PersonRepository.FindAsync(TestDataBuilder.UserJohnDeletedId); + var person = await PersonRepository.FindAsync(TestDataBuilder.UserJohnDeletedId).ConfigureAwait(false); person.ShouldBeNull(); - }); + }).ConfigureAwait(false); } [Fact] - public void Should_Not_Get_Deleted_Entities_By_Default_ToList() + public async Task Should_Not_Get_Deleted_Entities_By_Default_ToList() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { var people = PersonRepository.ToList(); people.Count.ShouldBe(1); people.Any(p => p.Name == "Douglas").ShouldBeTrue(); - }); + return Task.CompletedTask; + }).ConfigureAwait(false); } [Fact] - public void Should_Get_Deleted_Entities_When_Filter_Is_Disabled() + public async Task Should_Get_Deleted_Entities_When_Filter_Is_Disabled() { - WithUnitOfWork(() => + await WithUnitOfWorkAsync(() => { //Soft delete is enabled by default var people = PersonRepository.ToList(); @@ -88,7 +90,9 @@ namespace Volo.Abp.TestApp.Testing people = PersonRepository.ToList(); people.Any(p => !p.IsDeleted).ShouldBeTrue(); people.Any(p => p.IsDeleted).ShouldBeFalse(); - }); + + return Task.CompletedTask; + }).ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs index 0059a39a11..e1f4bc56a7 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/SoftDelete_Tests.cs @@ -24,15 +24,15 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task Should_Cancel_Deletion_For_Soft_Delete_Entities() { - var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); - await PersonRepository.DeleteAsync(douglas); + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); + await PersonRepository.DeleteAsync(douglas).ConfigureAwait(false); - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldBeNull(); using (DataFilter.Disable()) { - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldNotBeNull(); douglas.IsDeleted.ShouldBeTrue(); douglas.DeletionTime.ShouldNotBeNull(); @@ -42,18 +42,18 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task Should_Handle_Deletion_On_Update_For_Soft_Delete_Entities() { - var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.Age = 42; douglas.IsDeleted = true; - await PersonRepository.UpdateAsync(douglas); + await PersonRepository.UpdateAsync(douglas).ConfigureAwait(false); - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldBeNull(); using (DataFilter.Disable()) { - douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId); + douglas = await PersonRepository.FindAsync(TestDataBuilder.UserDouglasId).ConfigureAwait(false); douglas.ShouldNotBeNull(); douglas.IsDeleted.ShouldBeTrue(); douglas.DeletionTime.ShouldNotBeNull(); diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs index 647e5eaa03..3f80bfb74b 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Volo.Abp.Uow; namespace Volo.Abp.TestApp.Testing @@ -16,26 +17,6 @@ namespace Volo.Abp.TestApp.Testing #region WithUnitOfWork - protected virtual void WithUnitOfWork(Action action) - { - WithUnitOfWork(new AbpUnitOfWorkOptions(), action); - } - - protected virtual void WithUnitOfWork(AbpUnitOfWorkOptions options, Action action) - { - using (var scope = ServiceProvider.CreateScope()) - { - var uowManager = scope.ServiceProvider.GetRequiredService(); - - using (var uow = uowManager.Begin(options)) - { - action(); - - uow.Complete(); - } - } - } - protected virtual Task WithUnitOfWorkAsync(Func func) { return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); @@ -49,29 +30,9 @@ namespace Volo.Abp.TestApp.Testing using (var uow = uowManager.Begin(options)) { - await action(); + await action().ConfigureAwait(false); - await uow.CompleteAsync(); - } - } - } - - protected virtual TResult WithUnitOfWork(Func func) - { - return WithUnitOfWork(new AbpUnitOfWorkOptions(), func); - } - - protected virtual TResult WithUnitOfWork(AbpUnitOfWorkOptions options, Func func) - { - using (var scope = ServiceProvider.CreateScope()) - { - var uowManager = scope.ServiceProvider.GetRequiredService(); - - using (var uow = uowManager.Begin(options)) - { - var result = func(); - uow.Complete(); - return result; + await uow.CompleteAsync().ConfigureAwait(false); } } } @@ -89,8 +50,8 @@ namespace Volo.Abp.TestApp.Testing using (var uow = uowManager.Begin(options)) { - var result = await func(); - await uow.CompleteAsync(); + var result = await func().ConfigureAwait(false); + await uow.CompleteAsync().ConfigureAwait(false); return result; } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs index 1b169bbe97..a101e64ea6 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Uow_Completed_Tests.cs @@ -25,15 +25,15 @@ namespace Volo.Abp.TestApp.Testing using (var uow = _unitOfWorkManager.Begin()) { //Perform an arbitrary database operation - await _cityRepository.InsertAsync(new City(Guid.NewGuid(), Guid.NewGuid().ToString())); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), Guid.NewGuid().ToString())).ConfigureAwait(false); uow.OnCompleted(async () => { //Perform another database operation inside the OnCompleted handler - await _cityRepository.InsertAsync(new City(Guid.NewGuid(), Guid.NewGuid().ToString())); + await _cityRepository.InsertAsync(new City(Guid.NewGuid(), Guid.NewGuid().ToString())).ConfigureAwait(false); }); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } } diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj index 412610301f..51beb181a1 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs index 5fed48c828..1f5190a9eb 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; -using Volo.Abp.UI.Navigation; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.UI.Navigation @@ -19,7 +19,7 @@ namespace Volo.Abp.UI.Navigation [Fact] public async Task Should_Get_Menu() { - var mainMenu = await _menuManager.GetAsync(StandardMenus.Main); + var mainMenu = await _menuManager.GetAsync(StandardMenus.Main).ConfigureAwait(false); mainMenu.Name.ShouldBe(StandardMenus.Main); mainMenu.DisplayName.ShouldBe("Main Menu"); diff --git a/framework/test/Volo.Abp.Uow.Tests/Volo.Abp.Uow.Tests.csproj b/framework/test/Volo.Abp.Uow.Tests/Volo.Abp.Uow.Tests.csproj index ee6dd78e4c..256dd07ed6 100644 --- a/framework/test/Volo.Abp.Uow.Tests/Volo.Abp.Uow.Tests.csproj +++ b/framework/test/Volo.Abp.Uow.Tests/Volo.Abp.Uow.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs index c4b43bebe1..6b1bc2f98d 100644 --- a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs +++ b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Uow @@ -29,13 +30,13 @@ namespace Volo.Abp.Uow _unitOfWorkManager.Current.ShouldNotBeNull(); _unitOfWorkManager.Current.Id.ShouldBe(uow1.Id); - await uow2.CompleteAsync(); + await uow2.CompleteAsync().ConfigureAwait(false); } _unitOfWorkManager.Current.ShouldNotBeNull(); _unitOfWorkManager.Current.ShouldBe(uow1); - await uow1.CompleteAsync(); + await uow1.CompleteAsync().ConfigureAwait(false); } _unitOfWorkManager.Current.ShouldBeNull(); @@ -55,7 +56,7 @@ namespace Volo.Abp.Uow _unitOfWorkManager.Current.ShouldNotBeNull(); _unitOfWorkManager.Current.Id.ShouldNotBe(uow1.Id); - await uow2.CompleteAsync(); + await uow2.CompleteAsync().ConfigureAwait(false); } _unitOfWorkManager.Current.ShouldBeNull(); @@ -65,7 +66,7 @@ namespace Volo.Abp.Uow _unitOfWorkManager.Current.ShouldNotBeNull(); _unitOfWorkManager.Current.Id.ShouldBe(uow1.Id); - await uow1.CompleteAsync(); + await uow1.CompleteAsync().ConfigureAwait(false); } _unitOfWorkManager.Current.ShouldBeNull(); diff --git a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs index 4d9bfc8dd6..7d9a176076 100644 --- a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs +++ b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs @@ -1,6 +1,8 @@ using System; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Uow @@ -15,17 +17,22 @@ namespace Volo.Abp.Uow } [Fact] - public void Should_Trigger_Complete_On_Success() + public async Task Should_Trigger_Complete_On_Success() { var completed = false; var disposed = false; using (var uow = _unitOfWorkManager.Begin()) { - uow.OnCompleted(async () => completed = true); + uow.OnCompleted(() => + { + completed = true; + return Task.CompletedTask; + }); + uow.Disposed += (sender, args) => disposed = true; - uow.Complete(); + await uow.CompleteAsync().ConfigureAwait(false); completed.ShouldBeTrue(); } @@ -34,7 +41,7 @@ namespace Volo.Abp.Uow } [Fact] - public void Should_Trigger_Complete_On_Success_In_Child_Uow() + public async Task Should_Trigger_Complete_On_Success_In_Child_Uow() { var completed = false; var disposed = false; @@ -46,7 +53,7 @@ namespace Volo.Abp.Uow childUow.OnCompleted(async () => completed = true); uow.Disposed += (sender, args) => disposed = true; - childUow.Complete(); + await childUow.CompleteAsync().ConfigureAwait(false); completed.ShouldBeFalse(); //Parent has not been completed yet! disposed.ShouldBeFalse(); @@ -55,7 +62,7 @@ namespace Volo.Abp.Uow completed.ShouldBeFalse(); //Parent has not been completed yet! disposed.ShouldBeFalse(); - uow.Complete(); + await uow.CompleteAsync().ConfigureAwait(false); completed.ShouldBeTrue(); //It's completed now! disposed.ShouldBeFalse(); //But not disposed yet! @@ -110,7 +117,7 @@ namespace Volo.Abp.Uow [InlineData(true)] [InlineData(false)] [Theory] - public void Should_Trigger_Failed_If_Rolled_Back(bool callComplete) + public async Task Should_Trigger_Failed_If_Rolled_Back(bool callComplete) { var completed = false; var failed = false; @@ -122,11 +129,11 @@ namespace Volo.Abp.Uow uow.Failed += (sender, args) => { failed = true; args.IsRolledback.ShouldBeTrue(); }; uow.Disposed += (sender, args) => disposed = true; - uow.Rollback(); + await uow.RollbackAsync().ConfigureAwait(false); if (callComplete) { - uow.Complete(); + await uow.CompleteAsync().ConfigureAwait(false); } } diff --git a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Nested_Tests.cs b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Nested_Tests.cs index e322a25682..efa4a7540e 100644 --- a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Nested_Tests.cs +++ b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Nested_Tests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Uow @@ -29,13 +30,13 @@ namespace Volo.Abp.Uow _unitOfWorkManager.Current.ShouldNotBeNull(); _unitOfWorkManager.Current.Id.ShouldNotBe(uow1.Id); - await uow2.CompleteAsync(); + await uow2.CompleteAsync().ConfigureAwait(false); } _unitOfWorkManager.Current.ShouldNotBeNull(); _unitOfWorkManager.Current.ShouldBe(uow1); - await uow1.CompleteAsync(); + await uow1.CompleteAsync().ConfigureAwait(false); } _unitOfWorkManager.Current.ShouldBeNull(); diff --git a/framework/test/Volo.Abp.Validation.Tests/Volo.Abp.Validation.Tests.csproj b/framework/test/Volo.Abp.Validation.Tests/Volo.Abp.Validation.Tests.csproj index b86adccff8..a16495ccda 100644 --- a/framework/test/Volo.Abp.Validation.Tests/Volo.Abp.Validation.Tests.csproj +++ b/framework/test/Volo.Abp.Validation.Tests/Volo.Abp.Validation.Tests.csproj @@ -9,9 +9,10 @@ + - + diff --git a/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs b/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs index 8ff4aa8bfd..8b4f4a6110 100644 --- a/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs +++ b/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.Application.Dtos; using Volo.Abp.Autofac; using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Validation @@ -25,57 +29,58 @@ namespace Volo.Abp.Validation } [Fact] - public void Should_Work_Proper_With_Right_Inputs() + public async Task Should_Work_Proper_With_Right_Inputs() { - var output = _myAppService.MyMethod(new MyMethodInput { MyStringValue = "test" }); + var output = await _myAppService.MyMethod(new MyMethodInput { MyStringValue = "test" }).ConfigureAwait(false); output.Result.ShouldBe(42); } [Fact] - public void Should_Not_Work_With_Wrong_Inputs() + public async Task Should_Not_Work_With_Wrong_Inputs() { - Assert.Throws(() => _myAppService.MyMethod(new MyMethodInput())); //MyStringValue is not supplied! - Assert.Throws(() => _myAppService.MyMethod(new MyMethodInput { MyStringValue = "a" })); //MyStringValue's min length should be 3! + await Assert.ThrowsAsync(async () => await _myAppService.MyMethod(new MyMethodInput()).ConfigureAwait(false)).ConfigureAwait(false); //MyStringValue is not supplied! + await Assert.ThrowsAsync(async () => await _myAppService.MyMethod(new MyMethodInput { MyStringValue = "a" }).ConfigureAwait(false)).ConfigureAwait(false); //MyStringValue's min length should be 3! } [Fact] - public void Should_Work_With_Right_Nesned_Inputs() + public async Task Should_Work_With_Right_Nesned_Inputs() { - var output = _myAppService.MyMethod2(new MyMethod2Input + var output = await _myAppService.MyMethod2(new MyMethod2Input { MyStringValue2 = "test 1", Input1 = new MyMethodInput { MyStringValue = "test 2" }, DateTimeValue = DateTime.Now - }); + }).ConfigureAwait(false); + output.Result.ShouldBe(42); } [Fact] - public void Should_Not_Work_With_Wrong_Nesned_Inputs_1() + public async Task Should_Not_Work_With_Wrong_Nesned_Inputs_1() { - Assert.Throws(() => - _myAppService.MyMethod2(new MyMethod2Input + await Assert.ThrowsAsync(async () => + await _myAppService.MyMethod2(new MyMethod2Input { MyStringValue2 = "test 1", Input1 = new MyMethodInput() //MyStringValue is not set - })); + }).ConfigureAwait(false)).ConfigureAwait(false); } [Fact] - public void Should_Not_Work_With_Wrong_Nesned_Inputs_2() + public async Task Should_Not_Work_With_Wrong_Nesned_Inputs_2() { - Assert.Throws(() => - _myAppService.MyMethod2(new MyMethod2Input //Input1 is not set + await Assert.ThrowsAsync(async () => + await _myAppService.MyMethod2(new MyMethod2Input //Input1 is not set { MyStringValue2 = "test 1" - })); + }).ConfigureAwait(false)).ConfigureAwait(false); } [Fact] - public void Should_Not_Work_With_Wrong_List_Input_1() + public async Task Should_Not_Work_With_Wrong_List_Input_1() { - Assert.Throws(() => - _myAppService.MyMethod3( + await Assert.ThrowsAsync(async () => + await _myAppService.MyMethod3( new MyMethod3Input { MyStringValue2 = "test 1", @@ -83,14 +88,14 @@ namespace Volo.Abp.Validation { new MyClassInList {ValueInList = null} } - })); + }).ConfigureAwait(false)).ConfigureAwait(false); } [Fact] - public void Should_Not_Work_With_Wrong_Array_Input_1() + public async Task Should_Not_Work_With_Wrong_Array_Input_1() { - Assert.Throws(() => - _myAppService.MyMethod3( + await Assert.ThrowsAsync(async () => + await _myAppService.MyMethod3( new MyMethod3Input { MyStringValue2 = "test 1", @@ -98,67 +103,91 @@ namespace Volo.Abp.Validation { new MyClassInList {ValueInList = null} } - })); + }).ConfigureAwait(false)).ConfigureAwait(false); } [Fact] - public void Should_Not_Work_If_Array_Is_Null() + public async Task Should_Not_Work_If_Array_Is_Null() { - Assert.Throws(() => - _myAppService.MyMethod4(new MyMethod4Input()) //ArrayItems is null! - ); + await Assert.ThrowsAsync(async () => + await _myAppService.MyMethod4(new MyMethod4Input()) //ArrayItems is null! +.ConfigureAwait(false)).ConfigureAwait(false); } [Fact] - public void Should_Work_If_Array_Is_Null_But_DisabledValidation_For_Method() + public async Task Should_Work_If_Array_Is_Null_But_DisabledValidation_For_Method() { - _myAppService.MyMethod4_2(new MyMethod4Input()); + await _myAppService.MyMethod4_2(new MyMethod4Input()).ConfigureAwait(false); } [Fact] - public void Should_Work_If_Array_Is_Null_But_DisabledValidation_For_Property() + public async Task Should_Work_If_Array_Is_Null_But_DisabledValidation_For_Property() { - _myAppService.MyMethod5(new MyMethod5Input()); + await _myAppService.MyMethod5(new MyMethod5Input()).ConfigureAwait(false); } [Fact] - public void Should_Use_IValidatableObject() + public async Task Should_Use_IValidatableObject() { - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - _myAppService.MyMethod6(new MyMethod6Input + await _myAppService.MyMethod6(new MyMethod6Input { MyStringValue = "test value" //MyIntValue has not set! - }); - }); + }).ConfigureAwait(false); + }).ConfigureAwait(false); + } + + //TODO: Create a Volo.Abp.Ddd.Application.Contracts.Tests project and move this to there and remove Volo.Abp.Ddd.Application.Contracts dependency from this project. + [Fact] + public async Task LimitedResultRequestDto_Should_Throw_Exception_For_Requests_More_Than_MaxMaxResultCount() + { + var exception = await Assert.ThrowsAsync(async () => + { + await _myAppService.MyMethodWithLimitedResult(new LimitedResultRequestDto + { + MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount + 1 + }).ConfigureAwait(false); + }).ConfigureAwait(false); + + exception.ValidationErrors.ShouldContain(e => e.MemberNames.Contains(nameof(LimitedResultRequestDto.MaxResultCount))); + } + + [Fact] + public async Task LimitedResultRequestDto_Should_Be_Valid_For_Requests_Less_Than_MaxMaxResultCount() + { + await _myAppService.MyMethodWithLimitedResult(new LimitedResultRequestDto + { + MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount - 1 + }).ConfigureAwait(false); } [Fact] - public void Should_Stop_Recursive_Validation_In_A_Constant_Depth() + public async Task Should_Stop_Recursive_Validation_In_A_Constant_Depth() { - _myAppService.MyMethod8(new MyClassWithRecursiveReference { Value = "42" }).Result.ShouldBe(42); + (await _myAppService.MyMethod8(new MyClassWithRecursiveReference { Value = "42" }).ConfigureAwait(false)).Result.ShouldBe(42); } [Fact] - public void Should_Allow_Null_For_Nullable_Enums() + public async Task Should_Allow_Null_For_Nullable_Enums() { - _myAppService.MyMethodWithNullableEnum(null); + await _myAppService.MyMethodWithNullableEnum(null).ConfigureAwait(false); } [Fact] public void Should_Validate_Emails() { //Valid - ValidationHandler.IsValidEmailAddress("john.doe@domain.com").ShouldBe(true); - ValidationHandler.IsValidEmailAddress("ip@1.2.3.123").ShouldBe(true); - ValidationHandler.IsValidEmailAddress("pharaoh@egyptian.museum").ShouldBe(true); - ValidationHandler.IsValidEmailAddress("john.doe+regexbuddy@gmail.com").ShouldBe(true); - ValidationHandler.IsValidEmailAddress("Mike.O'Dell@ireland.com").ShouldBe(true); + ValidationHelper.IsValidEmailAddress("john.doe@domain.com").ShouldBe(true); + ValidationHelper.IsValidEmailAddress("ip@1.2.3.123").ShouldBe(true); + ValidationHelper.IsValidEmailAddress("pharaoh@egyptian.museum").ShouldBe(true); + ValidationHelper.IsValidEmailAddress("john.doe+regexbuddy@gmail.com").ShouldBe(true); + ValidationHelper.IsValidEmailAddress("Mike.O'Dell@ireland.com").ShouldBe(true); //Invalid - ValidationHandler.IsValidEmailAddress("1024x768@60Hz").ShouldBe(false); - ValidationHandler.IsValidEmailAddress("not.a.valid.email").ShouldBe(false); - ValidationHandler.IsValidEmailAddress("john@aol...com").ShouldBe(false); + ValidationHelper.IsValidEmailAddress("1024x768@60Hz").ShouldBe(false); + ValidationHelper.IsValidEmailAddress("not.a.valid.email").ShouldBe(false); + ValidationHelper.IsValidEmailAddress("john@aol...com").ShouldBe(false); } [DependsOn(typeof(AbpAutofacModule))] @@ -184,63 +213,69 @@ namespace Volo.Abp.Validation public interface IMyAppService { - MyMethodOutput MyMethod(MyMethodInput input); - MyMethodOutput MyMethod2(MyMethod2Input input); - MyMethodOutput MyMethod3(MyMethod3Input input); - MyMethodOutput MyMethod4(MyMethod4Input input); - MyMethodOutput MyMethod4_2(MyMethod4Input input); - MyMethodOutput MyMethod5(MyMethod5Input input); - MyMethodOutput MyMethod6(MyMethod6Input input); - MyMethodOutput MyMethod8(MyClassWithRecursiveReference input); - void MyMethodWithNullableEnum(MyEnum? value); + Task MyMethod(MyMethodInput input); + Task MyMethod2(MyMethod2Input input); + Task MyMethod3(MyMethod3Input input); + Task MyMethod4(MyMethod4Input input); + Task MyMethod4_2(MyMethod4Input input); + Task MyMethod5(MyMethod5Input input); + Task MyMethod6(MyMethod6Input input); + Task MyMethod8(MyClassWithRecursiveReference input); + Task MyMethodWithNullableEnum(MyEnum? value); + Task MyMethodWithLimitedResult(LimitedResultRequestDto input); } public class MyAppService : IMyAppService, ITransientDependency { - public MyMethodOutput MyMethod(MyMethodInput input) + public Task MyMethod(MyMethodInput input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public MyMethodOutput MyMethod2(MyMethod2Input input) + public Task MyMethod2(MyMethod2Input input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public MyMethodOutput MyMethod3(MyMethod3Input input) + public Task MyMethod3(MyMethod3Input input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public MyMethodOutput MyMethod4(MyMethod4Input input) + public Task MyMethod4(MyMethod4Input input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } [DisableValidation] - public MyMethodOutput MyMethod4_2(MyMethod4Input input) + public Task MyMethod4_2(MyMethod4Input input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public MyMethodOutput MyMethod5(MyMethod5Input input) + public Task MyMethod5(MyMethod5Input input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public MyMethodOutput MyMethod6(MyMethod6Input input) + public Task MyMethod6(MyMethod6Input input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public MyMethodOutput MyMethod8(MyClassWithRecursiveReference input) + public Task MyMethod8(MyClassWithRecursiveReference input) { - return new MyMethodOutput { Result = 42 }; + return Task.FromResult(new MyMethodOutput { Result = 42 }); } - public void MyMethodWithNullableEnum(MyEnum? value) + public Task MyMethodWithLimitedResult(LimitedResultRequestDto input) { + return Task.CompletedTask; + } + public Task MyMethodWithNullableEnum(MyEnum? value) + { + return Task.CompletedTask; } } diff --git a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj index 6d65a8ebe6..63617f36c0 100644 --- a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj +++ b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/DynamicFileProvider_Tests.cs b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/DynamicFileProvider_Tests.cs index 45aaa88fd4..3b44387da5 100644 --- a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/DynamicFileProvider_Tests.cs +++ b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/DynamicFileProvider_Tests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.VirtualFileSystem diff --git a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs index e6464f6bd4..3d69b87b56 100644 --- a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs +++ b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs @@ -4,6 +4,7 @@ using System.Text; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.VirtualFileSystem diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs index 1d3ced4cdb..ee1b6c7957 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs @@ -2,8 +2,8 @@ using Volo.Abp.Identity; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Account diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json index f0ec8ad410..ac8b58ee1e 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/cs.json @@ -14,8 +14,31 @@ "Login": "Přihlásit", "Cancel": "Zrušit", "Register": "Registrovat", + "AreYouANewUser": "Jste nový uživatel?", + "AlreadyRegistered": "Jste už zaregistrovaní?", "InvalidLoginRequest": "Neplatný požadavek k přihlášení", "ThereAreNoLoginSchemesConfiguredForThisClient": "Pro tohoto klienta nejsou nakonfigurovány žádné přihlašovací schémata.", - "LogInUsingYourProviderAccount": "Přihlásit pomocí vašeho účtu {0}" + "LogInUsingYourProviderAccount": "Přihlásit pomocí vašeho účtu {0}", + "DisplayName:CurrentPassword": "Současné heslo", + "DisplayName:NewPassword": "Nové heslo", + "DisplayName:NewPasswordConfirm": "Potvrzení nového hesla", + "PasswordChangedMessage": "Vaše heslo bylo úspěšně změněno.", + "DisplayName:UserName": "Uživatelské jméno", + "DisplayName:Email": "Email", + "DisplayName:Name": "Jméno", + "DisplayName:Surname": "Příjmení", + "DisplayName:Password": "Heslo", + "DisplayName:EmailAddress": "Email adresa", + "DisplayName:PhoneNumber": "Telefonní číslo", + "PersonalSettings": "Osobní nastavení", + "PersonalSettingsSaved": "Osobní nastavení uloženo", + "PasswordChanged": "Heslo změněno", + "NewPasswordConfirmFailed": "Potvrďte nové heslo.", + "Manage": "Spravovat", + "ManageYourProfile": "Spravujte svůj profil", + "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "Je povolena automatická registrace", + "Description:Abp.Account.IsSelfRegistrationEnabled": "Zda si uživatel může účet zaregistrovat sám.", + "DisplayName:Abp.Account.EnableLocalLogin": "Ověření pomocí místního účtu", + "Description:Abp.Account.EnableLocalLogin": "Označuje, zda server umožní uživatelům ověřovat se pomocí místního účtu." } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json index bc507158b1..ea2d94f5f2 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json @@ -1,16 +1,16 @@ { "culture": "en", "texts": { - "UserName": "User name", + "UserName": "Username", "EmailAddress": "Email address", - "UserNameOrEmailAddress": "User name or email address", + "UserNameOrEmailAddress": "Username or email address", "Password": "Password", "RememberMe": "Remember me", "UseAnotherServiceToLogin": "Use another service to log in", "UserLockedOutMessage": "The user account has been locked out due to invalid login attempts. Please wait a while and try again.", "InvalidUserNameOrPassword": "Invalid username or password!", "LoginIsNotAllowed": "You are not allowed to login! You need to confirm your email/phone number.", - "SelfRegistrationDisabledMessage": "Self user registration is disabled for this application. Contact to the application administrator to register a new user.", + "SelfRegistrationDisabledMessage": "Self-registration is disabled for this application. Please contact the application administrator to register a new user.", "Login": "Login", "Cancel": "Cancel", "Register": "Register", @@ -23,7 +23,7 @@ "DisplayName:NewPassword": "New password", "DisplayName:NewPasswordConfirm": "Confirm new password", "PasswordChangedMessage": "Your password has been changed successfully.", - "DisplayName:UserName": "User name", + "DisplayName:UserName": "Username", "DisplayName:Email": "Email", "DisplayName:Name": "Name", "DisplayName:Surname": "Surname", @@ -35,6 +35,10 @@ "PasswordChanged": "Password changed", "NewPasswordConfirmFailed": "Please confirm the new password.", "Manage": "Manage", - "ManageYourProfile": "Manage your profile" + "ManageYourProfile": "Manage your profile", + "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "Is self-registration enabled", + "Description:Abp.Account.IsSelfRegistrationEnabled": "Whether a user can register the account by him or herself.", + "DisplayName:Abp.Account.EnableLocalLogin": "Authenticate with a local account", + "Description:Abp.Account.EnableLocalLogin": "Indicates if the server will allow users to authenticate with a local account." } -} \ No newline at end of file +} diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json index 1db38474ae..c778a28dd6 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json @@ -29,12 +29,16 @@ "DisplayName:Surname": "姓", "DisplayName:Password": "密码", "DisplayName:EmailAddress": "电子邮件地址", - "DisplayName:PhoneNumber": "电话号码", + "DisplayName:PhoneNumber": "手机号码", "PersonalSettings": "个人设置", "PersonalSettingsSaved": "个人设置已保存", "PasswordChanged": "修改密码", "NewPasswordConfirmFailed": "请确认新密码", "Manage": "管理", - "ManageYourProfile": "管理你的个人资料" + "ManageYourProfile": "管理你的个人资料", + "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "启用自行注册", + "Description:Abp.Account.IsSelfRegistrationEnabled": "是否允许用户自行注册帐户.", + "DisplayName:Abp.Account.EnableLocalLogin": "使用本地帐户进行身份验证", + "Description:Abp.Account.EnableLocalLogin": "服务器是否将允许用户使用本地帐户进行身份验证。" } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..e21631e92e --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json @@ -0,0 +1,44 @@ +{ + "culture": "zh-Hant", + "texts": { + "UserName": "使用者名稱", + "EmailAddress": "電子信箱地址", + "UserNameOrEmailAddress": "使用者名稱或電子信箱地址", + "Password": "密碼", + "RememberMe": "記住我", + "UseAnotherServiceToLogin": "使用另一個服務登入", + "UserLockedOutMessage": "登入失敗,使用者帳號已被鎖定.請稍後再試.", + "InvalidUserNameOrPassword": "使用者名稱或密碼錯誤!", + "LoginIsNotAllowed": "無法登入!你需要驗證電子信箱地址/手機號碼.", + "SelfRegistrationDisabledMessage": "應用程式未開放註冊,請聯絡管理員以加入新使用者.", + "Login": "登入", + "Cancel": "取消", + "Register": "註冊", + "AreYouANewUser": "你是新使用者嗎?", + "AlreadyRegistered": "已經註冊過了?", + "InvalidLoginRequest": "登入請求無效", + "ThereAreNoLoginSchemesConfiguredForThisClient": "沒有為此客戶端配置登入方案.", + "LogInUsingYourProviderAccount": "使用你的{0}帳號登入", + "DisplayName:CurrentPassword": "目前密碼", + "DisplayName:NewPassword": "新密碼", + "DisplayName:NewPasswordConfirm": "確認新密碼", + "PasswordChangedMessage": "你的密碼已修改成功.", + "DisplayName:UserName": "使用者名稱", + "DisplayName:Email": "電子信箱", + "DisplayName:Name": "名字", + "DisplayName:Surname": "姓", + "DisplayName:Password": "密碼", + "DisplayName:EmailAddress": "電子信箱地址", + "DisplayName:PhoneNumber": "電話號碼", + "PersonalSettings": "個人設置", + "PersonalSettingsSaved": "個人設置已保存", + "PasswordChanged": "修改密碼", + "NewPasswordConfirmFailed": "請確認新密碼", + "Manage": "管理", + "ManageYourProfile": "管理你的個人資料", + "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "啟用自行註冊", + "Description:Abp.Account.IsSelfRegistrationEnabled": "是否允許使用者自行註冊帳號.", + "DisplayName:Abp.Account.EnableLocalLogin": "使用本地帳號進行身分驗證", + "Description:Abp.Account.EnableLocalLogin": "伺服器是否允許使用者使用本地帳號進行身份驗證。" + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Settings/AccountSettingNames.cs similarity index 84% rename from modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs rename to modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Settings/AccountSettingNames.cs index a167be0ce8..d2596fd33d 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Settings/AccountSettingNames.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.Account.Web.Settings +namespace Volo.Abp.Account.Settings { public class AccountSettingNames { diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs index eba47666a4..9935078fe1 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs @@ -1,7 +1,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; +using Volo.Abp.Account.Settings; using Volo.Abp.Application.Services; using Volo.Abp.Identity; +using Volo.Abp.Settings; namespace Volo.Abp.Account { @@ -17,11 +19,21 @@ namespace Volo.Abp.Account public virtual async Task RegisterAsync(RegisterDto input) { + await CheckSelfRegistrationAsync().ConfigureAwait(false); + var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.EmailAddress, CurrentTenant.Id); - (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); + (await UserManager.CreateAsync(user, input.Password).ConfigureAwait(false)).CheckErrors(); return ObjectMapper.Map(user); } + + protected virtual async Task CheckSelfRegistrationAsync() + { + if (!await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled).ConfigureAwait(false)) + { + throw new UserFriendlyException(L["SelfRegistrationDisabledMessage"]); + } + } } } diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Settings/AccountSettingDefinitionProvider.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Settings/AccountSettingDefinitionProvider.cs new file mode 100644 index 0000000000..907100c61a --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Settings/AccountSettingDefinitionProvider.cs @@ -0,0 +1,33 @@ +using Volo.Abp.Account.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Settings; + +namespace Volo.Abp.Account.Settings +{ + public class AccountSettingDefinitionProvider : SettingDefinitionProvider + { + public override void Define(ISettingDefinitionContext context) + { + context.Add( + new SettingDefinition( + AccountSettingNames.IsSelfRegistrationEnabled, + "true", + L("DisplayName:Abp.Account.IsSelfRegistrationEnabled"), + L("Description:Abp.Account.IsSelfRegistrationEnabled"), isVisibleToClients : true) + ); + + context.Add( + new SettingDefinition( + AccountSettingNames.EnableLocalLogin, + "true", + L("DisplayName:Abp.Account.EnableLocalLogin"), + L("Description:Abp.Account.EnableLocalLogin"), isVisibleToClients : true) + ); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index f1abf44750..2fa2aa5778 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -12,7 +12,7 @@ using System.Linq; using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; -using Volo.Abp.Account.Web.Settings; +using Volo.Abp.Account.Settings; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; @@ -46,7 +46,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { LoginInput = new LoginInputModel(); - var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl); + var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl).ConfigureAwait(false); if (context != null) { @@ -68,7 +68,7 @@ namespace Volo.Abp.Account.Web.Pages.Account return Page(); } - var schemes = await _schemeProvider.GetAllSchemesAsync(); + var schemes = await _schemeProvider.GetAllSchemesAsync().ConfigureAwait(false); var providers = schemes .Where(x => x.DisplayName != null || x.Name.Equals(_accountOptions.WindowsAuthenticationSchemeName, StringComparison.OrdinalIgnoreCase)) @@ -79,10 +79,10 @@ namespace Volo.Abp.Account.Web.Pages.Account }) .ToList(); - EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin).ConfigureAwait(false); if (context?.ClientId != null) { - var client = await ClientStore.FindEnabledClientByIdAsync(context.ClientId); + var client = await ClientStore.FindEnabledClientByIdAsync(context.ClientId).ConfigureAwait(false); if (client != null) { EnableLocalLogin = client.EnableLocalLogin; @@ -98,7 +98,7 @@ namespace Volo.Abp.Account.Web.Pages.Account if (IsExternalLoginOnly) { - return await base.OnPostExternalLogin(providers.First().AuthenticationScheme); + return await base.OnPostExternalLogin(providers.First().AuthenticationScheme).ConfigureAwait(false); } return Page(); @@ -107,31 +107,31 @@ namespace Volo.Abp.Account.Web.Pages.Account [UnitOfWork] //TODO: Will be removed when we implement action filter public override async Task OnPostAsync(string action) { - EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin).ConfigureAwait(false); if (action == "Cancel") { - var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl); + var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl).ConfigureAwait(false); if (context == null) { return Redirect("~/"); } - await Interaction.GrantConsentAsync(context, ConsentResponse.Denied); + await Interaction.GrantConsentAsync(context, ConsentResponse.Denied).ConfigureAwait(false); return Redirect(ReturnUrl); } ValidateModel(); - await ReplaceEmailToUsernameOfInputIfNeeds(); + await ReplaceEmailToUsernameOfInputIfNeeds().ConfigureAwait(false); var result = await SignInManager.PasswordSignInAsync( LoginInput.UserNameOrEmailAddress, LoginInput.Password, LoginInput.RememberMe, true - ); + ).ConfigureAwait(false); if (result.RequiresTwoFactor) { @@ -162,11 +162,11 @@ namespace Volo.Abp.Account.Web.Pages.Account } //TODO: Find a way of getting user's id from the logged in user and do not query it again like that! - var user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress) ?? - await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress); + var user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false) ?? + await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false); Debug.Assert(user != null, nameof(user) + " != null"); - await IdentityServerEvents.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName)); //TODO: Use user's name once implemented + await IdentityServerEvents.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName)).ConfigureAwait(false); //TODO: Use user's name once implemented return RedirectSafely(ReturnUrl, ReturnUrlHash); } @@ -176,15 +176,15 @@ namespace Volo.Abp.Account.Web.Pages.Account { if (_accountOptions.WindowsAuthenticationSchemeName == provider) { - return await ProcessWindowsLoginAsync(); + return await ProcessWindowsLoginAsync().ConfigureAwait(false); } - return await base.OnPostExternalLogin(provider); + return await base.OnPostExternalLogin(provider).ConfigureAwait(false); } private async Task ProcessWindowsLoginAsync() { - var result = await HttpContext.AuthenticateAsync(_accountOptions.WindowsAuthenticationSchemeName); + var result = await HttpContext.AuthenticateAsync(_accountOptions.WindowsAuthenticationSchemeName).ConfigureAwait(false); if (!(result?.Principal is WindowsPrincipal windowsPrincipal)) { return Challenge(_accountOptions.WindowsAuthenticationSchemeName); @@ -219,7 +219,7 @@ namespace Volo.Abp.Account.Web.Pages.Account IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme, new ClaimsPrincipal(identity), props - ); + ).ConfigureAwait(false); return RedirectSafely(props.RedirectUri); } diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs new file mode 100644 index 0000000000..3190834fec --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs @@ -0,0 +1,44 @@ +using IdentityServer4.Services; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Account.Web.Pages.Account +{ + [ExposeServices(typeof(LogoutModel))] + public class IdentityServerSupportedLogoutModel : LogoutModel + { + protected IIdentityServerInteractionService Interaction { get; } + + public IdentityServerSupportedLogoutModel(IIdentityServerInteractionService interaction) + { + Interaction = interaction; + } + + public override async Task OnGetAsync() + { + await SignInManager.SignOutAsync().ConfigureAwait(false); + + var logoutId = Request.Query["logoutId"].ToString(); + + if (!string.IsNullOrEmpty(logoutId)) + { + var logoutContext = await Interaction.GetLogoutContextAsync(logoutId).ConfigureAwait(false); + + var postLogoutUri = logoutContext.PostLogoutRedirectUri; + + if (!string.IsNullOrEmpty(postLogoutUri)) + { + return Redirect(postLogoutUri); + } + } + + if (ReturnUrl != null) + { + return LocalRedirect(ReturnUrl); + } + + return RedirectToPage("/Account/Login"); + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs index 3fb68feaca..e34f6e98f1 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml.cs @@ -44,19 +44,19 @@ namespace Volo.Abp.Account.Web.Pages public virtual async Task OnGet() { - var request = await _interaction.GetAuthorizationContextAsync(ReturnUrl); + var request = await _interaction.GetAuthorizationContextAsync(ReturnUrl).ConfigureAwait(false); if (request == null) { throw new ApplicationException($"No consent request matching request: {ReturnUrl}"); } - var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId); + var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId).ConfigureAwait(false); if (client == null) { throw new ApplicationException($"Invalid client id: {request.ClientId}"); } - var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested); + var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested).ConfigureAwait(false); if (resources == null || (!resources.IdentityResources.Any() && !resources.ApiResources.Any())) { throw new ApplicationException($"No scopes matching: {request.ScopesRequested.Aggregate((x, y) => x + ", " + y)}"); @@ -78,7 +78,7 @@ namespace Volo.Abp.Account.Web.Pages public virtual async Task OnPost(string userDecision) { - var result = await ProcessConsentAsync(); + var result = await ProcessConsentAsync().ConfigureAwait(false); if (result.IsRedirect) { @@ -122,13 +122,13 @@ namespace Volo.Abp.Account.Web.Pages if (grantedConsent != null) { - var request = await _interaction.GetAuthorizationContextAsync(ReturnUrl); + var request = await _interaction.GetAuthorizationContextAsync(ReturnUrl).ConfigureAwait(false); if (request == null) { return result; } - await _interaction.GrantConsentAsync(request, grantedConsent); + await _interaction.GrantConsentAsync(request, grantedConsent).ConfigureAwait(false); result.RedirectUri = ReturnUrl; //TODO: ReturnUrlHash? } diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs index 05f37067d4..d1f433e343 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs @@ -34,14 +34,14 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers { ValidateLoginInfo(login); - await ReplaceEmailToUsernameOfInputIfNeeds(login); + await ReplaceEmailToUsernameOfInputIfNeeds(login).ConfigureAwait(false); return GetAbpLoginResult(await _signInManager.PasswordSignInAsync( login.UserNameOrEmailAddress, login.Password, login.RememberMe, true - )); + ).ConfigureAwait(false)); } [HttpPost] @@ -50,32 +50,32 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers { ValidateLoginInfo(login); - await ReplaceEmailToUsernameOfInputIfNeeds(login); + await ReplaceEmailToUsernameOfInputIfNeeds(login).ConfigureAwait(false); - var identityUser = await _userManager.FindByNameAsync(login.UserNameOrEmailAddress); + var identityUser = await _userManager.FindByNameAsync(login.UserNameOrEmailAddress).ConfigureAwait(false); if (identityUser == null) { return new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword); } - return GetAbpLoginResult(await _signInManager.CheckPasswordSignInAsync(identityUser, login.Password, true)); + return GetAbpLoginResult(await _signInManager.CheckPasswordSignInAsync(identityUser, login.Password, true).ConfigureAwait(false)); } protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds(UserLoginInfo login) { - if (!ValidationHandler.IsValidEmailAddress(login.UserNameOrEmailAddress)) + if (!ValidationHelper.IsValidEmailAddress(login.UserNameOrEmailAddress)) { return; } - var userByUsername = await _userManager.FindByNameAsync(login.UserNameOrEmailAddress); + var userByUsername = await _userManager.FindByNameAsync(login.UserNameOrEmailAddress).ConfigureAwait(false); if (userByUsername != null) { return; } - var userByEmail = await _userManager.FindByEmailAsync(login.UserNameOrEmailAddress); + var userByEmail = await _userManager.FindByEmailAsync(login.UserNameOrEmailAddress).ConfigureAwait(false); if (userByEmail == null) { return; diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs deleted file mode 100644 index eb7d1cbc84..0000000000 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using IdentityUser = Volo.Abp.Identity.IdentityUser; - -namespace Volo.Abp.Account.Web.Areas.Account.Controllers -{ - [Area("Account")] - public class LogoutController : AbpController - { - private readonly SignInManager _signInManager; - - public LogoutController(SignInManager signInManager) - { - _signInManager = signInManager; - } - - //todo@alper: this method can be moved to AccountController like "account/logout" - public async Task Index(string returnUrl = null) - { - await _signInManager.SignOutAsync(); - - if (returnUrl != null) - { - return LocalRedirect(returnUrl); - } - - return RedirectToPage("/Account/Login"); - } - } -} diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml index cba1fec431..fca4622a29 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml @@ -1,5 +1,6 @@ @page -@using Volo.Abp.Account.Web.Settings +@using Volo.Abp.Account.Settings +@using Volo.Abp.Settings @model Volo.Abp.Account.Web.Pages.Account.LoginModel @inherits Volo.Abp.Account.Web.Pages.Account.AccountPage @inject Volo.Abp.Settings.ISettingProvider SettingProvider @@ -7,8 +8,8 @@ {
    -

    @L["Login"]

    - @if (string.Equals(await SettingProvider.GetOrNullAsync(AccountSettingNames.IsSelfRegistrationEnabled), "true", StringComparison.OrdinalIgnoreCase)) +

    @L["Login"]

    + @if (await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled)) { @L["AreYouANewUser"] diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index e7e625416a..eb4ad4ad04 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -10,7 +10,7 @@ using System.Diagnostics; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; -using Volo.Abp.Account.Web.Settings; +using Volo.Abp.Account.Settings; using Volo.Abp.Identity; using Volo.Abp.Security.Claims; using Volo.Abp.Settings; @@ -62,7 +62,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { LoginInput = new LoginInputModel(); - var schemes = await _schemeProvider.GetAllSchemesAsync(); + var schemes = await _schemeProvider.GetAllSchemesAsync().ConfigureAwait(false); var providers = schemes .Where(x => x.DisplayName != null || x.Name.Equals(_accountOptions.WindowsAuthenticationSchemeName, StringComparison.OrdinalIgnoreCase)) @@ -73,7 +73,7 @@ namespace Volo.Abp.Account.Web.Pages.Account }) .ToList(); - EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin).ConfigureAwait(false); ExternalProviders = providers.ToArray(); @@ -89,18 +89,18 @@ namespace Volo.Abp.Account.Web.Pages.Account [UnitOfWork] //TODO: Will be removed when we implement action filter public virtual async Task OnPostAsync(string action) { - EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin).ConfigureAwait(false); ValidateModel(); - await ReplaceEmailToUsernameOfInputIfNeeds(); + await ReplaceEmailToUsernameOfInputIfNeeds().ConfigureAwait(false); var result = await SignInManager.PasswordSignInAsync( LoginInput.UserNameOrEmailAddress, LoginInput.Password, LoginInput.RememberMe, true - ); + ).ConfigureAwait(false); if (result.RequiresTwoFactor) { @@ -131,8 +131,8 @@ namespace Volo.Abp.Account.Web.Pages.Account } //TODO: Find a way of getting user's id from the logged in user and do not query it again like that! - var user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress) ?? - await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress); + var user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false) ?? + await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false); Debug.Assert(user != null, nameof(user) + " != null"); @@ -163,7 +163,7 @@ namespace Volo.Abp.Account.Web.Pages.Account return RedirectToPage("./Login"); } - var loginInfo = await SignInManager.GetExternalLoginInfoAsync(); + var loginInfo = await SignInManager.GetExternalLoginInfoAsync().ConfigureAwait(false); if (loginInfo == null) { Logger.LogWarning("External login info is not available"); @@ -175,7 +175,7 @@ namespace Volo.Abp.Account.Web.Pages.Account loginInfo.ProviderKey, isPersistent: false, bypassTwoFactor: true - ); + ).ConfigureAwait(false); if (result.IsLockedOut) { @@ -190,15 +190,15 @@ namespace Volo.Abp.Account.Web.Pages.Account //TODO: Handle other cases for result! // Get the information about the user from the external login provider - var info = await SignInManager.GetExternalLoginInfoAsync(); + var info = await SignInManager.GetExternalLoginInfoAsync().ConfigureAwait(false); if (info == null) { throw new ApplicationException("Error loading external login information during confirmation."); } - var user = await CreateExternalUserAsync(info); + var user = await CreateExternalUserAsync(info).ConfigureAwait(false); - await SignInManager.SignInAsync(user, false); + await SignInManager.SignInAsync(user, false).ConfigureAwait(false); return RedirectSafely(returnUrl, returnUrlHash); } @@ -208,27 +208,27 @@ namespace Volo.Abp.Account.Web.Pages.Account var user = new IdentityUser(GuidGenerator.Create(), emailAddress, emailAddress, CurrentTenant.Id); - CheckIdentityErrors(await UserManager.CreateAsync(user)); - CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress)); - CheckIdentityErrors(await UserManager.AddLoginAsync(user, info)); + CheckIdentityErrors(await UserManager.CreateAsync(user).ConfigureAwait(false)); + CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress).ConfigureAwait(false)); + CheckIdentityErrors(await UserManager.AddLoginAsync(user, info).ConfigureAwait(false)); return user; } protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds() { - if (!ValidationHandler.IsValidEmailAddress(LoginInput.UserNameOrEmailAddress)) + if (!ValidationHelper.IsValidEmailAddress(LoginInput.UserNameOrEmailAddress)) { return; } - var userByUsername = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress); + var userByUsername = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false); if (userByUsername != null) { return; } - var userByEmail = await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress); + var userByEmail = await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false); if (userByEmail == null) { return; diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml new file mode 100644 index 0000000000..f57c7258d1 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml @@ -0,0 +1,3 @@ +@page "/Account/Logout" +@inherits Volo.Abp.Account.Web.Pages.Account.AccountPage +@model Volo.Abp.Account.Web.Pages.Account.LogoutModel \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs new file mode 100644 index 0000000000..6825457a7e --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.Account.Web.Pages.Account +{ + public class LogoutModel : AccountPageModel + { + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ReturnUrl { get; set; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ReturnUrlHash { get; set; } + + public virtual async Task OnGetAsync() + { + await SignInManager.SignOutAsync().ConfigureAwait(false); + if (ReturnUrl != null) + { + return RedirectSafely(ReturnUrl, ReturnUrlHash); + } + + return RedirectToPage("/Account/Login"); + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml.cs index 9fba470929..7c94f747cd 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Account.Web.Pages.Account public async Task OnGetAsync() { - var user = await _profileAppService.GetAsync(); + var user = await _profileAppService.GetAsync().ConfigureAwait(false); PersonalSettingsInfoModel = ObjectMapper.Map(user); } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs index 1a16cecc2a..40b819e0e1 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs @@ -2,7 +2,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using Volo.Abp.Account.Web.Settings; +using Volo.Abp.Account.Settings; +using Volo.Abp.Identity; using Volo.Abp.Settings; using Volo.Abp.Uow; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -22,7 +23,7 @@ namespace Volo.Abp.Account.Web.Pages.Account public virtual async Task OnGet() { - await CheckSelfRegistrationAsync(); + await CheckSelfRegistrationAsync().ConfigureAwait(false); } [UnitOfWork] //TODO: Will be removed when we implement action filter @@ -30,22 +31,23 @@ namespace Volo.Abp.Account.Web.Pages.Account { ValidateModel(); - await CheckSelfRegistrationAsync(); + await CheckSelfRegistrationAsync().ConfigureAwait(false); var user = new IdentityUser(GuidGenerator.Create(), Input.UserName, Input.EmailAddress, CurrentTenant.Id); - (await UserManager.CreateAsync(user, Input.Password)).CheckErrors(); - - await UserManager.SetEmailAsync(user, Input.EmailAddress); + (await UserManager.CreateAsync(user, Input.Password).ConfigureAwait(false)).CheckErrors(); + + await UserManager.SetEmailAsync(user, Input.EmailAddress).ConfigureAwait(false); - await SignInManager.SignInAsync(user, isPersistent: false); + await SignInManager.SignInAsync(user, isPersistent: false).ConfigureAwait(false); return Redirect(ReturnUrl ?? "/"); //TODO: How to ensure safety? IdentityServer requires it however it should be checked somehow! } protected virtual async Task CheckSelfRegistrationAsync() { - if (!await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled)) + if (!await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled).ConfigureAwait(false) || + !await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin).ConfigureAwait(false)) { throw new UserFriendlyException(L["SelfRegistrationDisabledMessage"]); } @@ -54,16 +56,16 @@ namespace Volo.Abp.Account.Web.Pages.Account public class PostInput { [Required] - [StringLength(32)] + [StringLength(IdentityUserConsts.MaxUserNameLength)] public string UserName { get; set; } [Required] [EmailAddress] - [StringLength(255)] + [StringLength(IdentityUserConsts.MaxEmailLength)] public string EmailAddress { get; set; } [Required] - [StringLength(32)] + [StringLength(IdentityUserConsts.MaxPasswordLength)] [DataType(DataType.Password)] public string Password { get; set; } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/SendSecurityCode.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/SendSecurityCode.cshtml.cs index 5923d8972c..ab8abd4853 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/SendSecurityCode.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/SendSecurityCode.cshtml.cs @@ -14,7 +14,7 @@ namespace Volo.Abp.Account.Web.Pages.Account public async Task OnGetAsync() { - var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); + var user = await SignInManager.GetTwoFactorAuthenticationUserAsync().ConfigureAwait(false); if (user == null) { return RedirectToPage("./Login"); diff --git a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs b/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs deleted file mode 100644 index be16fa7045..0000000000 --- a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Volo.Abp.Settings; - -namespace Volo.Abp.Account.Web.Settings -{ - public class AccountSettingDefinitionProvider : SettingDefinitionProvider - { - public override void Define(ISettingDefinitionContext context) - { - context.Add( - new SettingDefinition(AccountSettingNames.IsSelfRegistrationEnabled, "true") - ); - - context.Add( - new SettingDefinition(AccountSettingNames.EnableLocalLogin, "true") - ); - } - } -} \ No newline at end of file diff --git a/modules/account/test/Volo.Abp.Account.Application.Tests/Volo.Abp.Account.Application.Tests.csproj b/modules/account/test/Volo.Abp.Account.Application.Tests/Volo.Abp.Account.Application.Tests.csproj index c8b85dcaee..2055dfc4ef 100644 --- a/modules/account/test/Volo.Abp.Account.Application.Tests/Volo.Abp.Account.Application.Tests.csproj +++ b/modules/account/test/Volo.Abp.Account.Application.Tests/Volo.Abp.Account.Application.Tests.csproj @@ -2,10 +2,11 @@ netcoreapp3.1 + - + diff --git a/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AbpAccountApplicationTestBase.cs b/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AbpAccountApplicationTestBase.cs index 38f1506a76..99a2eed68e 100644 --- a/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AbpAccountApplicationTestBase.cs +++ b/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AbpAccountApplicationTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.Account +using Volo.Abp.Testing; + +namespace Volo.Abp.Account { public class AbpAccountApplicationTestBase : AbpIntegratedTest { diff --git a/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AccountAppService_Tests.cs b/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AccountAppService_Tests.cs index 634cbfc253..14d257993c 100644 --- a/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AccountAppService_Tests.cs +++ b/modules/account/test/Volo.Abp.Account.Application.Tests/Volo/Abp/Account/AccountAppService_Tests.cs @@ -4,7 +4,7 @@ using Shouldly; using Volo.Abp.Identity; using Xunit; -namespace Volo.Abp.Account.Pro.Application.Tests.Volo.Abp.Account +namespace Volo.Abp.Account { public class AccountAppService_Tests : AbpAccountApplicationTestBase { @@ -12,8 +12,7 @@ namespace Volo.Abp.Account.Pro.Application.Tests.Volo.Abp.Account private readonly IIdentityUserRepository _identityUserRepository; private readonly ILookupNormalizer _lookupNormalizer; private readonly IdentityUserManager _userManager; - - + public AccountAppService_Tests() { _accountAppService = GetRequiredService(); @@ -33,16 +32,16 @@ namespace Volo.Abp.Account.Pro.Application.Tests.Volo.Abp.Account AppName = "MVC" }; - await _accountAppService.RegisterAsync(registerDto); + await _accountAppService.RegisterAsync(registerDto).ConfigureAwait(false); var user = await _identityUserRepository.FindByNormalizedUserNameAsync( - _lookupNormalizer.NormalizeName("bob.lee")); + _lookupNormalizer.NormalizeName("bob.lee")).ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("bob.lee"); user.Email.ShouldBe("bob.lee@abp.io"); - (await _userManager.CheckPasswordAsync(user, "P@ssW0rd")).ShouldBeTrue(); + (await _userManager.CheckPasswordAsync(user, "P@ssW0rd").ConfigureAwait(false)).ShouldBeTrue(); } } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo.Abp.AuditLogging.Domain.Shared.csproj b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo.Abp.AuditLogging.Domain.Shared.csproj index b1d7f04bbf..44c36fd1d1 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo.Abp.AuditLogging.Domain.Shared.csproj +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo.Abp.AuditLogging.Domain.Shared.csproj @@ -8,7 +8,6 @@ - diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AbpAuditLoggingDomainSharedModule.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AbpAuditLoggingDomainSharedModule.cs index efa043efd1..ca0209a620 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AbpAuditLoggingDomainSharedModule.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AbpAuditLoggingDomainSharedModule.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AuditLogging.Localization; +using Volo.Abp.AuditLogging.Localization; using Volo.Abp.Localization; using Volo.Abp.Modularity; diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditingStore.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditingStore.cs index 7bbd51af12..50380549dc 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditingStore.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditingStore.cs @@ -33,47 +33,21 @@ namespace Volo.Abp.AuditLogging Logger = NullLogger.Instance; } - public void Save(AuditLogInfo auditInfo) - { - if (!Options.HideErrors) - { - SaveLog(auditInfo); - return; - } - - try - { - SaveLog(auditInfo); - } - catch (Exception ex) - { - Logger.LogException(ex, LogLevel.Error); - } - } - - protected virtual void SaveLog(AuditLogInfo auditInfo) - { - using (var uow = _unitOfWorkManager.Begin(true)) - { - _auditLogRepository.Insert(new AuditLog(_guidGenerator, auditInfo)); - uow.SaveChanges(); - } - } - public async Task SaveAsync(AuditLogInfo auditInfo) { if (!Options.HideErrors) { - await SaveLogAsync(auditInfo); + await SaveLogAsync(auditInfo).ConfigureAwait(false); return; } try { - await SaveLogAsync(auditInfo); + await SaveLogAsync(auditInfo).ConfigureAwait(false); } catch (Exception ex) { + Logger.LogWarning("Could not save the audit log object: " + Environment.NewLine + auditInfo.ToString()); Logger.LogException(ex, LogLevel.Error); } } @@ -82,8 +56,8 @@ namespace Volo.Abp.AuditLogging { using (var uow = _unitOfWorkManager.Begin(true)) { - await _auditLogRepository.InsertAsync(new AuditLog(_guidGenerator, auditInfo)); - await uow.SaveChangesAsync(); + await _auditLogRepository.InsertAsync(new AuditLog(_guidGenerator, auditInfo)).ConfigureAwait(false); + await uow.SaveChangesAsync().ConfigureAwait(false); } } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.csproj b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.csproj index 93422d8f3f..ff72eb23da 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.csproj +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs index 094f946777..0b68932224 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs @@ -54,7 +54,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore var auditLogs = await query.OrderBy(sorting ?? "executionTime desc") .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); return auditLogs; } @@ -87,7 +87,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore httpStatusCode ); - var totalCount = await query.LongCountAsync(GetCancellationToken(cancellationToken)); + var totalCount = await query.LongCountAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); return totalCount; } @@ -129,7 +129,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore .OrderBy(t => t.ExecutionTime) .GroupBy(t => new { t.ExecutionTime.Date }) .Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) }) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime); } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs index 8beeff86a3..51ae55d86a 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs @@ -55,7 +55,7 @@ namespace Volo.Abp.AuditLogging.MongoDB return await query.OrderBy(sorting ?? "executionTime desc").As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task GetCountAsync( @@ -87,7 +87,7 @@ namespace Volo.Abp.AuditLogging.MongoDB ); var count = await query.As>() - .LongCountAsync(GetCancellationToken(cancellationToken)); + .LongCountAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); return count; } @@ -134,7 +134,7 @@ namespace Volo.Abp.AuditLogging.MongoDB t.ExecutionTime.Day }) .Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) }) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime); } diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests.csproj b/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests.csproj index 27d4817501..8ee9a2e2f6 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests.csproj +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogRepository_Tests.cs b/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogRepository_Tests.cs index 4f626c3636..7330e3292e 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogRepository_Tests.cs +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogRepository_Tests.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Volo.Abp.AuditLogging.EntityFrameworkCore +namespace Volo.Abp.AuditLogging.EntityFrameworkCore { public class AuditLogRepository_Tests : AuditLogRepository_Tests { diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.csproj b/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.csproj index 37eaac2693..b5c7084cf2 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.csproj +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo.Abp.AuditLogging.TestBase.csproj b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo.Abp.AuditLogging.TestBase.csproj index 7068fcf8e5..157301aecb 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo.Abp.AuditLogging.TestBase.csproj +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo.Abp.AuditLogging.TestBase.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogRepository_Tests.cs b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogRepository_Tests.cs index 3f61988ec0..1af259d082 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogRepository_Tests.cs +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogRepository_Tests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; -using System.Text; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Auditing; @@ -119,11 +118,11 @@ namespace Volo.Abp.AuditLogging } }; - AuditLogRepository.Insert(new AuditLog(GuidGenerator, log1)); - AuditLogRepository.Insert(new AuditLog(GuidGenerator, log2)); + await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1)).ConfigureAwait(false); + await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2)).ConfigureAwait(false); //Assert - var logs = await AuditLogRepository.GetListAsync(); + var logs = await AuditLogRepository.GetListAsync().ConfigureAwait(false); logs.ShouldNotBeNull(); logs.ShouldContain(x => x.UserId == userId); logs.ShouldContain(x => x.UserId == userId2); @@ -223,11 +222,11 @@ namespace Volo.Abp.AuditLogging } }; - AuditLogRepository.Insert(new AuditLog(GuidGenerator, log1)); - AuditLogRepository.Insert(new AuditLog(GuidGenerator, log2)); + await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1)).ConfigureAwait(false); + await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2)).ConfigureAwait(false); //Assert - var logs = await AuditLogRepository.GetCountAsync(); + var logs = await AuditLogRepository.GetCountAsync().ConfigureAwait(false); logs.ShouldBe(2); } @@ -245,7 +244,7 @@ namespace Volo.Abp.AuditLogging UserId = userId, ImpersonatorUserId = Guid.NewGuid(), ImpersonatorTenantId = Guid.NewGuid(), - ExecutionTime = DateTime.Parse("2020-01-01 01:00:00"), + ExecutionTime = DateTime.SpecifyKind(DateTime.Parse("2020-01-01 01:00:00"), DateTimeKind.Utc), ExecutionDuration = 45, ClientIpAddress = ipAddress, ClientName = "MyDesktop", @@ -296,7 +295,7 @@ namespace Volo.Abp.AuditLogging UserId = userId2, ImpersonatorUserId = Guid.NewGuid(), ImpersonatorTenantId = Guid.NewGuid(), - ExecutionTime = DateTime.Parse("2020-01-01 03:00:00"), + ExecutionTime = DateTime.SpecifyKind(DateTime.Parse("2020-01-01 03:00:00"), DateTimeKind.Utc), ExecutionDuration = 55, ClientIpAddress = ipAddress, ClientName = "MyDesktop", @@ -325,12 +324,12 @@ namespace Volo.Abp.AuditLogging } }; - AuditLogRepository.Insert(new AuditLog(GuidGenerator, log1)); - AuditLogRepository.Insert(new AuditLog(GuidGenerator, log2)); + await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log1)).ConfigureAwait(false); + await AuditLogRepository.InsertAsync(new AuditLog(GuidGenerator, log2)).ConfigureAwait(false); //Assert var date = DateTime.Parse("2020-01-01"); - var results = await AuditLogRepository.GetAverageExecutionDurationPerDayAsync(date, date); + var results = await AuditLogRepository.GetAverageExecutionDurationPerDayAsync(date, date).ConfigureAwait(false); results.Count.ShouldBe(1); results.Values.First().ShouldBe(50); // (45 + 55) / 2 } diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLoggingTestBase.cs b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLoggingTestBase.cs index 6cbe6bd126..f7378f74dc 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLoggingTestBase.cs +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLoggingTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.AuditLogging { diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditStore_Basic_Tests.cs b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditStore_Basic_Tests.cs index c54d98608c..9744930c09 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditStore_Basic_Tests.cs +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditStore_Basic_Tests.cs @@ -64,11 +64,11 @@ namespace Volo.Abp.AuditLogging }; //Act - await _auditingStore.SaveAsync(auditLog); + await _auditingStore.SaveAsync(auditLog).ConfigureAwait(false); //Assert - var insertedLog = _auditLogRepository.GetList(true) + var insertedLog = (await _auditLogRepository.GetListAsync(true)) .FirstOrDefault(al => al.UserId == userId); insertedLog.ShouldNotBeNull(); @@ -170,14 +170,14 @@ namespace Volo.Abp.AuditLogging } }; - await _auditingStore.SaveAsync(log1); - await _auditingStore.SaveAsync(log2); + await _auditingStore.SaveAsync(log1).ConfigureAwait(false); + await _auditingStore.SaveAsync(log2).ConfigureAwait(false); - var allLogsCount = await _auditLogRepository.GetCountAsync(); + var allLogsCount = await _auditLogRepository.GetCountAsync().ConfigureAwait(false); - var onlyLog1QueryResult = await _auditLogRepository.GetListAsync(includeDetails: true, userName: "Douglas"); + var onlyLog1QueryResult = await _auditLogRepository.GetListAsync(includeDetails: true, userName: "Douglas").ConfigureAwait(false); - var onlyLog2QueryResult = await _auditLogRepository.GetListAsync(includeDetails: true, httpStatusCode: HttpStatusCode.BadGateway); + var onlyLog2QueryResult = await _auditLogRepository.GetListAsync(includeDetails: true, httpStatusCode: HttpStatusCode.BadGateway).ConfigureAwait(false); allLogsCount.ShouldBe(2); diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo.Abp.AuditLogging.Tests.csproj b/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo.Abp.AuditLogging.Tests.csproj index ccaef6bd0e..31a70aa5b1 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo.Abp.AuditLogging.Tests.csproj +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo.Abp.AuditLogging.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs b/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs index 6e92bc6f7f..04c885be20 100644 --- a/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs +++ b/modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs @@ -59,12 +59,12 @@ namespace Volo.Abp.AuditLogging } ); - await scope.SaveAsync(); + await scope.SaveAsync().ConfigureAwait(false); } //Assert - var auditLogs = await _auditLogRepository.GetListAsync(applicationName: applicationName, includeDetails: true); + var auditLogs = await _auditLogRepository.GetListAsync(applicationName: applicationName, includeDetails: true).ConfigureAwait(false); auditLogs.Count.ShouldBe(1); var auditLog = auditLogs.First(); auditLog.EntityChanges.ShouldNotBeNull(); diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Volo.Abp.BackgroundJobs.DemoApp.HangFire.csproj b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Volo.Abp.BackgroundJobs.DemoApp.HangFire.csproj index 3c2388a914..3490b31f67 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Volo.Abp.BackgroundJobs.DemoApp.HangFire.csproj +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Volo.Abp.BackgroundJobs.DemoApp.HangFire.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/SampleJobCreator.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/SampleJobCreator.cs index b131c5943d..3c05c4abd3 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/SampleJobCreator.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/SampleJobCreator.cs @@ -20,10 +20,10 @@ namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs public async Task CreateJobsAsync() { - await _backgroundJobManager.EnqueueAsync(new WriteToConsoleGreenJobArgs { Value = "test 1 (green)" }); - await _backgroundJobManager.EnqueueAsync(new WriteToConsoleGreenJobArgs { Value = "test 2 (green)" }); - await _backgroundJobManager.EnqueueAsync(new WriteToConsoleYellowJobArgs { Value = "test 1 (yellow)" }); - await _backgroundJobManager.EnqueueAsync(new WriteToConsoleYellowJobArgs { Value = "test 2 (yellow)" }); + await _backgroundJobManager.EnqueueAsync(new WriteToConsoleGreenJobArgs { Value = "test 1 (green)" }).ConfigureAwait(false); + await _backgroundJobManager.EnqueueAsync(new WriteToConsoleGreenJobArgs { Value = "test 2 (green)" }).ConfigureAwait(false); + await _backgroundJobManager.EnqueueAsync(new WriteToConsoleYellowJobArgs { Value = "test 1 (yellow)" }).ConfigureAwait(false); + await _backgroundJobManager.EnqueueAsync(new WriteToConsoleYellowJobArgs { Value = "test 2 (yellow)" }).ConfigureAwait(false); } } } diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs index 833ce54a6b..2fe3a0fdda 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs @@ -20,80 +20,42 @@ namespace Volo.Abp.BackgroundJobs BackgroundJobRepository = backgroundJobRepository; } - public BackgroundJobInfo Find(Guid jobId) - { - return ObjectMapper.Map( - BackgroundJobRepository.Find(jobId) - ); - } - public virtual async Task FindAsync(Guid jobId) { return ObjectMapper.Map( await BackgroundJobRepository.FindAsync(jobId) - ); - } - - public void Insert(BackgroundJobInfo jobInfo) - { - BackgroundJobRepository.Insert( - ObjectMapper.Map(jobInfo) - ); +.ConfigureAwait(false)); } public virtual async Task InsertAsync(BackgroundJobInfo jobInfo) { await BackgroundJobRepository.InsertAsync( ObjectMapper.Map(jobInfo) - ); - } - - public List GetWaitingJobs(int maxResultCount) - { - return ObjectMapper.Map, List>( - BackgroundJobRepository.GetWaitingList(maxResultCount) - ); + ).ConfigureAwait(false); } public virtual async Task> GetWaitingJobsAsync(int maxResultCount) { return ObjectMapper.Map, List>( await BackgroundJobRepository.GetWaitingListAsync(maxResultCount) - ); - } - - public void Delete(Guid jobId) - { - BackgroundJobRepository.Delete(jobId); +.ConfigureAwait(false)); } public virtual async Task DeleteAsync(Guid jobId) { - await BackgroundJobRepository.DeleteAsync(jobId); - } - - public void Update(BackgroundJobInfo jobInfo) - { - var backgroundJobRecord = BackgroundJobRepository.Find(jobInfo.Id); - if (backgroundJobRecord == null) - { - return; - } - - ObjectMapper.Map(jobInfo, backgroundJobRecord); - BackgroundJobRepository.Update(backgroundJobRecord); + await BackgroundJobRepository.DeleteAsync(jobId).ConfigureAwait(false); } public virtual async Task UpdateAsync(BackgroundJobInfo jobInfo) { - var backgroundJobRecord = await BackgroundJobRepository.FindAsync(jobInfo.Id); + var backgroundJobRecord = await BackgroundJobRepository.FindAsync(jobInfo.Id).ConfigureAwait(false); if (backgroundJobRecord == null) { return; } ObjectMapper.Map(jobInfo, backgroundJobRecord); - await BackgroundJobRepository.UpdateAsync(backgroundJobRecord); + await BackgroundJobRepository.UpdateAsync(backgroundJobRecord).ConfigureAwait(false); } } } diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs index a34cbd6abb..e12aeff70a 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs @@ -7,8 +7,6 @@ namespace Volo.Abp.BackgroundJobs { public interface IBackgroundJobRepository : IBasicRepository { - List GetWaitingList(int maxResultCount); - Task> GetWaitingListAsync(int maxResultCount); } } \ No newline at end of file diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.csproj b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.csproj index eb92972675..1b3ed12524 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.csproj +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs index 8128d18bfb..22b8e6ab46 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs @@ -21,16 +21,10 @@ namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore Clock = clock; } - public List GetWaitingList(int maxResultCount) - { - return GetWaitingListQuery(maxResultCount) - .ToList(); - } - public async Task> GetWaitingListAsync(int maxResultCount) { return await GetWaitingListQuery(maxResultCount) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); } private IQueryable GetWaitingListQuery(int maxResultCount) diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs index fe3ffa7e07..cd266eeac4 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs @@ -21,16 +21,10 @@ namespace Volo.Abp.BackgroundJobs.MongoDB Clock = clock; } - public List GetWaitingList(int maxResultCount) - { - return GetWaitingListQuery(maxResultCount) - .ToList(); - } - public async Task> GetWaitingListAsync(int maxResultCount) { return await GetWaitingListQuery(maxResultCount) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); } private IMongoQueryable GetWaitingListQuery(int maxResultCount) diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo.Abp.BackgroundJobs.Domain.Tests.csproj b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo.Abp.BackgroundJobs.Domain.Tests.csproj index 917a1b1146..c7d43a8e71 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo.Abp.BackgroundJobs.Domain.Tests.csproj +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo.Abp.BackgroundJobs.Domain.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo/Abp/BackgroundJobs/BackgroundJobStore_Tests.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo/Abp/BackgroundJobs/BackgroundJobStore_Tests.cs index caa9a3c445..94b9375d83 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo/Abp/BackgroundJobs/BackgroundJobStore_Tests.cs +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.Domain.Tests/Volo/Abp/BackgroundJobs/BackgroundJobStore_Tests.cs @@ -26,9 +26,9 @@ namespace Volo.Abp.BackgroundJobs await _backgroundJobStore.InsertAsync( jobInfo - ); + ).ConfigureAwait(false); - var jobInfo2 = await _backgroundJobStore.FindAsync(jobInfo.Id); + var jobInfo2 = await _backgroundJobStore.FindAsync(jobInfo.Id).ConfigureAwait(false); jobInfo2.ShouldNotBeNull(); jobInfo2.Id.ShouldBe(jobInfo.Id); jobInfo2.JobArgs.ShouldBe(jobInfo.JobArgs); diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests.csproj b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests.csproj index 81998369e0..25434f3b06 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests.csproj +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests/Volo.Abp.BackgroundJobs.EntityFrameworkCore.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo.Abp.BackgroundJobs.MongoDB.Tests.csproj b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo.Abp.BackgroundJobs.MongoDB.Tests.csproj index 3802e0091c..faece9ea33 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo.Abp.BackgroundJobs.MongoDB.Tests.csproj +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo.Abp.BackgroundJobs.MongoDB.Tests.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo.Abp.BackgroundJobs.TestBase.csproj b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo.Abp.BackgroundJobs.TestBase.csproj index 445d3652ac..538f9376fb 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo.Abp.BackgroundJobs.TestBase.csproj +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo.Abp.BackgroundJobs.TestBase.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/AbpBackgroundJobsTestBaseModule.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/AbpBackgroundJobsTestBaseModule.cs index 0c1a681eeb..75e150dc25 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/AbpBackgroundJobsTestBaseModule.cs +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/AbpBackgroundJobsTestBaseModule.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Autofac; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs { @@ -28,9 +29,9 @@ namespace Volo.Abp.BackgroundJobs { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs index 59a2709edd..2187db533e 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobRepository_Tests.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.BackgroundJobs [InlineData(5)] public async Task GetWaitingListAsync(int maxResultCount) { - var backgroundJobs = await _backgroundJobRepository.GetWaitingListAsync(maxResultCount); + var backgroundJobs = await _backgroundJobRepository.GetWaitingListAsync(maxResultCount).ConfigureAwait(false); backgroundJobs.Count.ShouldBeGreaterThan(0); backgroundJobs.Count.ShouldBeLessThanOrEqualTo(maxResultCount); diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs index ea7b932a79..c87edcd788 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestBase.cs @@ -1,5 +1,6 @@ using Volo.Abp; using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.BackgroundJobs { diff --git a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs index dd74854a9c..90ec92ea35 100644 --- a/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs +++ b/modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo/Abp/BackgroundJobs/BackgroundJobsTestDataBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Timing; @@ -20,9 +21,9 @@ namespace Volo.Abp.BackgroundJobs _clock = clock; } - public void Build() + public async Task BuildAsync() { - _backgroundJobRepository.Insert( + await _backgroundJobRepository.InsertAsync( new BackgroundJobRecord(_testData.JobId1) { JobName = "TestJobName", @@ -34,9 +35,9 @@ namespace Volo.Abp.BackgroundJobs CreationTime = _clock.Now.Subtract(TimeSpan.FromMinutes(2)), TryCount = 0 } - ); + ).ConfigureAwait(false); - _backgroundJobRepository.Insert( + await _backgroundJobRepository.InsertAsync( new BackgroundJobRecord(_testData.JobId2) { JobName = "TestJobName", @@ -48,9 +49,9 @@ namespace Volo.Abp.BackgroundJobs CreationTime = _clock.Now.Subtract(TimeSpan.FromDays(2)), TryCount = 3 } - ); + ).ConfigureAwait(false); - _backgroundJobRepository.Insert( + await _backgroundJobRepository.InsertAsync( new BackgroundJobRecord(_testData.JobId3) { JobName = "TestJobName", @@ -62,7 +63,7 @@ namespace Volo.Abp.BackgroundJobs CreationTime = _clock.Now.Subtract(TimeSpan.FromMinutes(90)), TryCount = 2 } - ); + ).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/blogging/README.md b/modules/blogging/README.md index 9eda941757..716713666f 100644 --- a/modules/blogging/README.md +++ b/modules/blogging/README.md @@ -1,3 +1,10 @@ # Blogging Module -This module is used for ABP blog: https://abp.io/blog/abp/ +This module adds a simple blog to your ABP application; + +* Allows to create multiple blogs in a single application. +* Supports the Markdown format. +* Allows to write comment for a post. +* Allows to assign tags to the blog posts. + +See the [blog.abp.io](https://blog.abp.io/) website as a live example of the blogging module. \ No newline at end of file diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj index 27fa209d2c..3f100043ee 100644 --- a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj +++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netstandard2.0 diff --git a/modules/blogging/app/Volo.BloggingTestApp/Controllers/HomeController.cs b/modules/blogging/app/Volo.BloggingTestApp/Controllers/HomeController.cs index 0e4a7acc1d..f64a1da5ae 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/Controllers/HomeController.cs +++ b/modules/blogging/app/Volo.BloggingTestApp/Controllers/HomeController.cs @@ -1,13 +1,22 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc; +using Volo.Blogging; namespace Volo.BloggingTestApp.Controllers { public class HomeController : AbpController { + private readonly BloggingUrlOptions _blogOptions; + + public HomeController(IOptions blogOptions) + { + _blogOptions = blogOptions.Value; + } public ActionResult Index() { - return Redirect("/blog/"); + var urlPrefix = _blogOptions.RoutePrefix; + return Redirect(urlPrefix); } } } diff --git a/modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.csproj b/modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.csproj index b0aa8c1183..4bfe348d4e 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.csproj +++ b/modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.csproj @@ -12,9 +12,11 @@ - - - + + + + + diff --git a/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/squire-rte/squire.js b/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/squire-rte/squire.js index 7ce7ef2258..870905984b 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/squire-rte/squire.js +++ b/modules/blogging/app/Volo.BloggingTestApp/wwwroot/libs/squire-rte/squire.js @@ -1,2 +1,2 @@ -!function(e,t){"use strict";function n(e,t,n){this.root=this.currentNode=e,this.nodeType=t,this.filter=n||ue}function o(e,t){for(var n=e.length;n--;)if(!t(e[n]))return!1;return!0}function i(e){return e.nodeType===M&&!!pe[e.nodeName]}function r(e){switch(e.nodeType){case H:return me;case M:case z:if(de&&Ce.has(e))return Ce.get(e);break;default:return ge}var t;return t=o(e.childNodes,a)?fe.test(e.nodeName)?me:ve:Ne,de&&Ce.set(e,t),t}function a(e){return r(e)===me}function s(e){return r(e)===ve}function d(e){return r(e)===Ne}function l(e,t){var o=new n(t,q,s);return o.currentNode=e,o}function c(e,t){return e=l(e,t).previousNode(),e!==t?e:null}function h(e,t){return e=l(e,t).nextNode(),e!==t?e:null}function u(e){return!e.textContent&&!e.querySelector("IMG")}function f(e,t){return!i(e)&&e.nodeType===t.nodeType&&e.nodeName===t.nodeName&&"A"!==e.nodeName&&e.className===t.className&&(!e.style&&!t.style||e.style.cssText===t.style.cssText)}function p(e,t,n){if(e.nodeName!==t)return!1;for(var o in n)if(e.getAttribute(o)!==n[o])return!1;return!0}function g(e,t,n,o){for(;e&&e!==t;){if(p(e,n,o))return e;e=e.parentNode}return null}function m(e,t,n){for(;e&&e!==t;){if(n.test(e.nodeName))return e;e=e.parentNode}return null}function v(e,t){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}function N(e,t,n){var o,i,r,a,s,d="";return e&&e!==t&&(d=N(e.parentNode,t,n),e.nodeType===M&&(d+=(d?">":"")+e.nodeName,(o=e.id)&&(d+="#"+o),(i=e.className.trim())&&(r=i.split(/\s\s*/),r.sort(),d+=".",d+=r.join(".")),(a=e.dir)&&(d+="[dir="+a+"]"),r&&(s=n.classNames,ce.call(r,s.highlight)>-1&&(d+="[backgroundColor="+e.style.backgroundColor.replace(/ /g,"")+"]"),ce.call(r,s.colour)>-1&&(d+="[color="+e.style.color.replace(/ /g,"")+"]"),ce.call(r,s.fontFamily)>-1&&(d+="[fontFamily="+e.style.fontFamily.replace(/ /g,"")+"]"),ce.call(r,s.fontSize)>-1&&(d+="[fontSize="+e.style.fontSize+"]")))),d}function C(e){var t=e.nodeType;return t===M||t===z?e.childNodes.length:e.length||0}function _(e){var t=e.parentNode;return t&&t.removeChild(e),e}function S(e,t){var n=e.parentNode;n&&n.replaceChild(t,e)}function y(e){for(var t=e.ownerDocument.createDocumentFragment(),n=e.childNodes,o=n?n.length:0;o--;)t.appendChild(e.firstChild);return t}function T(e,n,o,i){var r,a,s,d=e.createElement(n);if(o instanceof Array&&(i=o,o=null),o)for(r in o)o[r]!==t&&d.setAttribute(r,o[r]);if(i)for(a=0,s=i.length;as?t.startOffset-=1:t.startOffset===s&&(t.startContainer=o,t.startOffset=C(o))),t.endContainer===e&&(t.endOffset>s?t.endOffset-=1:t.endOffset===s&&(t.endContainer=o,t.endOffset=C(o))),_(n),n.nodeType===H?o.appendData(n.data):d.push(y(n));else if(n.nodeType===M){for(i=d.length;i--;)n.appendChild(d.pop());k(n,t)}}function A(e,t){if(e.nodeType===H&&(e=e.parentNode),e.nodeType===M){var n={startContainer:t.startContainer,startOffset:t.startOffset,endContainer:t.endContainer,endOffset:t.endOffset};k(e,n),t.setStart(n.startContainer,n.startOffset),t.setEnd(n.endContainer,n.endOffset)}}function L(e){var t=e.nodeName;return"TD"===t||"TH"===t||"TR"===t||"TBODY"===t||"THEAD"===t}function O(e,t,n,o){var i,r,a,s=t;if(!L(e)||!L(t)){for(;(i=s.parentNode)&&i!==o&&i.nodeType===M&&1===i.childNodes.length;)s=i;_(s),a=e.childNodes.length,r=e.lastChild,r&&"BR"===r.nodeName&&(e.removeChild(r),a-=1),e.appendChild(y(t)),n.setStart(e,a),n.collapse(!0),A(e,n),J&&(r=e.lastChild)&&"BR"===r.nodeName&&e.removeChild(r)}}function B(e,t){var n,o,i=e.previousSibling,r=e.firstChild,a=e.ownerDocument,s="LI"===e.nodeName;if((!s||r&&/^[OU]L$/.test(r.nodeName))&&!L(e))if(i&&f(i,e)&&i.isContentEditable&&e.isContentEditable){if(!d(i)){if(!s)return;o=T(a,"DIV"),o.appendChild(y(i)),i.appendChild(o)}_(e),n=!d(e),i.appendChild(y(e)),n&&b(i,t),r&&B(r,t)}else s&&(i=T(a,"DIV"),e.insertBefore(i,r),E(i,t))}function D(e){this.isShiftDown=e.shiftKey}function R(e,t,n){var o,i;if(e||(e={}),t)for(o in t)!n&&o in e||(i=t[o],e[o]=i&&i.constructor===Object?R(e[o],i,n):i);return e}function P(e,t){e.nodeType===W&&(e=e.body);var n,o=e.ownerDocument,i=o.defaultView;this._win=i,this._doc=o,this._root=e,this._events={},this._isFocused=!1,this._lastSelection=null,ae&&this.addEventListener("beforedeactivate",this.getSelection),this._hasZWS=!1,this._lastAnchorNode=null,this._lastFocusNode=null,this._path="",this._willUpdatePath=!1,"onselectionchange"in o?this.addEventListener("selectionchange",this._updatePathOnEvent):(this.addEventListener("keyup",this._updatePathOnEvent),this.addEventListener("mouseup",this._updatePathOnEvent)),this._undoIndex=-1,this._undoStack=[],this._undoStackLength=0,this._isInUndoState=!1,this._ignoreChange=!1,this._ignoreAllChanges=!1,se?(n=new MutationObserver(this._docWasChanged.bind(this)),n.observe(e,{childList:!0,attributes:!0,characterData:!0,subtree:!0}),this._mutation=n):this.addEventListener("keyup",this._keyUpDetectChange),this._restoreSelection=!1,this.addEventListener("blur",U),this.addEventListener("mousedown",I),this.addEventListener("touchstart",I),this.addEventListener("focus",w),this._awaitingPaste=!1,this.addEventListener(X?"beforecut":"cut",tt),this.addEventListener("copy",nt),this.addEventListener("keydown",D),this.addEventListener("keyup",D),this.addEventListener(X?"beforepaste":"paste",ot),this.addEventListener("drop",it),this.addEventListener(J?"keypress":"keydown",Ie),this._keyHandlers=Object.create(He),this.setConfig(t),X&&(i.Text.prototype.splitText=function(e){var t=this.ownerDocument.createTextNode(this.data.slice(e)),n=this.nextSibling,o=this.parentNode,i=this.length-e;return n?o.insertBefore(t,n):o.appendChild(t),i&&this.deleteData(e,i),t}),e.setAttribute("contenteditable","true");try{o.execCommand("enableObjectResizing",!1,"false"),o.execCommand("enableInlineTableEditing",!1,"false")}catch(e){}e.__squire__=this,this.setHTML("")}function U(){this._restoreSelection=!0}function I(){this._restoreSelection=!1}function w(){this._restoreSelection&&this.setSelection(this._lastSelection)}function F(e,t,n){var o,i;for(o=t.firstChild;o;o=i){if(i=o.nextSibling,a(o)){if(o.nodeType===H||"BR"===o.nodeName||"IMG"===o.nodeName){n.appendChild(o);continue}}else if(s(o)){n.appendChild(e.createDefaultBlock([F(e,o,e._doc.createDocumentFragment())]));continue}F(e,o,n)}return n}var M=1,H=3,W=9,z=11,q=1,K="​",G=e.defaultView,Z=navigator.userAgent,j=/Android/.test(Z),Q=/iP(?:ad|hone|od)/.test(Z),$=/Mac OS X/.test(Z),V=/Windows NT/.test(Z),Y=/Gecko\//.test(Z),X=/Trident\/[456]\./.test(Z),J=!!G.opera,ee=/Edge\//.test(Z),te=!ee&&/WebKit\//.test(Z),ne=/Trident\/[4567]\./.test(Z),oe=$?"meta-":"ctrl-",ie=X||J,re=X||te,ae=X,se="undefined"!=typeof MutationObserver,de="undefined"!=typeof WeakMap,le=/[^ \t\r\n]/,ce=Array.prototype.indexOf;Object.create||(Object.create=function(e){var t=function(){};return t.prototype=e,new t});var he={1:1,2:2,3:4,8:128,9:256,11:1024},ue=function(){return!0};n.prototype.nextNode=function(){for(var e,t=this.currentNode,n=this.root,o=this.nodeType,i=this.filter;;){for(e=t.firstChild;!e&&t&&t!==n;)(e=t.nextSibling)||(t=t.parentNode);if(!e)return null;if(he[e.nodeType]&o&&i(e))return this.currentNode=e,e;t=e}},n.prototype.previousNode=function(){for(var e,t=this.currentNode,n=this.root,o=this.nodeType,i=this.filter;;){if(t===n)return null;if(e=t.previousSibling)for(;t=e.lastChild;)e=t;else e=t.parentNode;if(!e)return null;if(he[e.nodeType]&o&&i(e))return this.currentNode=e,e;t=e}},n.prototype.previousPONode=function(){for(var e,t=this.currentNode,n=this.root,o=this.nodeType,i=this.filter;;){for(e=t.lastChild;!e&&t&&t!==n;)(e=t.previousSibling)||(t=t.parentNode);if(!e)return null;if(he[e.nodeType]&o&&i(e))return this.currentNode=e,e;t=e}};var fe=/^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|I(?:FRAME|MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/,pe={BR:1,HR:1,IFRAME:1,IMG:1,INPUT:1},ge=0,me=1,ve=2,Ne=3,Ce=de?new WeakMap:null,_e=function(e,t){for(var n=e.childNodes;t&&e.nodeType===M;)e=n[t-1],n=e.childNodes,t=n.length;return e},Se=function(e,t){if(e.nodeType===M){var n=e.childNodes;if(t-1,r=e.compareBoundaryPoints(1,o)<1;return!i&&!r}var a=e.compareBoundaryPoints(0,o)<1,s=e.compareBoundaryPoints(2,o)>-1;return a&&s},ke=function(e){for(var t,n=e.startContainer,o=e.startOffset,r=e.endContainer,a=e.endOffset,s=!0;n.nodeType!==H&&(t=n.childNodes[o])&&!i(t);)n=t,o=0;if(a)for(;r.nodeType!==H;){if(!(t=r.childNodes[a-1])||i(t)){if(s&&t&&"BR"===t.nodeName){a-=1,s=!1;continue}break}r=t,a=C(r)}else for(;r.nodeType!==H&&(t=r.firstChild)&&!i(t);)r=t;e.collapsed?(e.setStart(r,a),e.setEnd(n,o)):(e.setStart(n,o),e.setEnd(r,a))},Ae=function(e,t,n,o){var i,r=e.startContainer,a=e.startOffset,s=e.endContainer,d=e.endOffset,l=!0;for(t||(t=e.commonAncestorContainer),n||(n=t);!a&&r!==t&&r!==o;)i=r.parentNode,a=ce.call(i.childNodes,r),r=i;for(;;){if(l&&s.nodeType!==H&&s.childNodes[d]&&"BR"===s.childNodes[d].nodeName&&(d+=1,l=!1),s===n||s===o||d!==C(s))break;i=s.parentNode,d=ce.call(i.childNodes,s)+1,s=i}e.setStart(r,a),e.setEnd(s,d)},Le=function(e,t){var n,o=e.startContainer;return a(o)?n=c(o,t):o!==t&&s(o)?n=o:(n=_e(o,e.startOffset),n=h(n,t)),n&&xe(e,n,!0)?n:null},Oe=function(e,t){var n,o,i=e.endContainer;if(a(i))n=c(i,t);else if(i!==t&&s(i))n=i;else{if(!(n=Se(i,e.endOffset))||!v(t,n))for(n=t;o=n.lastChild;)n=o;n=c(n,t)}return n&&xe(e,n,!0)?n:null},Be=new n(null,4|q,function(e){return e.nodeType===H?le.test(e.data):"IMG"===e.nodeName}),De=function(e,t){var n,o=e.startContainer,i=e.startOffset;if(Be.root=null,o.nodeType===H){if(i)return!1;n=o}else if(n=Se(o,i),n&&!v(t,n)&&(n=null),!n&&(n=_e(o,i),n.nodeType===H&&n.length))return!1;return Be.currentNode=n,Be.root=Le(e,t),!Be.previousNode()},Re=function(e,t){var n,o=e.endContainer,i=e.endOffset;if(Be.root=null,o.nodeType===H){if((n=o.data.length)&&i-1||!Y&&ce.call(i,"text/plain")>-1&&ce.call(i,"text/rtf")<0))return e.preventDefault(),void(!d&&(r=a.getData("text/html"))?this.insertHTML(r,!0):((r=a.getData("text/plain"))||(r=a.getData("text/uri-list")))&&this.insertPlainText(r,!0));this._awaitingPaste=!0;var f=this._doc.body,p=this.getSelection(),g=p.startContainer,m=p.startOffset,v=p.endContainer,N=p.endOffset,C=this.createElement("DIV",{contenteditable:"true",style:"position:fixed; overflow:hidden; top:0; right:100%; width:1px; height:1px;"});f.appendChild(C),p.selectNodeContents(C),this.setSelection(p),setTimeout(function(){try{u._awaitingPaste=!1;for(var e,t,n="",o=C;C=o;)o=C.nextSibling,_(C),e=C.firstChild,e&&e===C.lastChild&&"DIV"===e.nodeName&&(C=e),n+=C.innerHTML;t=u.createRange(g,m,v,N),u.setSelection(t),n&&u.insertHTML(n,!0)}catch(e){u.didError(e)}},0)},it=function(e){for(var t=e.dataTransfer.types,n=t.length,o=!1,i=!1;n--;)switch(t[n]){case"text/plain":o=!0;break;case"text/html":i=!0;break;default:return}(i||o)&&this.saveUndoState()},rt=P.prototype,at=function(e,t,n){var o=n._doc,i=e?DOMPurify.sanitize(e,{ALLOW_UNKNOWN_PROTOCOLS:!0,WHOLE_DOCUMENT:!1,RETURN_DOM:!0,RETURN_DOM_FRAGMENT:!0}):null;return i?o.importNode(i,!0):o.createDocumentFragment()};rt.setConfig=function(e){return e=R({blockTag:"DIV",blockAttributes:null,tagAttributes:{blockquote:null,ul:null,ol:null,li:null,a:null},classNames:{colour:"colour",fontFamily:"font",fontSize:"size",highlight:"highlight"},leafNodeNames:pe,undo:{documentSizeThreshold:-1,undoLimit:-1},isInsertedHTMLSanitized:!0,isSetHTMLSanitized:!0,sanitizeToDOMFragment:"undefined"!=typeof DOMPurify&&DOMPurify.isSupported?at:null,willCutCopy:null},e,!0),e.blockTag=e.blockTag.toUpperCase(),this._config=e,this},rt.createElement=function(e,t,n){return T(this._doc,e,t,n)},rt.createDefaultBlock=function(e){var t=this._config;return E(this.createElement(t.blockTag,t.blockAttributes,e),this._root)},rt.didError=function(e){console.log(e)},rt.getDocument=function(){return this._doc},rt.getRoot=function(){return this._root},rt.modifyDocument=function(e){var t=this._mutation;t&&(t.takeRecords().length&&this._docWasChanged(),t.disconnect()),this._ignoreAllChanges=!0,e(),this._ignoreAllChanges=!1,t&&(t.observe(this._root,{childList:!0,attributes:!0,characterData:!0,subtree:!0}),this._ignoreChange=!1)};var st={pathChange:1,select:1,input:1,undoStateChange:1};rt.fireEvent=function(e,t){var n,o,i,r=this._events[e];if(/^(?:focus|blur)/.test(e))if(n=this._root===this._doc.activeElement,"focus"===e){if(!n||this._isFocused)return this;this._isFocused=!0}else{if(n||!this._isFocused)return this;this._isFocused=!1}if(r)for(t||(t={}),t.type!==e&&(t.type=e),r=r.slice(),o=r.length;o--;){i=r[o];try{i.handleEvent?i.handleEvent(t):i.call(this,t)}catch(t){t.details="Squire: fireEvent error. Event type: "+e,this.didError(t)}}return this},rt.destroy=function(){var e,t=this._events;for(e in t)this.removeEventListener(e);this._mutation&&this._mutation.disconnect(),delete this._root.__squire__,this._undoIndex=-1,this._undoStack=[],this._undoStackLength=0},rt.handleEvent=function(e){this.fireEvent(e.type,e)},rt.addEventListener=function(e,t){var n=this._events[e],o=this._root;return t?(n||(n=this._events[e]=[],st[e]||("selectionchange"===e&&(o=this._doc),o.addEventListener(e,this,!0))),n.push(t),this):(this.didError({name:"Squire: addEventListener with null or undefined fn",message:"Event type: "+e}),this)},rt.removeEventListener=function(e,t){var n,o=this._events[e],i=this._root;if(o){if(t)for(n=o.length;n--;)o[n]===t&&o.splice(n,1);else o.length=0;o.length||(delete this._events[e],st[e]||("selectionchange"===e&&(i=this._doc),i.removeEventListener(e,this,!0)))}return this},rt.createRange=function(e,t,n,o){if(e instanceof this._win.Range)return e.cloneRange();var i=this._doc.createRange();return i.setStart(e,t),n?i.setEnd(n,o):i.setEnd(e,t),i},rt.getCursorPosition=function(e){if(!e&&!(e=this.getSelection())||!e.getBoundingClientRect)return null;var t,n,o=e.getBoundingClientRect();return o&&!o.top&&(this._ignoreChange=!0,t=this._doc.createElement("SPAN"),t.textContent=K,ye(e,t),o=t.getBoundingClientRect(),n=t.parentNode,n.removeChild(t),A(n,e)),o},rt._moveCursorTo=function(e){var t=this._root,n=this.createRange(t,e?0:t.childNodes.length);return ke(n),this.setSelection(n),this},rt.moveCursorToStart=function(){return this._moveCursorTo(!0)},rt.moveCursorToEnd=function(){return this._moveCursorTo(!1)};var dt=function(e){return e._win.getSelection()||null};rt.setSelection=function(e){if(e)if(this._lastSelection=e,this._isFocused)if(j&&!this._restoreSelection)U.call(this),this.blur(),this.focus();else{Q&&this._win.focus();var t=dt(this);t&&(t.removeAllRanges(),t.addRange(e))}else U.call(this);return this},rt.getSelection=function(){var e,t,n,o,r=dt(this),a=this._root;return this._isFocused&&r&&r.rangeCount&&(e=r.getRangeAt(0).cloneRange(),t=e.startContainer,n=e.endContainer,t&&i(t)&&e.setStartBefore(t),n&&i(n)&&e.setEndBefore(n)),e&&v(a,e.commonAncestorContainer)?this._lastSelection=e:(e=this._lastSelection,o=e.commonAncestorContainer,v(o.ownerDocument,o)||(e=null)),e||(e=this.createRange(a.firstChild,0)),e},rt.getSelectedText=function(){var e=this.getSelection();if(!e||e.collapsed)return"";var t,o=new n(e.commonAncestorContainer,4|q,function(t){return xe(e,t,!0)}),i=e.startContainer,r=e.endContainer,s=o.currentNode=i,d="",l=!1;for(o.filter(s)||(s=o.nextNode());s;)s.nodeType===H?(t=s.data)&&/\S/.test(t)&&(s===r&&(t=t.slice(0,e.endOffset)),s===i&&(t=t.slice(e.startOffset)),d+=t,l=!0):("BR"===s.nodeName||l&&!a(s))&&(d+="\n",l=!1),s=o.nextNode();return d},rt.getPath=function(){return this._path};var lt=function(e,t){for(var o,i,r,s=new n(e,4);i=s.nextNode();)for(;(r=i.data.indexOf(K))>-1&&(!t||i.parentNode!==t);){if(1===i.length){do{o=i.parentNode,o.removeChild(i),i=o,s.currentNode=o}while(a(i)&&!C(i));break}i.deleteData(r,1)}};rt._didAddZWS=function(){this._hasZWS=!0},rt._removeZWS=function(){this._hasZWS&&(lt(this._root),this._hasZWS=!1)},rt._updatePath=function(e,t){if(e){var n,o=e.startContainer,i=e.endContainer;(t||o!==this._lastAnchorNode||i!==this._lastFocusNode)&&(this._lastAnchorNode=o,this._lastFocusNode=i,n=o&&i?o===i?N(i,this._root,this._config):"(selection)":"",this._path!==n&&(this._path=n,this.fireEvent("pathChange",{path:n}))),this.fireEvent(e.collapsed?"cursor":"select",{range:e})}}, -rt._updatePathOnEvent=function(e){var t=this;t._isFocused&&!t._willUpdatePath&&(t._willUpdatePath=!0,setTimeout(function(){t._willUpdatePath=!1,t._updatePath(t.getSelection())},0))},rt.focus=function(){if(ne){try{this._root.setActive()}catch(e){}this.fireEvent("focus")}else this._root.focus();return this},rt.blur=function(){return this._root.blur(),ne&&this.fireEvent("blur"),this};var ct="squire-selection-end";rt._saveRangeToBookmark=function(e){var t,n=this.createElement("INPUT",{id:"squire-selection-start",type:"hidden"}),o=this.createElement("INPUT",{id:ct,type:"hidden"});ye(e,n),e.collapse(!1),ye(e,o),2&n.compareDocumentPosition(o)&&(n.id=ct,o.id="squire-selection-start",t=n,n=o,o=t),e.setStartAfter(n),e.setEndBefore(o)},rt._getRangeAndRemoveBookmark=function(e){var t=this._root,n=t.querySelector("#squire-selection-start"),o=t.querySelector("#"+ct);if(n&&o){var i=n.parentNode,r=o.parentNode,a=ce.call(i.childNodes,n),s=ce.call(r.childNodes,o);i===r&&(s-=1),_(n),_(o),e||(e=this._doc.createRange()),e.setStart(i,a),e.setEnd(r,s),A(i,e),i!==r&&A(r,e),e.collapsed&&(i=e.startContainer,i.nodeType===H&&(r=i.childNodes[e.startOffset],r&&r.nodeType===H||(r=i.childNodes[e.startOffset-1]),r&&r.nodeType===H&&(e.setStart(r,0),e.collapse(!0))))}return e||null},rt._keyUpDetectChange=function(e){var t=e.keyCode;e.ctrlKey||e.metaKey||e.altKey||!(t<16||t>20)||!(t<33||t>45)||this._docWasChanged()},rt._docWasChanged=function(){if(de&&(Ce=new WeakMap),!this._ignoreAllChanges){if(se&&this._ignoreChange)return void(this._ignoreChange=!1);this._isInUndoState&&(this._isInUndoState=!1,this.fireEvent("undoStateChange",{canUndo:!0,canRedo:!1})),this.fireEvent("input")}},rt._recordUndoState=function(e,t){if(!this._isInUndoState||t){var n,o=this._undoIndex,i=this._undoStack,r=this._config.undo,a=r.documentSizeThreshold,s=r.undoLimit;t||(o+=1),o-1&&2*n.length>a&&s>-1&&o>s&&(i.splice(0,o-s),o=s,this._undoStackLength=s),i[o]=n,this._undoIndex=o,this._undoStackLength+=1,this._isInUndoState=!0}},rt.saveUndoState=function(e){return e===t&&(e=this.getSelection()),this._recordUndoState(e,this._isInUndoState),this._getRangeAndRemoveBookmark(e),this},rt.undo=function(){if(0!==this._undoIndex||!this._isInUndoState){this._recordUndoState(this.getSelection(),!1),this._undoIndex-=1,this._setHTML(this._undoStack[this._undoIndex]);var e=this._getRangeAndRemoveBookmark();e&&this.setSelection(e),this._isInUndoState=!0,this.fireEvent("undoStateChange",{canUndo:0!==this._undoIndex,canRedo:!0}),this.fireEvent("input")}return this},rt.redo=function(){var e=this._undoIndex,t=this._undoStackLength;if(e+1c&&h.splitText(c),h===s&&l&&(h=h.splitText(l),d===s&&(d=h,c-=l),s=h,l=0),i=this.createElement(e,t),S(h,i),i.appendChild(h))}while(r.nextNode());d.nodeType!==H&&(h.nodeType===H?(d=h,c=h.length):(d=h.parentNode,c=1)),o=this.createRange(s,l,d,c)}return o},rt._removeFormat=function(e,t,n,o){this._saveRangeToBookmark(n);var i,r=this._doc;n.collapsed&&(re?(i=r.createTextNode(K),this._didAddZWS()):i=r.createTextNode(""),ye(n,i));for(var s=n.commonAncestorContainer;a(s);)s=s.parentNode;var d=n.startContainer,l=n.startOffset,c=n.endContainer,h=n.endOffset,u=[],f=function(e,t){if(!xe(n,e,!1)){var o,i,r=e.nodeType===H;if(!xe(n,e,!0))return void("INPUT"===e.nodeName||r&&!e.data||u.push([t,e]));if(r)e===c&&h!==e.length&&u.push([t,e.splitText(h)]),e===d&&l&&(e.splitText(l),u.push([t,e]));else for(o=e.firstChild;o;o=i)i=o.nextSibling,f(o,t)}},g=Array.prototype.filter.call(s.getElementsByTagName(e),function(o){return xe(n,o,!0)&&p(o,e,t)});return o||g.forEach(function(e){f(e,e)}),u.forEach(function(e){var t=e[0].cloneNode(!1),n=e[1];S(n,t),t.appendChild(n)}),g.forEach(function(e){S(e,y(e))}),this._getRangeAndRemoveBookmark(n),i&&n.collapse(!1),A(s,n),n},rt.changeFormat=function(e,t,n,o){return n||(n=this.getSelection())?(this.saveUndoState(n),t&&(n=this._removeFormat(t.tag.toUpperCase(),t.attributes||{},n,o)),e&&(n=this._addFormat(e.tag.toUpperCase(),e.attributes||{},n)),this.setSelection(n),this._updatePath(n,!0),se||this._docWasChanged(),this):this};var ht={DT:"DD",DD:"DT",LI:"LI",PRE:"PRE"},ut=function(e,t,n,o){var i=ht[t.nodeName],r=null,a=x(n,o,t.parentNode,e._root),s=e._config;return i||(i=s.blockTag,r=s.blockAttributes),p(a,i,r)||(t=T(a.ownerDocument,i,r),a.dir&&(t.dir=a.dir),S(a,t),t.appendChild(y(a)),a=t),a};rt.forEachBlock=function(e,t,n){if(!n&&!(n=this.getSelection()))return this;t&&this.saveUndoState(n);var o=this._root,i=Le(n,o),r=Oe(n,o);if(i&&r)do{if(e(i)||i===r)break}while(i=h(i,o));return t&&(this.setSelection(n),this._updatePath(n,!0),se||this._docWasChanged()),this},rt.modifyBlocks=function(e,t){if(!t&&!(t=this.getSelection()))return this;this._recordUndoState(t,this._isInUndoState);var n,o=this._root;return Pe(t,o),Ae(t,o,o,o),n=Te(t,o,o),ye(t,e.call(this,n)),t.endOffset]+|\([^\s()<>]+\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))|([\w\-.%+]+@(?:[\w\-]+\.)+[A-Z]{2,}\b)(?:\?[^&?\s]+=[^&?\s]+(?:&[^&?\s]+=[^&?\s]+)*)?/i;var St=function(e,t,o){var i,r,a,s,d,l,c,h=e.ownerDocument,u=new n(e,4,function(e){return!g(e,t,"A")}),f=o.linkRegExp,p=o._config.tagAttributes.a;if(f)for(;i=u.nextNode();)for(r=i.data,a=i.parentNode;s=f.exec(r);)d=s.index,l=d+s[0].length,d&&(c=h.createTextNode(r.slice(0,d)),a.insertBefore(c,i)),c=o.createElement("A",R({href:s[1]?/^(?:ht|f)tps?:/i.test(s[1])?s[1]:"http://"+s[1]:"mailto:"+s[0]},p,!1)),c.textContent=r.slice(d,l),a.insertBefore(c,i),i.data=r=r.slice(l)};rt.insertHTML=function(e,t){var n,o,i,r,a,s,d,l=this._config,c=l.isInsertedHTMLSanitized?l.sanitizeToDOMFragment:null,u=this.getSelection(),f=this._doc;"function"==typeof c?r=c(e,t,this):(t&&(n=e.indexOf("\x3c!--StartFragment--\x3e"),o=e.lastIndexOf("\x3c!--EndFragment--\x3e"),n>-1&&o>-1&&(e=e.slice(n+20,o))),/<\/td>((?!<\/tr>)[\s\S])*$/i.test(e)&&(e=""+e+""),/<\/tr>((?!<\/table>)[\s\S])*$/i.test(e)&&(e=""+e+"
    "),i=this.createElement("DIV"),i.innerHTML=e,r=f.createDocumentFragment(),r.appendChild(y(i))),this.saveUndoState(u);try{for(a=this._root,s=r,d={fragment:r,preventDefault:function(){this.defaultPrevented=!0},defaultPrevented:!1},St(r,r,this),$e(r,l),Je(r,a,!1),Ve(r),r.normalize();s=h(s,r);)E(s,a);t&&this.fireEvent("willPaste",d),d.defaultPrevented||(be(u,d.fragment,a),se||this._docWasChanged(),u.collapse(!1),this._ensureBottomLine()),this.setSelection(u),this._updatePath(u,!0),t&&this.focus()}catch(e){this.didError(e)}return this};var yt=function(e){return e.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""")};rt.insertPlainText=function(e,t){var n=this.getSelection();if(n.collapsed&&g(n.startContainer,this._root,"PRE")){var o,i,r=n.startContainer,a=n.startOffset;return r&&r.nodeType===H||(o=this._doc.createTextNode(""),r.insertBefore(o,r.childNodes[a]),r=o,a=0),i={text:e,preventDefault:function(){this.defaultPrevented=!0},defaultPrevented:!1},t&&this.fireEvent("willPaste",i),i.defaultPrevented||(e=i.text,r.insertData(a,e),n.setStart(r,a+e.length),n.collapse(!0)),this.setSelection(n),this}var s,d,l,c,h=e.split("\n"),u=this._config,f=u.blockTag,p=u.blockAttributes,m="",v="<"+f;for(s in p)v+=" "+s+'="'+yt(p[s])+'"';for(v+=">",d=0,l=h.length;d")+m;return this.insertHTML(h.join(""),t)};var Tt=function(e,t,n){return function(){return this[e](t,n),this.focus()}};rt.addStyles=function(e){if(e){var t=this._doc.documentElement.firstChild,n=this.createElement("STYLE",{type:"text/css"});n.appendChild(this._doc.createTextNode(e)),t.appendChild(n)}return this},rt.bold=Tt("changeFormat",{tag:"B"}),rt.italic=Tt("changeFormat",{tag:"I"}),rt.underline=Tt("changeFormat",{tag:"U"}),rt.strikethrough=Tt("changeFormat",{tag:"S"}),rt.subscript=Tt("changeFormat",{tag:"SUB"},{tag:"SUP"}),rt.superscript=Tt("changeFormat",{tag:"SUP"},{tag:"SUB"}),rt.removeBold=Tt("changeFormat",null,{tag:"B"}),rt.removeItalic=Tt("changeFormat",null,{tag:"I"}),rt.removeUnderline=Tt("changeFormat",null,{tag:"U"}),rt.removeStrikethrough=Tt("changeFormat",null,{tag:"S"}),rt.removeSubscript=Tt("changeFormat",null,{tag:"SUB"}),rt.removeSuperscript=Tt("changeFormat",null,{tag:"SUP"}),rt.makeLink=function(e,t){var n=this.getSelection();if(n.collapsed){var o=e.indexOf(":")+1;if(o)for(;"/"===e[o];)o+=1;ye(n,this._doc.createTextNode(e.slice(o)))}return t=R(R({href:e},t,!0),this._config.tagAttributes.a,!1),this.changeFormat({tag:"A",attributes:t},{tag:"A"},n),this.focus()},rt.removeLink=function(){return this.changeFormat(null,{tag:"A"},this.getSelection(),!0),this.focus()},rt.setFontFace=function(e){var t=this._config.classNames.fontFamily;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"font-family: "+e+", sans-serif;"}}:null,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setFontSize=function(e){var t=this._config.classNames.fontSize;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"font-size: "+("number"==typeof e?e+"px":e)}}:null,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setTextColour=function(e){var t=this._config.classNames.colour;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"color:"+e}}:null,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setHighlightColour=function(e){var t=this._config.classNames.highlight;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"background-color:"+e}}:e,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setTextAlignment=function(e){return this.forEachBlock(function(t){var n=t.className.split(/\s+/).filter(function(e){return!!e&&!/^align/.test(e)}).join(" ");e?(t.className=n+" align-"+e,t.style.textAlign=e):(t.className=n,t.style.textAlign="")},!0),this.focus()},rt.setTextDirection=function(e){return this.forEachBlock(function(t){e?t.dir=e:t.removeAttribute("dir")},!0),this.focus()};var Et=function(e){for(var t,o=this._root,i=this._doc,r=i.createDocumentFragment(),a=l(e,o);t=a.nextNode();){var s,d,c=t.querySelectorAll("BR"),h=[],u=c.length;for(s=0;s-1;)a.appendChild(d.createTextNode(r.slice(0,s))),a.appendChild(d.createElement("BR")),r=r.slice(s+1);i.parentNode.insertBefore(a,i),i.data=r}b(t,l),S(t,y(t))}return e};rt.code=function(){var e=this.getSelection();return e.collapsed||d(e.commonAncestorContainer)?this.modifyBlocks(Et,e):this.changeFormat({tag:"CODE",attributes:this._config.tagAttributes.code},null,e),this.focus()},rt.removeCode=function(){var e=this.getSelection();return g(e.commonAncestorContainer,this._root,"PRE")?this.modifyBlocks(bt,e):this.changeFormat(null,{tag:"CODE"},e),this.focus()},rt.toggleCode=function(){return this.hasFormat("PRE")||this.hasFormat("CODE")?this.removeCode():this.code(),this},rt.removeAllFormatting=function(e){if(!e&&!(e=this.getSelection())||e.collapsed)return this;for(var t=this._root,n=e.commonAncestorContainer;n&&!s(n);)n=n.parentNode;if(n||(Pe(e,t),n=t),n.nodeType===H)return this;this.saveUndoState(e),Ae(e,n,n,t);for(var o,i,r=n.ownerDocument,a=e.startContainer,d=e.startOffset,l=e.endContainer,c=e.endOffset,h=r.createDocumentFragment(),u=r.createDocumentFragment(),f=x(l,c,n,t),p=x(a,d,n,t);p!==f;)o=p.nextSibling,h.appendChild(p),p=o;return F(this,h,u),u.normalize(),p=u.firstChild,o=u.lastChild,i=n.childNodes,p?(n.insertBefore(u,f),d=ce.call(i,p),c=ce.call(i,o)+1):(d=ce.call(i,f),c=d),e.setStart(n,d),e.setEnd(n,c),A(n,e),ke(e),this.setSelection(e),this._updatePath(e,!0),this.focus()},rt.increaseQuoteLevel=Tt("modifyBlocks",ft),rt.decreaseQuoteLevel=Tt("modifyBlocks",pt),rt.makeUnorderedList=Tt("modifyBlocks",vt),rt.makeOrderedList=Tt("modifyBlocks",Nt),rt.removeList=Tt("modifyBlocks",Ct),P.isInline=a,P.isBlock=s,P.isContainer=d,P.getBlockWalker=l,P.getPreviousBlock=c,P.getNextBlock=h,P.areAlike=f,P.hasTagAttributes=p,P.getNearest=g,P.isOrContains=v,P.detach=_,P.replaceWith=S,P.empty=y,P.getNodeBefore=_e,P.getNodeAfter=Se,P.insertNodeInRange=ye,P.extractContentsOfRange=Te,P.deleteContentsOfRange=Ee,P.insertTreeFragmentIntoRange=be,P.isNodeContainedInRange=xe,P.moveRangeBoundariesDownTree=ke,P.moveRangeBoundariesUpTree=Ae,P.getStartBlockOfRange=Le,P.getEndBlockOfRange=Oe,P.contentWalker=Be,P.rangeDoesStartAtBlockBoundary=De,P.rangeDoesEndAtBlockBoundary=Re,P.expandRangeToBlockBoundaries=Pe,P.onPaste=ot,P.addLinks=St,P.splitBlock=ut,P.startSelectionId="squire-selection-start",P.endSelectionId=ct,"object"==typeof exports?module.exports=P:"function"==typeof define&&define.amd?define(function(){return P}):(G.Squire=P,top!==G&&"true"===e.documentElement.getAttribute("data-squireinit")&&(G.editor=new P(e),G.onEditorLoad&&(G.onEditorLoad(G.editor),G.onEditorLoad=null)))}(document); \ No newline at end of file +!function(e,t){"use strict";function n(e,t,n){this.root=this.currentNode=e,this.nodeType=t,this.filter=n||ue}function o(e,t){for(var n=e.length;n--;)if(!t(e[n]))return!1;return!0}function i(e){return e.nodeType===M&&!!pe[e.nodeName]}function r(e){switch(e.nodeType){case H:return me;case M:case z:if(de&&Ce.has(e))return Ce.get(e);break;default:return ge}var t;return t=o(e.childNodes,a)?fe.test(e.nodeName)?me:ve:Ne,de&&Ce.set(e,t),t}function a(e){return r(e)===me}function s(e){return r(e)===ve}function d(e){return r(e)===Ne}function l(e,t){var o=new n(t,q,s);return o.currentNode=e,o}function c(e,t){return e=l(e,t).previousNode(),e!==t?e:null}function h(e,t){return e=l(e,t).nextNode(),e!==t?e:null}function u(e){return!e.textContent&&!e.querySelector("IMG")}function f(e,t){return!i(e)&&e.nodeType===t.nodeType&&e.nodeName===t.nodeName&&"A"!==e.nodeName&&e.className===t.className&&(!e.style&&!t.style||e.style.cssText===t.style.cssText)}function p(e,t,n){if(e.nodeName!==t)return!1;for(var o in n)if(e.getAttribute(o)!==n[o])return!1;return!0}function g(e,t,n,o){for(;e&&e!==t;){if(p(e,n,o))return e;e=e.parentNode}return null}function m(e,t,n){for(;e&&e!==t;){if(n.test(e.nodeName))return e;e=e.parentNode}return null}function v(e,t){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}function N(e,t,n){var o,i,r,a,s,d="";return e&&e!==t&&(d=N(e.parentNode,t,n),e.nodeType===M&&(d+=(d?">":"")+e.nodeName,(o=e.id)&&(d+="#"+o),(i=e.className.trim())&&(r=i.split(/\s\s*/),r.sort(),d+=".",d+=r.join(".")),(a=e.dir)&&(d+="[dir="+a+"]"),r&&(s=n.classNames,ce.call(r,s.highlight)>-1&&(d+="[backgroundColor="+e.style.backgroundColor.replace(/ /g,"")+"]"),ce.call(r,s.colour)>-1&&(d+="[color="+e.style.color.replace(/ /g,"")+"]"),ce.call(r,s.fontFamily)>-1&&(d+="[fontFamily="+e.style.fontFamily.replace(/ /g,"")+"]"),ce.call(r,s.fontSize)>-1&&(d+="[fontSize="+e.style.fontSize+"]")))),d}function C(e){var t=e.nodeType;return t===M||t===z?e.childNodes.length:e.length||0}function _(e){var t=e.parentNode;return t&&t.removeChild(e),e}function S(e,t){var n=e.parentNode;n&&n.replaceChild(t,e)}function y(e){for(var t=e.ownerDocument.createDocumentFragment(),n=e.childNodes,o=n?n.length:0;o--;)t.appendChild(e.firstChild);return t}function T(e,n,o,i){var r,a,s,d=e.createElement(n);if(o instanceof Array&&(i=o,o=null),o)for(r in o)o[r]!==t&&d.setAttribute(r,o[r]);if(i)for(a=0,s=i.length;as?t.startOffset-=1:t.startOffset===s&&(t.startContainer=o,t.startOffset=C(o))),t.endContainer===e&&(t.endOffset>s?t.endOffset-=1:t.endOffset===s&&(t.endContainer=o,t.endOffset=C(o))),_(n),n.nodeType===H?o.appendData(n.data):d.push(y(n));else if(n.nodeType===M){for(i=d.length;i--;)n.appendChild(d.pop());k(n,t)}}function L(e,t){if(e.nodeType===H&&(e=e.parentNode),e.nodeType===M){var n={startContainer:t.startContainer,startOffset:t.startOffset,endContainer:t.endContainer,endOffset:t.endOffset};k(e,n),t.setStart(n.startContainer,n.startOffset),t.setEnd(n.endContainer,n.endOffset)}}function A(e){var t=e.nodeName;return"TD"===t||"TH"===t||"TR"===t||"TBODY"===t||"THEAD"===t}function O(e,t,n,o){var i,r,a,s=t;if(!A(e)||!A(t)){for(;(i=s.parentNode)&&i!==o&&i.nodeType===M&&1===i.childNodes.length;)s=i;_(s),a=e.childNodes.length,r=e.lastChild,r&&"BR"===r.nodeName&&(e.removeChild(r),a-=1),e.appendChild(y(t)),n.setStart(e,a),n.collapse(!0),L(e,n),J&&(r=e.lastChild)&&"BR"===r.nodeName&&e.removeChild(r)}}function B(e,t){var n,o,i=e.previousSibling,r=e.firstChild,a=e.ownerDocument,s="LI"===e.nodeName;if((!s||r&&/^[OU]L$/.test(r.nodeName))&&!A(e))if(i&&f(i,e)){if(!d(i)){if(!s)return;o=T(a,"DIV"),o.appendChild(y(i)),i.appendChild(o)}_(e),n=!d(e),i.appendChild(y(e)),n&&b(i,t),r&&B(r,t)}else s&&(i=T(a,"DIV"),e.insertBefore(i,r),E(i,t))}function D(e){this.isShiftDown=e.shiftKey}function R(e,t,n){var o,i;if(e||(e={}),t)for(o in t)!n&&o in e||(i=t[o],e[o]=i&&i.constructor===Object?R(e[o],i,n):i);return e}function P(e,t){e.nodeType===W&&(e=e.body);var n,o=e.ownerDocument,i=o.defaultView;this._win=i,this._doc=o,this._root=e,this._events={},this._isFocused=!1,this._lastSelection=null,ae&&this.addEventListener("beforedeactivate",this.getSelection),this._hasZWS=!1,this._lastAnchorNode=null,this._lastFocusNode=null,this._path="",this._willUpdatePath=!1,"onselectionchange"in o?this.addEventListener("selectionchange",this._updatePathOnEvent):(this.addEventListener("keyup",this._updatePathOnEvent),this.addEventListener("mouseup",this._updatePathOnEvent)),this._undoIndex=-1,this._undoStack=[],this._undoStackLength=0,this._isInUndoState=!1,this._ignoreChange=!1,this._ignoreAllChanges=!1,se?(n=new MutationObserver(this._docWasChanged.bind(this)),n.observe(e,{childList:!0,attributes:!0,characterData:!0,subtree:!0}),this._mutation=n):this.addEventListener("keyup",this._keyUpDetectChange),this._restoreSelection=!1,this.addEventListener("blur",U),this.addEventListener("mousedown",I),this.addEventListener("touchstart",I),this.addEventListener("focus",w),this._awaitingPaste=!1,this.addEventListener(X?"beforecut":"cut",tt),this.addEventListener("copy",nt),this.addEventListener("keydown",D),this.addEventListener("keyup",D),this.addEventListener(X?"beforepaste":"paste",ot),this.addEventListener("drop",it),this.addEventListener(J?"keypress":"keydown",Ie),this._keyHandlers=Object.create(He),this.setConfig(t),X&&(i.Text.prototype.splitText=function(e){var t=this.ownerDocument.createTextNode(this.data.slice(e)),n=this.nextSibling,o=this.parentNode,i=this.length-e;return n?o.insertBefore(t,n):o.appendChild(t),i&&this.deleteData(e,i),t}),e.setAttribute("contenteditable","true");try{o.execCommand("enableObjectResizing",!1,"false"),o.execCommand("enableInlineTableEditing",!1,"false")}catch(e){}e.__squire__=this,this.setHTML("")}function U(){this._restoreSelection=!0}function I(){this._restoreSelection=!1}function w(){this._restoreSelection&&this.setSelection(this._lastSelection)}function F(e,t,n){var o,i;for(o=t.firstChild;o;o=i){if(i=o.nextSibling,a(o)){if(o.nodeType===H||"BR"===o.nodeName||"IMG"===o.nodeName){n.appendChild(o);continue}}else if(s(o)){n.appendChild(e.createDefaultBlock([F(e,o,e._doc.createDocumentFragment())]));continue}F(e,o,n)}return n}var M=1,H=3,W=9,z=11,q=1,K="​",G=e.defaultView,Z=navigator.userAgent,j=/Android/.test(Z),Q=/iP(?:ad|hone|od)/.test(Z),$=/Mac OS X/.test(Z),V=/Windows NT/.test(Z),Y=/Gecko\//.test(Z),X=/Trident\/[456]\./.test(Z),J=!!G.opera,ee=/Edge\//.test(Z),te=!ee&&/WebKit\//.test(Z),ne=/Trident\/[4567]\./.test(Z),oe=$?"meta-":"ctrl-",ie=X||J,re=X||te,ae=X,se="undefined"!=typeof MutationObserver,de="undefined"!=typeof WeakMap,le=/[^ \t\r\n]/,ce=Array.prototype.indexOf;Object.create||(Object.create=function(e){var t=function(){};return t.prototype=e,new t});var he={1:1,2:2,3:4,8:128,9:256,11:1024},ue=function(){return!0};n.prototype.nextNode=function(){for(var e,t=this.currentNode,n=this.root,o=this.nodeType,i=this.filter;;){for(e=t.firstChild;!e&&t&&t!==n;)(e=t.nextSibling)||(t=t.parentNode);if(!e)return null;if(he[e.nodeType]&o&&i(e))return this.currentNode=e,e;t=e}},n.prototype.previousNode=function(){for(var e,t=this.currentNode,n=this.root,o=this.nodeType,i=this.filter;;){if(t===n)return null;if(e=t.previousSibling)for(;t=e.lastChild;)e=t;else e=t.parentNode;if(!e)return null;if(he[e.nodeType]&o&&i(e))return this.currentNode=e,e;t=e}},n.prototype.previousPONode=function(){for(var e,t=this.currentNode,n=this.root,o=this.nodeType,i=this.filter;;){for(e=t.lastChild;!e&&t&&t!==n;)(e=t.previousSibling)||(t=t.parentNode);if(!e)return null;if(he[e.nodeType]&o&&i(e))return this.currentNode=e,e;t=e}};var fe=/^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|I(?:FRAME|MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/,pe={BR:1,HR:1,IFRAME:1,IMG:1,INPUT:1},ge=0,me=1,ve=2,Ne=3,Ce=de?new WeakMap:null,_e=function(e,t){for(var n=e.childNodes;t&&e.nodeType===M;)e=n[t-1],n=e.childNodes,t=n.length;return e},Se=function(e,t){if(e.nodeType===M){var n=e.childNodes;if(t-1,r=e.compareBoundaryPoints(1,o)<1;return!i&&!r}var a=e.compareBoundaryPoints(0,o)<1,s=e.compareBoundaryPoints(2,o)>-1;return a&&s},ke=function(e){for(var t,n=e.startContainer,o=e.startOffset,r=e.endContainer,a=e.endOffset,s=!0;n.nodeType!==H&&(t=n.childNodes[o])&&!i(t);)n=t,o=0;if(a)for(;r.nodeType!==H;){if(!(t=r.childNodes[a-1])||i(t)){if(s&&t&&"BR"===t.nodeName){a-=1,s=!1;continue}break}r=t,a=C(r)}else for(;r.nodeType!==H&&(t=r.firstChild)&&!i(t);)r=t;e.collapsed?(e.setStart(r,a),e.setEnd(n,o)):(e.setStart(n,o),e.setEnd(r,a))},Le=function(e,t,n,o){var i,r=e.startContainer,a=e.startOffset,s=e.endContainer,d=e.endOffset,l=!0;for(t||(t=e.commonAncestorContainer),n||(n=t);!a&&r!==t&&r!==o;)i=r.parentNode,a=ce.call(i.childNodes,r),r=i;for(;;){if(l&&s.nodeType!==H&&s.childNodes[d]&&"BR"===s.childNodes[d].nodeName&&(d+=1,l=!1),s===n||s===o||d!==C(s))break;i=s.parentNode,d=ce.call(i.childNodes,s)+1,s=i}e.setStart(r,a),e.setEnd(s,d)},Ae=function(e,t){var n,o=e.startContainer;return a(o)?n=c(o,t):o!==t&&s(o)?n=o:(n=_e(o,e.startOffset),n=h(n,t)),n&&xe(e,n,!0)?n:null},Oe=function(e,t){var n,o,i=e.endContainer;if(a(i))n=c(i,t);else if(i!==t&&s(i))n=i;else{if(!(n=Se(i,e.endOffset))||!v(t,n))for(n=t;o=n.lastChild;)n=o;n=c(n,t)}return n&&xe(e,n,!0)?n:null},Be=new n(null,4|q,function(e){return e.nodeType===H?le.test(e.data):"IMG"===e.nodeName}),De=function(e,t){var n,o=e.startContainer,i=e.startOffset;if(Be.root=null,o.nodeType===H){if(i)return!1;n=o}else if(n=Se(o,i),n&&!v(t,n)&&(n=null),!n&&(n=_e(o,i),n.nodeType===H&&n.length))return!1;return Be.currentNode=n,Be.root=Ae(e,t),!Be.previousNode()},Re=function(e,t){var n,o=e.endContainer,i=e.endOffset;if(Be.root=null,o.nodeType===H){if((n=o.data.length)&&i-1||!Y&&ce.call(i,"text/plain")>-1&&ce.call(i,"text/rtf")<0))return e.preventDefault(),void(!d&&(r=a.getData("text/html"))?this.insertHTML(r,!0):((r=a.getData("text/plain"))||(r=a.getData("text/uri-list")))&&this.insertPlainText(r,!0));this._awaitingPaste=!0;var f=this._doc.body,p=this.getSelection(),g=p.startContainer,m=p.startOffset,v=p.endContainer,N=p.endOffset,C=this.createElement("DIV",{contenteditable:"true",style:"position:fixed; overflow:hidden; top:0; right:100%; width:1px; height:1px;"});f.appendChild(C),p.selectNodeContents(C),this.setSelection(p),setTimeout(function(){try{u._awaitingPaste=!1;for(var e,t,n="",o=C;C=o;)o=C.nextSibling,_(C),e=C.firstChild,e&&e===C.lastChild&&"DIV"===e.nodeName&&(C=e),n+=C.innerHTML;t=u.createRange(g,m,v,N),u.setSelection(t),n&&u.insertHTML(n,!0)}catch(e){u.didError(e)}},0)},it=function(e){for(var t=e.dataTransfer.types,n=t.length,o=!1,i=!1;n--;)switch(t[n]){case"text/plain":o=!0;break;case"text/html":i=!0;break;default:return}(i||o)&&this.saveUndoState()},rt=P.prototype,at=function(e,t,n){var o=n._doc,i=e?DOMPurify.sanitize(e,{ALLOW_UNKNOWN_PROTOCOLS:!0,WHOLE_DOCUMENT:!1,RETURN_DOM:!0,RETURN_DOM_FRAGMENT:!0}):null;return i?o.importNode(i,!0):o.createDocumentFragment()};rt.setConfig=function(e){return e=R({blockTag:"DIV",blockAttributes:null,tagAttributes:{blockquote:null,ul:null,ol:null,li:null,a:null},classNames:{colour:"colour",fontFamily:"font",fontSize:"size",highlight:"highlight"},leafNodeNames:pe,undo:{documentSizeThreshold:-1,undoLimit:-1},isInsertedHTMLSanitized:!0,isSetHTMLSanitized:!0,sanitizeToDOMFragment:"undefined"!=typeof DOMPurify&&DOMPurify.isSupported?at:null,willCutCopy:null},e,!0),e.blockTag=e.blockTag.toUpperCase(),this._config=e,this},rt.createElement=function(e,t,n){return T(this._doc,e,t,n)},rt.createDefaultBlock=function(e){var t=this._config;return E(this.createElement(t.blockTag,t.blockAttributes,e),this._root)},rt.didError=function(e){console.log(e)},rt.getDocument=function(){return this._doc},rt.getRoot=function(){return this._root},rt.modifyDocument=function(e){var t=this._mutation;t&&(t.takeRecords().length&&this._docWasChanged(),t.disconnect()),this._ignoreAllChanges=!0,e(),this._ignoreAllChanges=!1,t&&(t.observe(this._root,{childList:!0,attributes:!0,characterData:!0,subtree:!0}),this._ignoreChange=!1)};var st={pathChange:1,select:1,input:1,undoStateChange:1};rt.fireEvent=function(e,t){var n,o,i,r=this._events[e];if(/^(?:focus|blur)/.test(e))if(n=this._root===this._doc.activeElement,"focus"===e){if(!n||this._isFocused)return this;this._isFocused=!0}else{if(n||!this._isFocused)return this;this._isFocused=!1}if(r)for(t||(t={}),t.type!==e&&(t.type=e),r=r.slice(),o=r.length;o--;){i=r[o];try{i.handleEvent?i.handleEvent(t):i.call(this,t)}catch(t){t.details="Squire: fireEvent error. Event type: "+e,this.didError(t)}}return this},rt.destroy=function(){var e,t=this._events;for(e in t)this.removeEventListener(e);this._mutation&&this._mutation.disconnect(),delete this._root.__squire__,this._undoIndex=-1,this._undoStack=[],this._undoStackLength=0},rt.handleEvent=function(e){this.fireEvent(e.type,e)},rt.addEventListener=function(e,t){var n=this._events[e],o=this._root;return t?(n||(n=this._events[e]=[],st[e]||("selectionchange"===e&&(o=this._doc),o.addEventListener(e,this,!0))),n.push(t),this):(this.didError({name:"Squire: addEventListener with null or undefined fn",message:"Event type: "+e}),this)},rt.removeEventListener=function(e,t){var n,o=this._events[e],i=this._root;if(o){if(t)for(n=o.length;n--;)o[n]===t&&o.splice(n,1);else o.length=0;o.length||(delete this._events[e],st[e]||("selectionchange"===e&&(i=this._doc),i.removeEventListener(e,this,!0)))}return this},rt.createRange=function(e,t,n,o){if(e instanceof this._win.Range)return e.cloneRange();var i=this._doc.createRange();return i.setStart(e,t),n?i.setEnd(n,o):i.setEnd(e,t),i},rt.getCursorPosition=function(e){if(!e&&!(e=this.getSelection())||!e.getBoundingClientRect)return null;var t,n,o=e.getBoundingClientRect();return o&&!o.top&&(this._ignoreChange=!0,t=this._doc.createElement("SPAN"),t.textContent=K,ye(e,t),o=t.getBoundingClientRect(),n=t.parentNode,n.removeChild(t),L(n,e)),o},rt._moveCursorTo=function(e){var t=this._root,n=this.createRange(t,e?0:t.childNodes.length);return ke(n),this.setSelection(n),this},rt.moveCursorToStart=function(){return this._moveCursorTo(!0)},rt.moveCursorToEnd=function(){return this._moveCursorTo(!1)};var dt=function(e){return e._win.getSelection()||null};rt.setSelection=function(e){if(e)if(this._lastSelection=e,this._isFocused)if(j&&!this._restoreSelection)U.call(this),this.blur(),this.focus();else{Q&&this._win.focus();var t=dt(this);t&&(t.removeAllRanges(),t.addRange(e))}else U.call(this);return this},rt.getSelection=function(){var e,t,n,o,r=dt(this),a=this._root;return this._isFocused&&r&&r.rangeCount&&(e=r.getRangeAt(0).cloneRange(),t=e.startContainer,n=e.endContainer,t&&i(t)&&e.setStartBefore(t),n&&i(n)&&e.setEndBefore(n)),e&&v(a,e.commonAncestorContainer)?this._lastSelection=e:(e=this._lastSelection,o=e.commonAncestorContainer,v(o.ownerDocument,o)||(e=null)),e||(e=this.createRange(a.firstChild,0)),e},rt.getSelectedText=function(){var e=this.getSelection();if(!e||e.collapsed)return"";var t,o=new n(e.commonAncestorContainer,4|q,function(t){return xe(e,t,!0)}),i=e.startContainer,r=e.endContainer,s=o.currentNode=i,d="",l=!1;for(o.filter(s)||(s=o.nextNode());s;)s.nodeType===H?(t=s.data)&&/\S/.test(t)&&(s===r&&(t=t.slice(0,e.endOffset)),s===i&&(t=t.slice(e.startOffset)),d+=t,l=!0):("BR"===s.nodeName||l&&!a(s))&&(d+="\n",l=!1),s=o.nextNode();return d},rt.getPath=function(){return this._path};var lt=function(e,t){for(var o,i,r,s=new n(e,4);i=s.nextNode();)for(;(r=i.data.indexOf(K))>-1&&(!t||i.parentNode!==t);){if(1===i.length){do{o=i.parentNode,o.removeChild(i),i=o,s.currentNode=o}while(a(i)&&!C(i));break}i.deleteData(r,1)}};rt._didAddZWS=function(){this._hasZWS=!0},rt._removeZWS=function(){this._hasZWS&&(lt(this._root),this._hasZWS=!1)},rt._updatePath=function(e,t){if(e){var n,o=e.startContainer,i=e.endContainer;(t||o!==this._lastAnchorNode||i!==this._lastFocusNode)&&(this._lastAnchorNode=o,this._lastFocusNode=i,n=o&&i?o===i?N(i,this._root,this._config):"(selection)":"",this._path!==n&&(this._path=n,this.fireEvent("pathChange",{path:n}))),this.fireEvent(e.collapsed?"cursor":"select",{range:e})}},rt._updatePathOnEvent=function(e){var t=this;t._isFocused&&!t._willUpdatePath&&(t._willUpdatePath=!0,setTimeout(function(){t._willUpdatePath=!1,t._updatePath(t.getSelection())},0))}, +rt.focus=function(){return this._root.focus(),ne&&this.fireEvent("focus"),this},rt.blur=function(){return this._root.blur(),ne&&this.fireEvent("blur"),this};var ct="squire-selection-end";rt._saveRangeToBookmark=function(e){var t,n=this.createElement("INPUT",{id:"squire-selection-start",type:"hidden"}),o=this.createElement("INPUT",{id:ct,type:"hidden"});ye(e,n),e.collapse(!1),ye(e,o),2&n.compareDocumentPosition(o)&&(n.id=ct,o.id="squire-selection-start",t=n,n=o,o=t),e.setStartAfter(n),e.setEndBefore(o)},rt._getRangeAndRemoveBookmark=function(e){var t=this._root,n=t.querySelector("#squire-selection-start"),o=t.querySelector("#"+ct);if(n&&o){var i=n.parentNode,r=o.parentNode,a=ce.call(i.childNodes,n),s=ce.call(r.childNodes,o);i===r&&(s-=1),_(n),_(o),e||(e=this._doc.createRange()),e.setStart(i,a),e.setEnd(r,s),L(i,e),i!==r&&L(r,e),e.collapsed&&(i=e.startContainer,i.nodeType===H&&(r=i.childNodes[e.startOffset],r&&r.nodeType===H||(r=i.childNodes[e.startOffset-1]),r&&r.nodeType===H&&(e.setStart(r,0),e.collapse(!0))))}return e||null},rt._keyUpDetectChange=function(e){var t=e.keyCode;e.ctrlKey||e.metaKey||e.altKey||!(t<16||t>20)||!(t<33||t>45)||this._docWasChanged()},rt._docWasChanged=function(){if(de&&(Ce=new WeakMap),!this._ignoreAllChanges){if(se&&this._ignoreChange)return void(this._ignoreChange=!1);this._isInUndoState&&(this._isInUndoState=!1,this.fireEvent("undoStateChange",{canUndo:!0,canRedo:!1})),this.fireEvent("input")}},rt._recordUndoState=function(e,t){if(!this._isInUndoState||t){var n,o=this._undoIndex,i=this._undoStack,r=this._config.undo,a=r.documentSizeThreshold,s=r.undoLimit;t||(o+=1),o-1&&2*n.length>a&&s>-1&&o>s&&(i.splice(0,o-s),o=s,this._undoStackLength=s),i[o]=n,this._undoIndex=o,this._undoStackLength+=1,this._isInUndoState=!0}},rt.saveUndoState=function(e){return e===t&&(e=this.getSelection()),this._recordUndoState(e,this._isInUndoState),this._getRangeAndRemoveBookmark(e),this},rt.undo=function(){if(0!==this._undoIndex||!this._isInUndoState){this._recordUndoState(this.getSelection(),!1),this._undoIndex-=1,this._setHTML(this._undoStack[this._undoIndex]);var e=this._getRangeAndRemoveBookmark();e&&this.setSelection(e),this._isInUndoState=!0,this.fireEvent("undoStateChange",{canUndo:0!==this._undoIndex,canRedo:!0}),this.fireEvent("input")}return this},rt.redo=function(){var e=this._undoIndex,t=this._undoStackLength;if(e+1c&&h.splitText(c),h===s&&l&&(h=h.splitText(l),d===s&&(d=h,c-=l),s=h,l=0),i=this.createElement(e,t),S(h,i),i.appendChild(h))}while(r.nextNode());d.nodeType!==H&&(h.nodeType===H?(d=h,c=h.length):(d=h.parentNode,c=1)),o=this.createRange(s,l,d,c)}return o},rt._removeFormat=function(e,t,n,o){this._saveRangeToBookmark(n);var i,r=this._doc;n.collapsed&&(re?(i=r.createTextNode(K),this._didAddZWS()):i=r.createTextNode(""),ye(n,i));for(var s=n.commonAncestorContainer;a(s);)s=s.parentNode;var d=n.startContainer,l=n.startOffset,c=n.endContainer,h=n.endOffset,u=[],f=function(e,t){if(!xe(n,e,!1)){var o,i,r=e.nodeType===H;if(!xe(n,e,!0))return void("INPUT"===e.nodeName||r&&!e.data||u.push([t,e]));if(r)e===c&&h!==e.length&&u.push([t,e.splitText(h)]),e===d&&l&&(e.splitText(l),u.push([t,e]));else for(o=e.firstChild;o;o=i)i=o.nextSibling,f(o,t)}},g=Array.prototype.filter.call(s.getElementsByTagName(e),function(o){return xe(n,o,!0)&&p(o,e,t)});return o||g.forEach(function(e){f(e,e)}),u.forEach(function(e){var t=e[0].cloneNode(!1),n=e[1];S(n,t),t.appendChild(n)}),g.forEach(function(e){S(e,y(e))}),this._getRangeAndRemoveBookmark(n),i&&n.collapse(!1),L(s,n),n},rt.changeFormat=function(e,t,n,o){return n||(n=this.getSelection())?(this.saveUndoState(n),t&&(n=this._removeFormat(t.tag.toUpperCase(),t.attributes||{},n,o)),e&&(n=this._addFormat(e.tag.toUpperCase(),e.attributes||{},n)),this.setSelection(n),this._updatePath(n,!0),se||this._docWasChanged(),this):this};var ht={DT:"DD",DD:"DT",LI:"LI",PRE:"PRE"},ut=function(e,t,n,o){var i=ht[t.nodeName],r=null,a=x(n,o,t.parentNode,e._root),s=e._config;return i||(i=s.blockTag,r=s.blockAttributes),p(a,i,r)||(t=T(a.ownerDocument,i,r),a.dir&&(t.dir=a.dir),S(a,t),t.appendChild(y(a)),a=t),a};rt.forEachBlock=function(e,t,n){if(!n&&!(n=this.getSelection()))return this;t&&this.saveUndoState(n);var o=this._root,i=Ae(n,o),r=Oe(n,o);if(i&&r)do{if(e(i)||i===r)break}while(i=h(i,o));return t&&(this.setSelection(n),this._updatePath(n,!0),se||this._docWasChanged()),this},rt.modifyBlocks=function(e,t){if(!t&&!(t=this.getSelection()))return this;this._recordUndoState(t,this._isInUndoState);var n,o=this._root;return Pe(t,o),Le(t,o,o,o),n=Te(t,o,o),ye(t,e.call(this,n)),t.endOffset]+|\([^\s()<>]+\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))|([\w\-.%+]+@(?:[\w\-]+\.)+[A-Z]{2,}\b)(?:\?[^&?\s]+=[^&?\s]+(?:&[^&?\s]+=[^&?\s]+)*)?/i;var St=function(e,t,o){var i,r,a,s,d,l,c,h=e.ownerDocument,u=new n(e,4,function(e){return!g(e,t,"A")}),f=o.linkRegExp,p=o._config.tagAttributes.a;if(f)for(;i=u.nextNode();)for(r=i.data,a=i.parentNode;s=f.exec(r);)d=s.index,l=d+s[0].length,d&&(c=h.createTextNode(r.slice(0,d)),a.insertBefore(c,i)),c=o.createElement("A",R({href:s[1]?/^(?:ht|f)tps?:/i.test(s[1])?s[1]:"http://"+s[1]:"mailto:"+s[0]},p,!1)),c.textContent=r.slice(d,l),a.insertBefore(c,i),i.data=r=r.slice(l)};rt.insertHTML=function(e,t){var n,o,i,r,a,s,d,l=this._config,c=l.isInsertedHTMLSanitized?l.sanitizeToDOMFragment:null,u=this.getSelection(),f=this._doc;"function"==typeof c?r=c(e,t,this):(t&&(n=e.indexOf("\x3c!--StartFragment--\x3e"),o=e.lastIndexOf("\x3c!--EndFragment--\x3e"),n>-1&&o>-1&&(e=e.slice(n+20,o))),/<\/td>((?!<\/tr>)[\s\S])*$/i.test(e)&&(e=""+e+""),/<\/tr>((?!<\/table>)[\s\S])*$/i.test(e)&&(e=""+e+"
    "),i=this.createElement("DIV"),i.innerHTML=e,r=f.createDocumentFragment(),r.appendChild(y(i))),this.saveUndoState(u);try{for(a=this._root,s=r,d={fragment:r,preventDefault:function(){this.defaultPrevented=!0},defaultPrevented:!1},St(r,r,this),$e(r,l),Je(r,a,!1),Ve(r),r.normalize();s=h(s,r);)E(s,a);t&&this.fireEvent("willPaste",d),d.defaultPrevented||(be(u,d.fragment,a),se||this._docWasChanged(),u.collapse(!1),this._ensureBottomLine()),this.setSelection(u),this._updatePath(u,!0),t&&this.focus()}catch(e){this.didError(e)}return this};var yt=function(e){return e.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""")};rt.insertPlainText=function(e,t){var n=this.getSelection();if(n.collapsed&&g(n.startContainer,this._root,"PRE")){var o,i,r=n.startContainer,a=n.startOffset;return r&&r.nodeType===H||(o=this._doc.createTextNode(""),r.insertBefore(o,r.childNodes[a]),r=o,a=0),i={text:e,preventDefault:function(){this.defaultPrevented=!0},defaultPrevented:!1},t&&this.fireEvent("willPaste",i),i.defaultPrevented||(e=i.text,r.insertData(a,e),n.setStart(r,a+e.length),n.collapse(!0)),this.setSelection(n),this}var s,d,l,c,h=e.split("\n"),u=this._config,f=u.blockTag,p=u.blockAttributes,m="",v="<"+f;for(s in p)v+=" "+s+'="'+yt(p[s])+'"';for(v+=">",d=0,l=h.length;d")+m;return this.insertHTML(h.join(""),t)};var Tt=function(e,t,n){return function(){return this[e](t,n),this.focus()}};rt.addStyles=function(e){if(e){var t=this._doc.documentElement.firstChild,n=this.createElement("STYLE",{type:"text/css"});n.appendChild(this._doc.createTextNode(e)),t.appendChild(n)}return this},rt.bold=Tt("changeFormat",{tag:"B"}),rt.italic=Tt("changeFormat",{tag:"I"}),rt.underline=Tt("changeFormat",{tag:"U"}),rt.strikethrough=Tt("changeFormat",{tag:"S"}),rt.subscript=Tt("changeFormat",{tag:"SUB"},{tag:"SUP"}),rt.superscript=Tt("changeFormat",{tag:"SUP"},{tag:"SUB"}),rt.removeBold=Tt("changeFormat",null,{tag:"B"}),rt.removeItalic=Tt("changeFormat",null,{tag:"I"}),rt.removeUnderline=Tt("changeFormat",null,{tag:"U"}),rt.removeStrikethrough=Tt("changeFormat",null,{tag:"S"}),rt.removeSubscript=Tt("changeFormat",null,{tag:"SUB"}),rt.removeSuperscript=Tt("changeFormat",null,{tag:"SUP"}),rt.makeLink=function(e,t){var n=this.getSelection();if(n.collapsed){var o=e.indexOf(":")+1;if(o)for(;"/"===e[o];)o+=1;ye(n,this._doc.createTextNode(e.slice(o)))}return t=R(R({href:e},t,!0),this._config.tagAttributes.a,!1),this.changeFormat({tag:"A",attributes:t},{tag:"A"},n),this.focus()},rt.removeLink=function(){return this.changeFormat(null,{tag:"A"},this.getSelection(),!0),this.focus()},rt.setFontFace=function(e){var t=this._config.classNames.fontFamily;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"font-family: "+e+", sans-serif;"}}:null,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setFontSize=function(e){var t=this._config.classNames.fontSize;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"font-size: "+("number"==typeof e?e+"px":e)}}:null,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setTextColour=function(e){var t=this._config.classNames.colour;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"color:"+e}}:null,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setHighlightColour=function(e){var t=this._config.classNames.highlight;return this.changeFormat(e?{tag:"SPAN",attributes:{class:t,style:"background-color:"+e}}:e,{tag:"SPAN",attributes:{class:t}}),this.focus()},rt.setTextAlignment=function(e){return this.forEachBlock(function(t){var n=t.className.split(/\s+/).filter(function(e){return!!e&&!/^align/.test(e)}).join(" ");e?(t.className=n+" align-"+e,t.style.textAlign=e):(t.className=n,t.style.textAlign="")},!0),this.focus()},rt.setTextDirection=function(e){return this.forEachBlock(function(t){e?t.dir=e:t.removeAttribute("dir")},!0),this.focus()};var Et=function(e){for(var t,o=this._root,i=this._doc,r=i.createDocumentFragment(),a=l(e,o);t=a.nextNode();){var s,d,c=t.querySelectorAll("BR"),h=[],u=c.length;for(s=0;s-1;)a.appendChild(d.createTextNode(r.slice(0,s))),a.appendChild(d.createElement("BR")),r=r.slice(s+1);i.parentNode.insertBefore(a,i),i.data=r}b(t,l),S(t,y(t))}return e};rt.code=function(){var e=this.getSelection();return e.collapsed||d(e.commonAncestorContainer)?this.modifyBlocks(Et,e):this.changeFormat({tag:"CODE",attributes:this._config.tagAttributes.code},null,e),this.focus()},rt.removeCode=function(){var e=this.getSelection();return g(e.commonAncestorContainer,this._root,"PRE")?this.modifyBlocks(bt,e):this.changeFormat(null,{tag:"CODE"},e),this.focus()},rt.toggleCode=function(){return this.hasFormat("PRE")||this.hasFormat("CODE")?this.removeCode():this.code(),this},rt.removeAllFormatting=function(e){if(!e&&!(e=this.getSelection())||e.collapsed)return this;for(var t=this._root,n=e.commonAncestorContainer;n&&!s(n);)n=n.parentNode;if(n||(Pe(e,t),n=t),n.nodeType===H)return this;this.saveUndoState(e),Le(e,n,n,t);for(var o,i,r=n.ownerDocument,a=e.startContainer,d=e.startOffset,l=e.endContainer,c=e.endOffset,h=r.createDocumentFragment(),u=r.createDocumentFragment(),f=x(l,c,n,t),p=x(a,d,n,t);p!==f;)o=p.nextSibling,h.appendChild(p),p=o;return F(this,h,u),u.normalize(),p=u.firstChild,o=u.lastChild,i=n.childNodes,p?(n.insertBefore(u,f),d=ce.call(i,p),c=ce.call(i,o)+1):(d=ce.call(i,f),c=d),e.setStart(n,d),e.setEnd(n,c),L(n,e),ke(e),this.setSelection(e),this._updatePath(e,!0),this.focus()},rt.increaseQuoteLevel=Tt("modifyBlocks",ft),rt.decreaseQuoteLevel=Tt("modifyBlocks",pt),rt.makeUnorderedList=Tt("modifyBlocks",vt),rt.makeOrderedList=Tt("modifyBlocks",Nt),rt.removeList=Tt("modifyBlocks",Ct),P.isInline=a,P.isBlock=s,P.isContainer=d,P.getBlockWalker=l,P.getPreviousBlock=c,P.getNextBlock=h,P.areAlike=f,P.hasTagAttributes=p,P.getNearest=g,P.isOrContains=v,P.detach=_,P.replaceWith=S,P.empty=y,P.getNodeBefore=_e,P.getNodeAfter=Se,P.insertNodeInRange=ye,P.extractContentsOfRange=Te,P.deleteContentsOfRange=Ee,P.insertTreeFragmentIntoRange=be,P.isNodeContainedInRange=xe,P.moveRangeBoundariesDownTree=ke,P.moveRangeBoundariesUpTree=Le,P.getStartBlockOfRange=Ae,P.getEndBlockOfRange=Oe,P.contentWalker=Be,P.rangeDoesStartAtBlockBoundary=De,P.rangeDoesEndAtBlockBoundary=Re,P.expandRangeToBlockBoundaries=Pe,P.onPaste=ot,P.addLinks=St,P.splitBlock=ut,P.startSelectionId="squire-selection-start",P.endSelectionId=ct,"object"==typeof exports?module.exports=P:"function"==typeof define&&define.amd?define(function(){return P}):(G.Squire=P,top!==G&&"true"===e.documentElement.getAttribute("data-squireinit")&&(G.editor=new P(e),G.onEditorLoad&&(G.onEditorLoad(G.editor),G.onEditorLoad=null)))}(document); \ No newline at end of file diff --git a/modules/blogging/app/Volo.BloggingTestApp/yarn.lock b/modules/blogging/app/Volo.BloggingTestApp/yarn.lock index 6f0078f2c9..13a712e13c 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/yarn.lock +++ b/modules/blogging/app/Volo.BloggingTestApp/yarn.lock @@ -2213,9 +2213,9 @@ pumpify@^1.3.5: inherits "^2.0.3" pump "^2.0.0" -"raphael@git+https://github.com/nhn/raphael.git#2.2.0-c": +"raphael@https://github.com/nhn/raphael.git#2.2.0-c": version "2.2.0-c" - resolved "git+https://github.com/nhn/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0" + resolved "https://github.com/nhn/raphael.git#78a6ed3ec269f33b6457b0ec66f8c3d1f2ed70e0" dependencies: eve "git://github.com/adobe-webplatform/eve.git#eef80ed" diff --git a/modules/blogging/app/update-database.ps1 b/modules/blogging/app/update-database.ps1 new file mode 100644 index 0000000000..39297dd2c9 --- /dev/null +++ b/modules/blogging/app/update-database.ps1 @@ -0,0 +1 @@ +dotnet ef database update -s Volo.BloggingTestApp/Volo.BloggingTestApp.csproj -p Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj \ No newline at end of file diff --git a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/BloggingApplicationContractsModule.cs b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/BloggingApplicationContractsModule.cs index 010f872b51..74b675187d 100644 --- a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/BloggingApplicationContractsModule.cs +++ b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/BloggingApplicationContractsModule.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Authorization.Permissions; -using Volo.Abp.Localization; +using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; using Volo.Blogging.Localization; diff --git a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Blogs/Dtos/UpdateBlogDto.cs b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Blogs/Dtos/UpdateBlogDto.cs index f7ec593465..2e3b0b7b4e 100644 --- a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Blogs/Dtos/UpdateBlogDto.cs +++ b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Blogs/Dtos/UpdateBlogDto.cs @@ -1,6 +1,4 @@ -using System; - -namespace Volo.Blogging.Blogs.Dtos +namespace Volo.Blogging.Blogs.Dtos { public class UpdateBlogDto { diff --git a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/zh-Hant.json b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/zh-Hant.json new file mode 100644 index 0000000000..bca246ba43 --- /dev/null +++ b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/zh-Hant.json @@ -0,0 +1,14 @@ +{ + "culture": "zh-Hant", + "texts": { + "Permission:Blogging": "部落格", + "Permission:Blogs": "部落格", + "Permission:Posts": "文章", + "Permission:Tags": "標籤", + "Permission:Comments": "評論", + "Permission:Management": "管理", + "Permission:Edit": "標及", + "Permission:Create": "新增", + "Permission:Delete": "刪除" + } + } \ No newline at end of file diff --git a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Posts/BlogUserDto.cs b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Posts/BlogUserDto.cs index b150c82953..eb4f707e34 100644 --- a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Posts/BlogUserDto.cs +++ b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Posts/BlogUserDto.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using Volo.Abp.Application.Dtos; namespace Volo.Blogging.Posts diff --git a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Tagging/Dtos/GetPopularTagsInput.cs b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Tagging/Dtos/GetPopularTagsInput.cs index b4c0a07eb5..a6be46cff7 100644 --- a/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Tagging/Dtos/GetPopularTagsInput.cs +++ b/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Tagging/Dtos/GetPopularTagsInput.cs @@ -1,6 +1,4 @@ -using System; - -namespace Volo.Blogging.Tagging.Dtos +namespace Volo.Blogging.Tagging.Dtos { public class GetPopularTagsInput { diff --git a/modules/blogging/src/Volo.Blogging.Application/Volo.Blogging.Application.csproj b/modules/blogging/src/Volo.Blogging.Application/Volo.Blogging.Application.csproj index 95682a2a9e..a162d644df 100644 --- a/modules/blogging/src/Volo.Blogging.Application/Volo.Blogging.Application.csproj +++ b/modules/blogging/src/Volo.Blogging.Application/Volo.Blogging.Application.csproj @@ -10,7 +10,7 @@ - + diff --git a/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs b/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs index a8232933a4..d798814caa 100644 --- a/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs +++ b/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs @@ -118,7 +118,7 @@ namespace Volo.Blogging.Posts await AuthorizationService.CheckAsync(post, CommonOperations.Delete); var tags = await GetTagsOfPost(id); - _tagRepository.DecreaseUsageCountOfTags(tags.Select(t => t.Id).ToList()); + await _tagRepository.DecreaseUsageCountOfTagsAsync(tags.Select(t => t.Id).ToList()); await _commentRepository.DeleteOfPost(id); await _postRepository.DeleteAsync(id); @@ -180,14 +180,14 @@ namespace Volo.Blogging.Posts return url; } - private async Task SaveTags(List newTags, Post post) + private async Task SaveTags(ICollection newTags, Post post) { await RemoveOldTags(newTags, post); await AddNewTags(newTags, post); } - private async Task RemoveOldTags(List newTags, Post post) + private async Task RemoveOldTags(ICollection newTags, Post post) { foreach (var oldTag in post.Tags) { @@ -209,7 +209,7 @@ namespace Volo.Blogging.Posts } } - private async Task AddNewTags(List newTags, Post post) + private async Task AddNewTags(IEnumerable newTags, Post post) { var tags = await _tagRepository.GetListAsync(post.BlogId); @@ -219,7 +219,7 @@ namespace Volo.Blogging.Posts if (tag == null) { - tag = await _tagRepository.InsertAsync(new Tag(post.BlogId, newTag, 1)); + tag = await _tagRepository.InsertAsync(new Tag(GuidGenerator.Create(), post.BlogId, newTag, 1)); } else { @@ -249,7 +249,7 @@ namespace Volo.Blogging.Posts return new List(tags.Split(",").Select(t => t.Trim())); } - private Task> FilterPostsByTag(List allPostDtos, Tag tag) + private Task> FilterPostsByTag(IEnumerable allPostDtos, Tag tag) { var filteredPostDtos = allPostDtos.Where(p => p.Tags?.Any(t => t.Id == tag.Id) ?? false).ToList(); diff --git a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo.Blogging.Domain.Shared.csproj b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo.Blogging.Domain.Shared.csproj index e466b4dc99..c71ae5aef5 100644 --- a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo.Blogging.Domain.Shared.csproj +++ b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo.Blogging.Domain.Shared.csproj @@ -15,7 +15,7 @@ - +
    diff --git a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/BloggingDomainSharedModule.cs b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/BloggingDomainSharedModule.cs index aaa4425ec7..5cdd272a20 100644 --- a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/BloggingDomainSharedModule.cs +++ b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/BloggingDomainSharedModule.cs @@ -1,13 +1,13 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; +using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Blogging.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Blogging { - [DependsOn(typeof(AbpLocalizationModule))] + [DependsOn(typeof(AbpValidationModule))] public class BloggingDomainSharedModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/zh-Hant.json b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..fcafc171de --- /dev/null +++ b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/zh-Hant.json @@ -0,0 +1,47 @@ +{ + "culture": "zh-Hant", + "texts": { + "Menu:Blogs": "部落格", + "Menu:BlogManagement": "部落格管理", + "Title": "標題", + "Delete": "刪除", + "Reply": "回覆", + "ReplyTo": "回覆 {0}", + "ContinueReading": "繼續閱讀", + "DaysAgo": "{0}天前", + "YearsAgo": "{0}年前", + "MonthsAgo": "{0}個月前", + "WeeksAgo": "{0}週前", + "MinutesAgo": "{0}分前", + "SecondsAgo": "{0}秒前", + "HoursAgo": "{0}小時前", + "Now": "剛剛", + "Content": "內容", + "SeeAll": "查看所有", + "PopularTags": "熱門標籤", + "WiewsWithCount": "{0}人查看", + "LastPosts": "最後的文章", + "LeaveComment": "發表評論", + "TagsInThisArticle": "文章中的標籤", + "Posts": "文章", + "Edit": "編輯", + "BLOG": "部落格", + "CommentDeletionWarningMessage": "評論將被刪除.", + "PostDeletionWarningMessage": "文章將被刪除.", + "BlogDeletionWarningMessage": "部落格將被刪除.", + "AreYouSure": "您確定嗎?", + "CommentWithCount": "{0}個評論", + "Comment": "評論", + "ShareOnTwitter": "分享到Twitter", + "CoverImage": "封面圖", + "CreateANewPost": "新增一篇文章", + "CreateANewBlog": "新增一個部落格", + "WhatIsNew": "最新消息", + "Name": "名稱", + "ShortName": "簡稱", + "CreationTime": "建立時間", + "Description": "描述", + "Blogs": "部落格", + "Tags": "標籤" + } +} \ No newline at end of file diff --git a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs index 6c73a7e71a..4690546a7e 100644 --- a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs +++ b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Domain; +using Volo.Abp.Domain; using Volo.Abp.Modularity; namespace Volo.Blogging diff --git a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/ITagRepository.cs b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/ITagRepository.cs index 33858b9baf..8c076c49d7 100644 --- a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/ITagRepository.cs +++ b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/ITagRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -15,6 +16,6 @@ namespace Volo.Blogging.Tagging Task> GetListAsync(IEnumerable ids); - void DecreaseUsageCountOfTags(List id); + Task DecreaseUsageCountOfTagsAsync(List id, CancellationToken cancellationToken = default); } } diff --git a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/Tag.cs b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/Tag.cs index 28d14d885d..fb8f97a4dc 100644 --- a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/Tag.cs +++ b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/Tag.cs @@ -20,8 +20,9 @@ namespace Volo.Blogging.Tagging } - public Tag(Guid blogId, [NotNull] string name, int usageCount = 0, string description = null) + public Tag(Guid id, Guid blogId, [NotNull] string name, int usageCount = 0, string description = null) { + Id = id; Name = Check.NotNullOrWhiteSpace(name, nameof(name)); BlogId = blogId; Description = description; diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.csproj b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.csproj index 122385c76f..77f25274f0 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.csproj +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Blogging.EntityFrameworkCore Volo.Blogging.EntityFrameworkCore diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs index 3605550ac4..fd4bec2de4 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs @@ -7,7 +7,6 @@ using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.Blogging.EntityFrameworkCore; -using System.Linq.Dynamic.Core; namespace Volo.Blogging.Posts { diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs index cd77b3cfab..3e897fa7e3 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -36,9 +37,11 @@ namespace Volo.Blogging.Tagging return await DbSet.Where(t => ids.Contains(t.Id)).ToListAsync(); } - public void DecreaseUsageCountOfTags(List ids) + public async Task DecreaseUsageCountOfTagsAsync(List ids, CancellationToken cancellationToken = default) { - var tags = DbSet.Where(t => ids.Any(id => id == t.Id)); + var tags = await DbSet + .Where(t => ids.Any(id => id == t.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); foreach (var tag in tags) { diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs index 518a37b809..158a3416ba 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/CommentsController.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Auditing; using Volo.Blogging.Comments; using Volo.Blogging.Comments.Dtos; diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs index a3cc6b0745..79e7d920f8 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/PostsController.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Auditing; using Volo.Blogging.Posts; namespace Volo.Blogging diff --git a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs index bdb7d1d77c..ede42dd264 100644 --- a/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs +++ b/modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/TagsController.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Auditing; using Volo.Blogging.Tagging; using Volo.Blogging.Tagging.Dtos; diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs index f09ddf7026..b17c7f906f 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs index e2fcdca96c..2c0b3b97bf 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; @@ -19,7 +20,7 @@ namespace Volo.Blogging.Tagging public async Task> GetListAsync(Guid blogId) { - return await GetMongoQueryable().Where(t=>t.BlogId == blogId).ToListAsync(); + return await GetMongoQueryable().Where(t => t.BlogId == blogId).ToListAsync(); } public async Task GetByNameAsync(Guid blogId, string name) @@ -37,14 +38,16 @@ namespace Volo.Blogging.Tagging return await GetMongoQueryable().Where(t => ids.Contains(t.Id)).ToListAsync(); } - public void DecreaseUsageCountOfTags(List ids) + public async Task DecreaseUsageCountOfTagsAsync(List ids, CancellationToken cancellationToken = default) { - var tags = GetMongoQueryable().Where(t => ids.Contains(t.Id)); + var tags = await GetMongoQueryable() + .Where(t => ids.Contains(t.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); foreach (var tag in tags) { tag.DecreaseUsageCount(); - Update(tag); + await UpdateAsync(tag, cancellationToken: GetCancellationToken(cancellationToken)); } } } diff --git a/modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs b/modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs index 063ecebf5b..00fa553902 100644 --- a/modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs +++ b/modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs @@ -59,10 +59,10 @@ namespace Volo.Blogging var routePrefix = urlOptions.RoutePrefix; - options.Conventions.AddPageRoute("/Blog/Posts/Index", routePrefix + "{blogShortName}"); - options.Conventions.AddPageRoute("/Blog/Posts/Detail", routePrefix + "{blogShortName}/{postUrl}"); - options.Conventions.AddPageRoute("/Blog/Posts/Edit", routePrefix + "{blogShortName}/posts/{postId}/edit"); - options.Conventions.AddPageRoute("/Blog/Posts/New", routePrefix + "{blogShortName}/posts/new"); + options.Conventions.AddPageRoute("/Blogs/Posts/Index", routePrefix + "{blogShortName}"); + options.Conventions.AddPageRoute("/Blogs/Posts/Detail", routePrefix + "{blogShortName}/{postUrl}"); + options.Conventions.AddPageRoute("/Blogs/Posts/Edit", routePrefix + "{blogShortName}/posts/{postId}/edit"); + options.Conventions.AddPageRoute("/Blogs/Posts/New", routePrefix + "{blogShortName}/posts/new"); }); } } diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Admin/Blogs/index.js b/modules/blogging/src/Volo.Blogging.Web/Pages/Admin/Blogs/index.js index 0d8e8b3641..c2a18e083d 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Admin/Blogs/index.js +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Admin/Blogs/index.js @@ -9,6 +9,7 @@ serverSide: true, paging: false, info: false, + scrollX: true, searching: false, autoWidth: false, scrollCollapse: true, diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml deleted file mode 100644 index 4c945e8aac..0000000000 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml +++ /dev/null @@ -1,319 +0,0 @@ -@page -@inherits Volo.Blogging.Pages.Blog.BloggingPage -@using Microsoft.AspNetCore.Authorization -@using Microsoft.AspNetCore.Http.Extensions -@using Volo.Abp.Users -@using Volo.Blogging -@using Volo.Blogging.Pages.Blog.Posts -@using Volo.Blogging.Areas.Blog.Helpers.TagHelpers -@inject IAuthorizationService Authorization -@model DetailModel -@{ - ViewBag.PageTitle = "Blog"; - var hasCommentingPermission = CurrentUser.IsAuthenticated; //TODO: Apply real policy! -} -@section scripts { - - - -} -@section styles { - - - -} - -
    - -
    -
    -
    -
    -
    -
    -

    - @Model.Post.Title -

    - -
    - -
    -
    -
    - -
    -
    -
    -
    -
    - -
    -
    -
    -

    - @Html.Raw(RenderMarkdownToHtml(Model.Post.Content)) -

    -
    -
    -
    - -
    -
    - @if (Model.Post.Tags.Count > 0) - { -
    -
    @L["TagsInThisArticle"]
    - @foreach (var tag in Model.Post.Tags) - { - @tag.Name - } -
    - } - - - @if (Model.CommentsWithReplies.Count > 0) - { - - -

    @L["CommentWithCount", @Model.CommentCount]

    - @if (hasCommentingPermission) - { - @L["LeaveComment"] - } - else - { - @L["LeaveComment"] - } -
    -
    - } - -
    - @foreach (var commentWithRepliesDto in Model.CommentsWithReplies) - { -
    - -
    -
    - @(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName) - @ConvertDatetimeToTimeAgo(commentWithRepliesDto.Comment.CreationTime) -
    -

    - @commentWithRepliesDto.Comment.Text -

    -
    - - @if (hasCommentingPermission) - { - - @L["Reply"] - - } - - @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Delete)) - { - | - - @L["Delete"] - - } - - @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) - { - | - - @L["Edit"] - - } -
    - - @if (hasCommentingPermission) - { -
    -
    -

    - @L["ReplyTo", commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName] - -

    -
    -
    - - - -
    - -
    - - - -
    -
    -
    - } - @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) - { -
    -
    -
    -
    - -
    - -
    - - - -
    -
    -
    - } - - @foreach (var reply in commentWithRepliesDto.Replies) - { -
    - -
    -
    - @(reply.Writer == null ? "" : reply.Writer.UserName) - @ConvertDatetimeToTimeAgo(reply.CreationTime) -
    -

    - @reply.Text -

    -
    - - @if (hasCommentingPermission) - { - - @L["Reply"] - - } - @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Delete) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) - { - | - - @L["Delete"] - - } - - @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) - { - | - - @L["Edit"] - - } -
    - - @if (hasCommentingPermission) - { -
    -
    -

    - @L["ReplyTo", commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName] -

    -
    -
    - - -
    - -
    - - - -
    -
    -
    - } - @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) - { -
    -
    -
    -
    - -
    - -
    - - - -
    -
    -
    - } -
    -
    - } -
    -
    - } -
    - - @if (hasCommentingPermission) - { -
    -
    -

    @L["LeaveComment"]

    -
    -
    -
    -
    - - -
    - -
    - - -
    -
    -
    - } - else - { - @L["LeaveComment"] - } -
    -
    -
    -
    diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/New.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/New.cshtml deleted file mode 100644 index 7ab0105c0c..0000000000 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/New.cshtml +++ /dev/null @@ -1,70 +0,0 @@ -@page -@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor -@using Volo.Blogging.Pages.Blog.Posts -@model NewModel -@inherits Volo.Blogging.Pages.Blog.BloggingPage -@{ - ViewBag.PageTitle = "Blog"; -} -@section styles { - - - - -} -@section scripts { - - - - -} -
    -
    - - - - - - - -
    - - -
    -
    - - - -
    - - - - - -
    -
    -
    -
    -
    - -
    -
    - -
    - @L["MarkdownSupported"] -
    - -
    @L["FileUploadInfo"].Value
    - -
    -
    - - - @L["Cancel"] -
    -
    - - -
    diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/BloggingPage.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPage.cs similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/BloggingPage.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPage.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/BloggingPageModel.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPageModel.cs similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/BloggingPageModel.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPageModel.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Index.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml similarity index 89% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Index.cshtml rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml index 97f06b6dc0..91eb12fac4 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Index.cshtml +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml @@ -3,7 +3,7 @@ @inherits BloggingPage @model IndexModel @{ - ViewBag.PageTitle = "Blog"; + ViewBag.PageTitle = "Blogs"; }

    @L["Blogs"] diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Index.cshtml.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml.cs similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Index.cshtml.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml new file mode 100644 index 0000000000..a76e92ea9b --- /dev/null +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml @@ -0,0 +1,319 @@ +@page +@inherits Volo.Blogging.Pages.Blog.BloggingPage +@using Microsoft.AspNetCore.Authorization +@using Microsoft.AspNetCore.Http.Extensions +@using Volo.Abp.Users +@using Volo.Blogging +@using Volo.Blogging.Pages.Blog.Posts +@using Volo.Blogging.Areas.Blog.Helpers.TagHelpers +@inject IAuthorizationService Authorization +@model DetailModel +@{ + ViewBag.PageTitle = Model.Post.Title; + var hasCommentingPermission = CurrentUser.IsAuthenticated; //TODO: Apply real policy! +} +@section scripts { + + + +} +@section styles { + + + +} + +
    + +
    +
    +
    +
    +
    +
    +

    + @Model.Post.Title +

    + +
    + +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    + @Html.Raw(RenderMarkdownToHtml(Model.Post.Content)) +

    +
    +
    +
    + +
    +
    + @if (Model.Post.Tags.Count > 0) + { +
    +
    @L["TagsInThisArticle"]
    + @foreach (var tag in Model.Post.Tags) + { + @tag.Name + } +
    + } + + + @if (Model.CommentsWithReplies.Count > 0) + { + + +

    @L["CommentWithCount", @Model.CommentCount]

    + @if (hasCommentingPermission) + { + @L["LeaveComment"] + } + else + { + @L["LeaveComment"] + } +
    +
    + +
    + @foreach (var commentWithRepliesDto in Model.CommentsWithReplies) + { +
    + +
    +
    + @(commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName) + @ConvertDatetimeToTimeAgo(commentWithRepliesDto.Comment.CreationTime) +
    +

    + @commentWithRepliesDto.Comment.Text +

    +
    + + @if (hasCommentingPermission) + { + + @L["Reply"] + + } + + @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Delete)) + { + | + + @L["Delete"] + + } + + @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) + { + | + + @L["Edit"] + + } +
    + + @if (hasCommentingPermission) + { +
    +
    +

    + @L["ReplyTo", commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName] + +

    +
    +
    + + + +
    + +
    + + + +
    +
    +
    + } + @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) + { +
    +
    +
    +
    + +
    + +
    + + + +
    +
    +
    + } + + @foreach (var reply in commentWithRepliesDto.Replies) + { +
    + +
    +
    + @(reply.Writer == null ? "" : reply.Writer.UserName) + @ConvertDatetimeToTimeAgo(reply.CreationTime) +
    +

    + @reply.Text +

    +
    + + @if (hasCommentingPermission) + { + + @L["Reply"] + + } + @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Delete) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) + { + | + + @L["Delete"] + + } + + @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) + { + | + + @L["Edit"] + + } +
    + + @if (hasCommentingPermission) + { +
    +
    +

    + @L["ReplyTo", commentWithRepliesDto.Comment.Writer == null ? "" : commentWithRepliesDto.Comment.Writer.UserName] +

    +
    +
    + + +
    + +
    + + + +
    +
    +
    + } + @if (await Authorization.IsGrantedAsync(BloggingPermissions.Comments.Update) || (CurrentUser.Id == commentWithRepliesDto.Comment.CreatorId)) + { +
    +
    +
    +
    + +
    + +
    + + + +
    +
    +
    + } +
    +
    + } +
    +
    + } +
    + } + + @if (hasCommentingPermission) + { +
    +
    +

    @L["LeaveComment"]

    +
    +
    +
    +
    + + +
    + +
    + + +
    +
    +
    + } + else + { + @L["LeaveComment"] + } +
    +
    +
    +
    diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml.cs similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Detail.cshtml.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Edit.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml similarity index 96% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Edit.cshtml rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml index dac2d5122f..15119745df 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Edit.cshtml +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml @@ -9,13 +9,13 @@ @section styles { - + } @section scripts { - + } diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Edit.cshtml.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml.cs similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Edit.cshtml.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml similarity index 94% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.cshtml rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml index 20ebc1887f..b0f9dc4d46 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.cshtml +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml @@ -12,13 +12,13 @@ @section scripts { - + } @section styles { - + } @@ -69,7 +69,7 @@

    @foreach (var tag in post.Tags) { - @tag.Name + @tag.Name }

    @@ -178,7 +178,7 @@

    @foreach (var tag in post.Tags) { - @tag.Name + @tag.Name }

    @@ -200,7 +200,7 @@ @foreach (var popularTag in Model.PopularTags) { } diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.cshtml.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml.cs similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.cshtml.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml.cs diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.min.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.min.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.min.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.min.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/Index.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml new file mode 100644 index 0000000000..95b7de9e03 --- /dev/null +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml @@ -0,0 +1,76 @@ +@page +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor +@using Volo.Blogging.Pages.Blog.Posts +@model NewModel +@inherits Volo.Blogging.Pages.Blog.BloggingPage +@{ + ViewBag.PageTitle = "Blog"; +} +@section styles { + + + + +} +@section scripts { + + + + +} +
    +
    +
    +
    +
    + + + + + + + +
    + + +
    +
    + + + +
    + + + + + +
    +
    +
    +
    +
    + +
    +
    + +
    + @L["MarkdownSupported"] +
    + +
    @L["FileUploadInfo"].Value
    + +
    +
    + + + @L["Cancel"] +
    +
    + + +
    +
    +
    +
    diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/New.cshtml.cs b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs similarity index 84% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/New.cshtml.cs rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs index ad2dbc846f..b566b7bbe0 100644 --- a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/New.cshtml.cs +++ b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs @@ -4,6 +4,7 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Volo.Blogging.Blogs; using Volo.Blogging.Blogs.Dtos; @@ -16,6 +17,7 @@ namespace Volo.Blogging.Pages.Blog.Posts private readonly IPostAppService _postAppService; private readonly IBlogAppService _blogAppService; private readonly IAuthorizationService _authorization; + private readonly BloggingUrlOptions _blogOptions; [BindProperty(SupportsGet = true)] public string BlogShortName { get; set; } @@ -25,11 +27,12 @@ namespace Volo.Blogging.Pages.Blog.Posts public BlogDto Blog { get; set; } - public NewModel(IPostAppService postAppService, IBlogAppService blogAppService, IAuthorizationService authorization) + public NewModel(IPostAppService postAppService, IBlogAppService blogAppService, IAuthorizationService authorization, IOptions blogOptions) { _postAppService = postAppService; _blogAppService = blogAppService; _authorization = authorization; + _blogOptions = blogOptions.Value; } public async Task OnGetAsync() @@ -54,7 +57,8 @@ namespace Volo.Blogging.Pages.Blog.Posts var postWithDetailsDto = await _postAppService.CreateAsync(ObjectMapper.Map(Post)); //TODO: Try Url.Page(...) - return Redirect(Url.Content($"~/blog/{WebUtility.UrlEncode(blog.ShortName)}/{WebUtility.UrlEncode(postWithDetailsDto.Url)}")); + var urlPrefix = _blogOptions.RoutePrefix; + return Redirect(Url.Content($"~{urlPrefix}{WebUtility.UrlEncode(blog.ShortName)}/{WebUtility.UrlEncode(postWithDetailsDto.Url)}")); } public class CreatePostViewModel diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/detail.js b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/detail.js similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/detail.js rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/detail.js diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/edit.js b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/edit.js similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/edit.js rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/edit.js diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.css.map b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.css.map similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.css.map rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.css.map diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.js b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.js similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.js rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.js diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.min.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.min.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.min.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.min.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Posts/new.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Scripts/blog.js b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Scripts/blog.js similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Scripts/blog.js rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Scripts/blog.js diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_bootstrap-overwrite.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_bootstrap-overwrite.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_bootstrap-overwrite.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_bootstrap-overwrite.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_custom.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_custom.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_custom.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_custom.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_header.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_header.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_header.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_header.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_home.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_home.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_home.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_home.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_home.min.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_home.min.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_home.min.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_home.min.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_home.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_home.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_home.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_home.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_post.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_post.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/_post.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/_post.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.css.map b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.css.map similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.css.map rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.css.map diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.min.css b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.min.css similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.min.css rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.min.css diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.scss b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.scss similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/Shared/Styles/blog.scss rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Shared/Styles/blog.scss diff --git a/modules/blogging/src/Volo.Blogging.Web/Pages/Blog/_ViewImports.cshtml b/modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/_ViewImports.cshtml similarity index 100% rename from modules/blogging/src/Volo.Blogging.Web/Pages/Blog/_ViewImports.cshtml rename to modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/_ViewImports.cshtml diff --git a/modules/blogging/test/Volo.Blogging.Application.Tests/Volo.Blogging.Application.Tests.csproj b/modules/blogging/test/Volo.Blogging.Application.Tests/Volo.Blogging.Application.Tests.csproj index 7b2e893ce6..473f1442c8 100644 --- a/modules/blogging/test/Volo.Blogging.Application.Tests/Volo.Blogging.Application.Tests.csproj +++ b/modules/blogging/test/Volo.Blogging.Application.Tests/Volo.Blogging.Application.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo.Blogging.Domain.Tests.csproj b/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo.Blogging.Domain.Tests.csproj index 0a8e38a5dc..dbc49033d3 100644 --- a/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo.Blogging.Domain.Tests.csproj +++ b/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo.Blogging.Domain.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo/Abp/Blogging/Tagging/Tag_Tests.cs b/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo/Abp/Blogging/Tagging/Tag_Tests.cs index a4368a6341..25ded93f72 100644 --- a/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo/Abp/Blogging/Tagging/Tag_Tests.cs +++ b/modules/blogging/test/Volo.Blogging.Domain.Tests/Volo/Abp/Blogging/Tagging/Tag_Tests.cs @@ -14,7 +14,7 @@ namespace Volo.Blogging [InlineData("bbb")] public void SetName(string name) { - var tag = new Tag(Guid.NewGuid(), "abp", 0, "abp tag"); + var tag = new Tag(Guid.NewGuid(), Guid.NewGuid(), "abp", 0, "abp tag"); tag.SetName(name); tag.Name.ShouldBe(name); } @@ -25,7 +25,7 @@ namespace Volo.Blogging [InlineData(3)] public void IncreaseUsageCount(int number) { - var tag = new Tag(Guid.NewGuid(), "abp", 0, "abp tag"); + var tag = new Tag(Guid.NewGuid(), Guid.NewGuid(), "abp", 0, "abp tag"); tag.IncreaseUsageCount(number); tag.UsageCount.ShouldBe(number); } @@ -36,7 +36,7 @@ namespace Volo.Blogging [InlineData(3)] public void DecreaseUsageCount(int number) { - var tag = new Tag(Guid.NewGuid(), "abp", 10, "abp tag"); + var tag = new Tag(Guid.NewGuid(), Guid.NewGuid(), "abp", 10, "abp tag"); tag.DecreaseUsageCount(number); tag.UsageCount.ShouldBe(10 - number); } @@ -44,7 +44,7 @@ namespace Volo.Blogging [Fact] public void DecreaseUsageCount_Should_Greater_ThanOrEqual_Zero() { - var tag = new Tag(Guid.NewGuid(), "abp", 10, "abp tag"); + var tag = new Tag(Guid.NewGuid(), Guid.NewGuid(), "abp", 10, "abp tag"); tag.DecreaseUsageCount(100); tag.UsageCount.ShouldBe(0); } @@ -54,7 +54,7 @@ namespace Volo.Blogging [InlineData("bbb")] public void SetDescription(string description) { - var tag = new Tag(Guid.NewGuid(), "abp", 0, "abp tag"); + var tag = new Tag(Guid.NewGuid(), Guid.NewGuid(), "abp", 0, "abp tag"); tag.SetDescription(description); tag.Description.ShouldBe(description); } diff --git a/modules/blogging/test/Volo.Blogging.EntityFrameworkCore.Tests/Volo.Blogging.EntityFrameworkCore.Tests.csproj b/modules/blogging/test/Volo.Blogging.EntityFrameworkCore.Tests/Volo.Blogging.EntityFrameworkCore.Tests.csproj index a82999e3a1..8b92f8b67b 100644 --- a/modules/blogging/test/Volo.Blogging.EntityFrameworkCore.Tests/Volo.Blogging.EntityFrameworkCore.Tests.csproj +++ b/modules/blogging/test/Volo.Blogging.EntityFrameworkCore.Tests/Volo.Blogging.EntityFrameworkCore.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.csproj b/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.csproj index c02eb49044..cc46eead03 100644 --- a/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.csproj +++ b/modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/modules/blogging/test/Volo.Blogging.TestBase/Volo.Blogging.TestBase.csproj b/modules/blogging/test/Volo.Blogging.TestBase/Volo.Blogging.TestBase.csproj index 35d576a8c6..bdc6873c3a 100644 --- a/modules/blogging/test/Volo.Blogging.TestBase/Volo.Blogging.TestBase.csproj +++ b/modules/blogging/test/Volo.Blogging.TestBase/Volo.Blogging.TestBase.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestBase.cs b/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestBase.cs index 69b752a32b..5b5a9718e6 100644 --- a/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestBase.cs +++ b/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestBase.cs @@ -4,6 +4,7 @@ using NSubstitute; using Volo.Abp; using Volo.Abp.Modularity; using Volo.Abp.Users; +using Volo.Abp.Testing; namespace Volo.Blogging { diff --git a/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestDataBuilder.cs b/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestDataBuilder.cs index 67d8049a06..cd2168d9df 100644 --- a/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestDataBuilder.cs +++ b/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/BloggingTestDataBuilder.cs @@ -43,8 +43,8 @@ namespace Volo.Blogging await _postRepository.InsertAsync(new Post(_testData.Blog1Post2Id, _testData.Blog1Id, "title2", "coverImage2", "url2")); await _commentRepository.InsertAsync(new Comment(_testData.Blog1Post1Comment1Id,_testData.Blog1Post1Id,null,"text")); await _commentRepository.InsertAsync(new Comment(_testData.Blog1Post1Comment2Id, _testData.Blog1Post1Id, _testData.Blog1Post1Comment1Id, "text")); - await _tagRepository.InsertAsync(new Tag(_testData.Blog1Id, _testData.Tag1Name, 10)); - await _tagRepository.InsertAsync(new Tag(_testData.Blog1Id, _testData.Tag2Name)); + await _tagRepository.InsertAsync(new Tag(Guid.NewGuid(), _testData.Blog1Id, _testData.Tag1Name, 10)); + await _tagRepository.InsertAsync(new Tag(Guid.NewGuid(), _testData.Blog1Id, _testData.Tag2Name)); } } diff --git a/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/Tagging/TagRepository_Tests.cs b/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/Tagging/TagRepository_Tests.cs index a81c7dde1e..0706ad3f4a 100644 --- a/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/Tagging/TagRepository_Tests.cs +++ b/modules/blogging/test/Volo.Blogging.TestBase/Volo/Blogging/Tagging/TagRepository_Tests.cs @@ -60,7 +60,7 @@ namespace Volo.Blogging.Tagging var tag = await TagRepository.FindByNameAsync(BloggingTestData.Blog1Id, BloggingTestData.Tag1Name); var usageCount = tag.UsageCount; - TagRepository.DecreaseUsageCountOfTags(new List() + await TagRepository.DecreaseUsageCountOfTagsAsync(new List() { tag.Id }); diff --git a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/Volo.ClientSimulation.Demo.csproj b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/Volo.ClientSimulation.Demo.csproj index e69e3146c7..0f9f7bde5e 100644 --- a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/Volo.ClientSimulation.Demo.csproj +++ b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/Volo.ClientSimulation.Demo.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/modules/docs/README.md b/modules/docs/README.md index ee4e33a785..99117426d3 100644 --- a/modules/docs/README.md +++ b/modules/docs/README.md @@ -1,13 +1,15 @@ # Docs Module -This module is used to create technical documentation web sites. [abp.io](https://abp.io) web site uses this module for its documentation. +This module is used to create technical documentation web sites; -### Screenshot +* Built-in **GitHub integration**: Directly write and manage documents on GitHub. +* **Versioning** support directly integrated to GitHub releases. +* Supports **multi-language** (with fallback support to the default language). +* Supports the **Markdown** and HTML formats. +* Provides a **navigation** and an **outline** section. +* Allows to host **multiple projects** documentation in a single application. +* Links to the file on GitHub, so anyone can easily contribute by clicking to the **Edit link**. +* In addition to the GitHub source, allows to simply use a folder as the documentation source. -![screenshot](screenshot.png) +ABP Framework uses this module to host its documentation. See [docs.abp.io](https://docs.abp.io/). A screenshot from the ABP documentation: -### Main Features - -* Retrieves documents from a Github repository. -* Supports Markdown document formatting. -* Supports versioning (integrated to Github releases). -* Supports multiple projects. +![screenshot](screenshot2.png) diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj index d7f8b49bae..b70794e39b 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netstandard2.0 diff --git a/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json b/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json index 2ad18ee148..54e544e43e 100644 --- a/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json +++ b/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/cs.json @@ -1,6 +1,7 @@ { "culture": "cs", "texts": { + "DocsTitle": "VoloDocs", "WelcomeVoloDocs": "Vítejte ve VoloDocs!", "NoProjectWarning": "Zatím zde není žádný projekt!", "CreateYourFirstProject": "Klikněte zde k vytvoření vašeho prvního projektu", diff --git a/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/zh-Hant.json b/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/zh-Hant.json new file mode 100644 index 0000000000..643b875562 --- /dev/null +++ b/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/zh-Hant.json @@ -0,0 +1,10 @@ +{ + "culture": "zh-Hant", + "texts": { + "DocsTitle": "VoloDocs", + "WelcomeVoloDocs": "歡迎使用VoloDocs!", + "NoProjectWarning": "目前沒有專案!", + "CreateYourFirstProject": "建立您的第一個專案", + "NoProject": "沒有專案!" + } +} \ No newline at end of file diff --git a/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj b/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj index ae50728391..9cfa7656f3 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj +++ b/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj @@ -14,9 +14,9 @@ - - - + + + diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index 189689064a..3e37206f31 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -18,7 +18,6 @@ using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Identity; using Volo.Abp.Identity.Web; using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement.Identity; @@ -32,6 +31,7 @@ using VoloDocs.EntityFrameworkCore; using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; +using Volo.Abp.Validation.Localization; namespace VoloDocs.Web { diff --git a/modules/docs/screenshot.png b/modules/docs/screenshot.png deleted file mode 100644 index 55ff411f0c..0000000000 Binary files a/modules/docs/screenshot.png and /dev/null differ diff --git a/modules/docs/screenshot2.png b/modules/docs/screenshot2.png new file mode 100644 index 0000000000..0dcdf921b9 Binary files /dev/null and b/modules/docs/screenshot2.png differ diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json new file mode 100644 index 0000000000..0a8415ccad --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -0,0 +1,32 @@ +{ + "culture": "zh-Hant", + "texts": { + "Permission:DocumentManagement": "文件管理", + "Permission:Projects": "專案", + "Permission:Edit": "編輯", + "Permission:Delete": "刪除", + "Permission:Create": "建立", + "Menu:DocumentManagement": "文件管理", + "Menu:ProjectManagement": "專案管理", + "CreateANewProject": "建立新專案", + "Edit": "編輯", + "Create": "建立", + "Projects": "專案", + "Name": "名稱", + "ShortName": "簡稱", + "DocumentStoreType": "文件存儲類型", + "Format": "格式", + "ShortNameInfoText": "將用於唯一的URL.", + "DisplayName:Name": "名稱", + "DisplayName:ShortName": "簡稱", + "DisplayName:Format": "格式", + "DisplayName:DefaultDocumentName": "預設文件名稱", + "DisplayName:NavigationDocumentName": "導覽文件名稱", + "DisplayName:MinimumVersion": "最低版本", + "DisplayName:MainWebsiteUrl": "主網站網址", + "DisplayName:LatestVersionBranchName": "最新版本的分支名稱", + "DisplayName:GitHubRootUrl": "GitHub根網址", + "DisplayName:GitHubAccessToken": "GitHub 存取Token ", + "DisplayName:GitHubUserAgent": "GitHub 使用者代理" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/DocsAdminWebModule.cs b/modules/docs/src/Volo.Docs.Admin.Web/DocsAdminWebModule.cs index de404a5884..1224b4371f 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/DocsAdminWebModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.Web/DocsAdminWebModule.cs @@ -1,12 +1,8 @@ -using Localization.Resources.AbpUi; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AutoMapper; -using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; -using Volo.Abp.UI; using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; using Volo.Docs.Admin.Navigation; diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js index f1ce283543..d25d04d671 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js @@ -16,6 +16,7 @@ var _dataTable = $('#ProjectsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ processing: true, serverSide: true, + scrollX: true, paging: true, searching: false, autoWidth: false, diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index b3b2a05b53..839c63860b 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -23,7 +23,7 @@ namespace Volo.Docs.Documents IDocumentStoreFactory documentStoreFactory, IDistributedCache documentCache, IDistributedCache languageCache, - IDistributedCache resourceCache, + IDistributedCache resourceCache, IHostEnvironment hostEnvironment) { _projectRepository = projectRepository; @@ -107,6 +107,11 @@ namespace Volo.Docs.Documents try { + if (string.IsNullOrWhiteSpace(project.ParametersDocumentName)) + { + return await Task.FromResult(null); + } + var document = await GetDocumentWithDetailsDtoAsync( project, project.ParametersDocumentName, diff --git a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj index b7f28a876b..9de0a675ea 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj +++ b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj @@ -16,7 +16,7 @@ - + diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json index 6ca29e5420..743218aeba 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json @@ -15,6 +15,7 @@ "DocumentNotFound": "Ups, vyžádaný dokument neexistuje!", "NavigationDocumentNotFound": "Tato verze nemá navigační dokument!", "DocumentNotFoundInSelectedLanguage": "Tento dokument není dostupný ve vybraném jazyce. Zobrazen dokument ve výchozím jazyce.", - "FilterTopics": "Filtrovat témata" + "FilterTopics": "Filtrovat témata", + "MultipleVersionDocumentInfo": "Tento dokument má více verzí. Vyberte možnosti, které vám nejlépe vyhovují." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json new file mode 100644 index 0000000000..34ded108f1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json @@ -0,0 +1,20 @@ +{ + "culture": "zh-Hant", + "texts": { + "Documents": "文件", + "BackToWebsite": "返回主網站", + "Contributors": "貢獻者", + "ShareOn": "分享到", + "Version": "版本", + "Edit": "編輯", + "Delete": "刪除", + "InThisDocument": "在此文件中", + "GoToTop": "到最上方", + "Projects": "專案", + "NoProjectWarning": "沒有專案!", + "DocumentNotFound": "找不到要求的文件!", + "NavigationDocumentNotFound": "這個版本沒有導覽文件!", + "DocumentNotFoundInSelectedLanguage": "本文件不適用於所選語系,將以預設語系顯示.", + "FilterTopics": "過濾主題" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo.Docs.EntityFrameworkCore.csproj b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo.Docs.EntityFrameworkCore.csproj index 1111fa62a2..1eb5495e93 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo.Docs.EntityFrameworkCore.csproj +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo.Docs.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Docs.EntityFrameworkCore Volo.Docs.EntityFrameworkCore diff --git a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Documents/DocsDocumentController.cs b/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Documents/DocsDocumentController.cs index dd60b2de06..9ff91c8b17 100644 --- a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Documents/DocsDocumentController.cs +++ b/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Documents/DocsDocumentController.cs @@ -46,6 +46,8 @@ namespace Volo.Docs.Documents return DocumentAppService.GetResourceAsync(input); } + [HttpGet] + [Route("parameters")] public Task GetParametersAsync(GetParametersDocumentInput input) { return DocumentAppService.GetParametersAsync(input); diff --git a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs index 81ce5ab1f7..5d7282a7e6 100644 --- a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs @@ -24,7 +24,7 @@ namespace Volo.Docs.Markdown } private const string MdLinkFormat = "[{0}]({1}{2}/{3}/{4}{5}/{6})"; - private const string MarkdownLinkRegExp = @"\[(.*?)\]\((.*?\.md)\)"; + private const string MarkdownLinkRegExp = @"\[(.*?)\]\((.*?)\)"; private const string AnchorLinkRegExp = @"]+href=\""(.*?)\""[^>]*>(.*)?"; public virtual string Convert(ProjectDto project, DocumentWithDetailsDto document, string version, @@ -56,7 +56,7 @@ namespace Volo.Docs.Markdown var normalized = Regex.Replace(content, MarkdownLinkRegExp, delegate (Match match) { var link = match.Groups[2].Value; - if (UrlHelper.IsExternalLink(link)) + if (UrlHelper.IsExternalLink(link) || !link.EndsWith(".md")) { return match.Value; } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 0002a66343..c653068baa 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -5,9 +5,11 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Domain.Entities; using Volo.Abp.Localization; using Volo.Docs.Documents; using Volo.Docs.HtmlConverting; @@ -87,7 +89,15 @@ namespace Volo.Docs.Pages.Documents.Project DocumentsUrlPrefix = _uiOptions.RoutePrefix; ShowProjectsCombobox = _uiOptions.ShowProjectsCombobox; - await SetProjectAsync(); + try + { + await SetProjectAsync(); + } + catch (EntityNotFoundException e) + { + Logger.LogWarning(e.Message); + return NotFound(); + } if (ShowProjectsCombobox) { @@ -381,9 +391,12 @@ namespace Volo.Docs.Pages.Documents.Project private async Task ConvertDocumentContentToHtmlAsync() { - await SetDocumentPreferences(); + await SetDocumentPreferencesAsync(); SetUserPreferences(); + UserPreferences.Add("Document_Language_Code", LanguageCode); + UserPreferences.Add("Document_Version", Version); + Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences); var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); @@ -421,27 +434,30 @@ namespace Volo.Docs.Pages.Documents.Project { continue; } + var key = keyValue.Split("=")[0]; var value = keyValue.Split("=")[1]; UserPreferences.Add(key, value); - UserPreferences.Add(key + "_Value", DocumentPreferences.Parameters?.FirstOrDefault(p=>p.Name == key) - ?.Values.FirstOrDefault(v=>v.Key == value).Value); + UserPreferences.Add(key + "_Value", DocumentPreferences?.Parameters?.FirstOrDefault(p => p.Name == key) + ?.Values.FirstOrDefault(v => v.Key == value).Value); } } var query = Request.Query; - foreach (var keyValue in query) + foreach (var (key, value) in query) { - if (UserPreferences.ContainsKey(keyValue.Key)) + if (UserPreferences.ContainsKey(key)) { - UserPreferences.Remove(keyValue.Key); - UserPreferences.Remove(keyValue.Key + "_Value"); + UserPreferences.Remove(key); + UserPreferences.Remove(key + "_Value"); } - UserPreferences.Add(keyValue.Key, keyValue.Value); - UserPreferences.Add(keyValue.Key + "_Value", DocumentPreferences.Parameters?.FirstOrDefault(p => p.Name == keyValue.Key) - ?.Values.FirstOrDefault(v => v.Key == keyValue.Value).Value); + + UserPreferences.Add(key, value); + UserPreferences.Add(key + "_Value", + DocumentPreferences?.Parameters?.FirstOrDefault(p => p.Name == key)?.Values + .FirstOrDefault(v => v.Key == value).Value); } if (DocumentPreferences?.Parameters == null) @@ -459,7 +475,7 @@ namespace Volo.Docs.Pages.Documents.Project } } - public async Task SetDocumentPreferences() + public async Task SetDocumentPreferencesAsync() { var projectParameters = await _documentAppService.GetParametersAsync( new GetParametersDocumentInput diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js index a95677891e..9cbfd547ab 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js @@ -5,7 +5,6 @@ var $navigation = $("#" + navigationContainerId); - var getShownDocumentLinks = function () { return $navigation.find(".mCSB_container > li a:visible").not(".tree-toggle"); }; @@ -140,6 +139,12 @@ window.history.replaceState({}, document.title, new_uri); }; + var getTenYearsLater = function () { + var tenYearsLater = new Date(); + tenYearsLater.setTime(tenYearsLater.getTime() + (365 * 10 * 24 * 60 * 60 * 1000)); + return tenYearsLater; + }; + var setCookies = function () { var cookie = abp.utils.getCookieValue("AbpDocsPreferences"); @@ -161,7 +166,6 @@ if (splitted.length > 0 && splitted[0] === key) { keyValues[k] = key + "=" + value; - console.log(keyValues[k]); changed = true; } } @@ -171,7 +175,7 @@ } } - abp.utils.setCookieValue("AbpDocsPreferences", keyValues.join('|')); + abp.utils.setCookieValue("AbpDocsPreferences", keyValues.join('|'), getTenYearsLater(), '/'); }; $(".doc-section-combobox").change(function () { diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css index 6b58aea222..4be74abd72 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css @@ -193,61 +193,63 @@ margin-left: 10px; } .docs-page .docs-content .docs-text-field { padding: 2rem; } - .docs-page .docs-content article.docs-body h1 { - padding-top: 1rem; - font-size: 2.25rem; - padding-bottom: 10px; } - .docs-page .docs-content article.docs-body h2 { - padding-top: 2rem; - padding-bottom: 10px; - font-size: 2rem; } - .docs-page .docs-content article.docs-body h3, .docs-page .docs-content article.docs-body h4, .docs-page .docs-content article.docs-body h5, .docs-page .docs-content article.docs-body h6 { - padding-top: 20px; - padding-bottom: 5px; - font-size: 1.5rem; } - .docs-page .docs-content article.docs-body h1, .docs-page .docs-content article.docs-body h2, .docs-page .docs-content article.docs-body h3, .docs-page .docs-content article.docs-body h4, .docs-page .docs-content article.docs-body h5, .docs-page .docs-content article.docs-body h6 { - position: relative; } - .docs-page .docs-content article.docs-body h1 .anchor, .docs-page .docs-content article.docs-body h2 .anchor, .docs-page .docs-content article.docs-body h3 .anchor, .docs-page .docs-content article.docs-body h4 .anchor, .docs-page .docs-content article.docs-body h5 .anchor, .docs-page .docs-content article.docs-body h6 .anchor { - position: absolute; - right: -26px; - font-size: 18px; - bottom: 5px; - color: #999; - opacity: 0; - transition: .5s; } - .docs-page .docs-content article.docs-body h1:hover .anchor, .docs-page .docs-content article.docs-body h2:hover .anchor, .docs-page .docs-content article.docs-body h3:hover .anchor, .docs-page .docs-content article.docs-body h4:hover .anchor, .docs-page .docs-content article.docs-body h5:hover .anchor, .docs-page .docs-content article.docs-body h6:hover .anchor { - opacity: 1; } - .docs-page .docs-content article.docs-body .blockquote { - margin-bottom: 1rem; - margin-left: 0; - border-left: 2px solid gray; - padding: 1em; - background-color: #eee; - padding-bottom: .2em; } - .docs-page .docs-content article.docs-body img { - max-width: 100%; - border: 1px solid #f4f5f7; - margin: 15px 0 25px; - box-shadow: 0 0 45px #f8f9fa; - border-radius: 6px; } - .docs-page .docs-content article.docs-body table { - display: block; - overflow: auto; - width: 100%; } - .docs-page .docs-content article.docs-body table thead tr { - border-bottom: 2px inset; } - .docs-page .docs-content article.docs-body table th { - font-weight: 600; } - .docs-page .docs-content article.docs-body table td, .docs-page .docs-content article.docs-body table th { - border: 1px solid #dfe2e5; - padding: 6px 13px; } - .docs-page .docs-content article.docs-body table tr { - background-color: #fff; - border-top: 1px solid #c6cbd1; } - .docs-page .docs-content article.docs-body table tr:nth-child(2n) { - background-color: #f6f8fa; } - .docs-page .docs-content article.docs-body table img { - background-color: initial; } + .docs-page .docs-content article.docs-body { + word-break: break-word; } + .docs-page .docs-content article.docs-body h1 { + padding-top: 1rem; + font-size: 2.25rem; + padding-bottom: 10px; } + .docs-page .docs-content article.docs-body h2 { + padding-top: 2rem; + padding-bottom: 10px; + font-size: 2rem; } + .docs-page .docs-content article.docs-body h3, .docs-page .docs-content article.docs-body h4, .docs-page .docs-content article.docs-body h5, .docs-page .docs-content article.docs-body h6 { + padding-top: 20px; + padding-bottom: 5px; + font-size: 1.5rem; } + .docs-page .docs-content article.docs-body h1, .docs-page .docs-content article.docs-body h2, .docs-page .docs-content article.docs-body h3, .docs-page .docs-content article.docs-body h4, .docs-page .docs-content article.docs-body h5, .docs-page .docs-content article.docs-body h6 { + position: relative; } + .docs-page .docs-content article.docs-body h1 .anchor, .docs-page .docs-content article.docs-body h2 .anchor, .docs-page .docs-content article.docs-body h3 .anchor, .docs-page .docs-content article.docs-body h4 .anchor, .docs-page .docs-content article.docs-body h5 .anchor, .docs-page .docs-content article.docs-body h6 .anchor { + position: absolute; + right: -26px; + font-size: 18px; + bottom: 5px; + color: #999; + opacity: 0; + transition: .5s; } + .docs-page .docs-content article.docs-body h1:hover .anchor, .docs-page .docs-content article.docs-body h2:hover .anchor, .docs-page .docs-content article.docs-body h3:hover .anchor, .docs-page .docs-content article.docs-body h4:hover .anchor, .docs-page .docs-content article.docs-body h5:hover .anchor, .docs-page .docs-content article.docs-body h6:hover .anchor { + opacity: 1; } + .docs-page .docs-content article.docs-body .blockquote { + margin-bottom: 1rem; + margin-left: 0; + border-left: 2px solid gray; + padding: 1em; + background-color: #eee; + padding-bottom: .2em; } + .docs-page .docs-content article.docs-body img { + max-width: 100%; + border: 1px solid #f4f5f7; + margin: 15px 0 25px; + box-shadow: 0 0 45px #f8f9fa; + border-radius: 6px; } + .docs-page .docs-content article.docs-body table { + display: block; + overflow: auto; + width: 100%; } + .docs-page .docs-content article.docs-body table thead tr { + border-bottom: 2px inset; } + .docs-page .docs-content article.docs-body table th { + font-weight: 600; } + .docs-page .docs-content article.docs-body table td, .docs-page .docs-content article.docs-body table th { + border: 1px solid #dfe2e5; + padding: 6px 13px; } + .docs-page .docs-content article.docs-body table tr { + background-color: #fff; + border-top: 1px solid #c6cbd1; } + .docs-page .docs-content article.docs-body table tr:nth-child(2n) { + background-color: #f6f8fa; } + .docs-page .docs-content article.docs-body table img { + background-color: initial; } .docs-page .docs-page-index { min-height: 96vh; } .docs-page .docs-page-index #scroll-index { diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.min.css b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.min.css index 4605cb9eff..b46833dd39 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.min.css +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.min.css @@ -1 +1 @@ -body{position:relative;}.docs-page{background:#f5f7f9;}.docs-page .anchorjs-link{transition:all .25s linear;}.docs-page *:hover>.anchorjs-link{margin-left:-1.125em !important;transition:color .25s linear;color:#808080;}.docs-page .anchorjs-link:hover{color:#007bff;text-decoration:none;}.docs-page .docs-sidebar{background:#f5f7f9;padding-right:1rem;position:relative;top:0;left:0;position:fixed;}.docs-page .docs-sidebar .docs-sidebar-wrapper{width:270px;float:right;}.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control{background:none;background:#fff;border:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:focus,.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:active,.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:hover,.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:visited{box-shadow:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version{position:relative;padding:0 1rem;margin:.25rem 0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select{border-radius:3px;border:1px solid #e9ecef;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select .input-group-text{padding:.375rem .6rem;font-size:.9rem;width:32px;height:30px;line-height:1;border-radius:0;border:1px solid #e9ecef;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control{padding:0 10px;border:0;min-height:30px;height:30px;font-size:.85em;border-radius:1px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:focus,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:active,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:hover,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:visited,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:focus,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:active,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:hover,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:visited{box-shadow:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control{padding-left:6px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-filter{padding:0 1rem;margin:.5rem 0;font-size:.9em;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-filter .filter-icon i.fa{color:#ddd;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{height:100vh;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list>ul{display:block;height:calc(100vh - 220px);overflow-y:auto;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul{font-size:.935em;list-style:none;padding:0 1rem;margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li{margin-left:0;padding-left:24px;display:block;width:100%;position:relative;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#999;font-weight:700;padding:7px 0;display:block;border-bottom:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a:hover{color:#000;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a.last-link{top:11px;color:#aaa;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li span.tree-toggle{color:#999;padding:7px 0;display:block;border-bottom:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li .plus-icon{font-size:.85em;transition:.3s;width:18px;height:18px;text-align:center;padding:0;line-height:1;border-radius:50%;margin-right:4px;position:absolute;left:2px;top:11px;color:#aaa;cursor:default;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li .plus-icon .fa-long-arrow-right.no-link{color:#555;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li .plus-icon .fa-chevron-right{cursor:pointer;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li a{font-weight:400;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul li a{font-weight:300;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#000;transition:.4s;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>span .fa{transform:rotate(90deg);color:#007bff;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree.last-link>span .fa{transform:rotate(0deg);}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:1.5rem;color:#000;font-weight:700;padding:20px 0 10px;line-height:1;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong{font-weight:300;text-transform:uppercase;font-size:.9rem;opacity:.6;}.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site{color:#000;opacity:.15;transition:.4s;font-size:.75rem;font-weight:300;}.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site:hover{text-decoration:none;opacity:.5;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:.85em;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong{display:block;}.docs-page .docs-content{overflow-x:scroll;}.docs-page .docs-content .contributors{position:absolute;top:15px;right:5px;}.docs-page .docs-content .contributors .contributors-avatar{border-radius:21px;width:21px;height:21px;}.docs-page .docs-content .contributors a{padding:0;width:21px;height:21px;display:inline-block;margin:0 0 0 2px;}.docs-page .docs-content .contributors a:hover{text-decoration:none;}.docs-page .docs-content .docs-link-btns{border-bottom:1px solid #f4f5f7;background:#fdfdfd;padding:10px 20px;margin:0 -15px;text-align:right;font-size:.8em;min-height:40px;}.docs-page .docs-content .docs-link-btns a{color:#999;}.docs-page .docs-content .docs-link-btns a:hover{color:#444;text-decoration:none;}.docs-page .docs-content .docs-link-btns .twitter{color:#00acee;}.docs-page .docs-content .docs-link-btns .linkedin{color:#0077b5;}.docs-page .docs-content .docs-link-btns .email{color:#5a5a5a;}.docs-page .docs-content .docs-link-btns .share-button{margin-left:10px;}.docs-page .docs-content .docs-text-field{padding:2rem;}.docs-page .docs-content article.docs-body h1{padding-top:1rem;font-size:2.25rem;padding-bottom:10px;}.docs-page .docs-content article.docs-body h2{padding-top:2rem;padding-bottom:10px;font-size:2rem;}.docs-page .docs-content article.docs-body h3,.docs-page .docs-content article.docs-body h4,.docs-page .docs-content article.docs-body h5,.docs-page .docs-content article.docs-body h6{padding-top:20px;padding-bottom:5px;font-size:1.5rem;}.docs-page .docs-content article.docs-body h1,.docs-page .docs-content article.docs-body h2,.docs-page .docs-content article.docs-body h3,.docs-page .docs-content article.docs-body h4,.docs-page .docs-content article.docs-body h5,.docs-page .docs-content article.docs-body h6{position:relative;}.docs-page .docs-content article.docs-body h1 .anchor,.docs-page .docs-content article.docs-body h2 .anchor,.docs-page .docs-content article.docs-body h3 .anchor,.docs-page .docs-content article.docs-body h4 .anchor,.docs-page .docs-content article.docs-body h5 .anchor,.docs-page .docs-content article.docs-body h6 .anchor{position:absolute;right:-26px;font-size:18px;bottom:5px;color:#999;opacity:0;transition:.5s;}.docs-page .docs-content article.docs-body h1:hover .anchor,.docs-page .docs-content article.docs-body h2:hover .anchor,.docs-page .docs-content article.docs-body h3:hover .anchor,.docs-page .docs-content article.docs-body h4:hover .anchor,.docs-page .docs-content article.docs-body h5:hover .anchor,.docs-page .docs-content article.docs-body h6:hover .anchor{opacity:1;}.docs-page .docs-content article.docs-body .blockquote{margin-bottom:1rem;margin-left:0;border-left:2px solid #808080;padding:1em;background-color:#eee;padding-bottom:.2em;}.docs-page .docs-content article.docs-body img{max-width:100%;border:1px solid #f4f5f7;margin:15px 0 25px;box-shadow:0 0 45px #f8f9fa;border-radius:6px;}.docs-page .docs-content article.docs-body table{display:block;overflow:auto;width:100%;}.docs-page .docs-content article.docs-body table thead tr{border-bottom:2px inset;}.docs-page .docs-content article.docs-body table th{font-weight:600;}.docs-page .docs-content article.docs-body table td,.docs-page .docs-content article.docs-body table th{border:1px solid #dfe2e5;padding:6px 13px;}.docs-page .docs-content article.docs-body table tr{background-color:#fff;border-top:1px solid #c6cbd1;}.docs-page .docs-content article.docs-body table tr:nth-child(2n){background-color:#f6f8fa;}.docs-page .docs-content article.docs-body table img{background-color:initial;}.docs-page .docs-page-index{min-height:96vh;}.docs-page .docs-page-index #scroll-index{max-height:96vh;}.docs-page .docs-page-index .docs-inner-anchors{position:fixed;top:0;padding:10px;font-size:.9em;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills{font-size:.92em;margin-left:15px;border-left:1px solid #eee;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link{padding:3px 14px 4px;color:#aaa;line-height:1.2;position:relative;border-left:1px solid #eee;border-radius:0;margin-left:-1px;margin-top:1px;margin-bottom:1px;transition:.2s;font-weight:normal;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link.active{border-left:1px solid #007bff;background:none;color:#007bff;font-weight:normal;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-link.active{color:#007bff;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-pills .nav-link.active{color:#007bff;}.docs-page .docs-page-index .docs-inner-anchors .index-scroll{margin-left:-30px;}.docs-page .docs-page-index .docs-inner-anchors .docs-anchors-wrapper{max-width:300px;float:left;}.docs-page .docs-page-index .scroll-top-btn{display:none;font-size:.85em;color:#aaa;text-decoration:none;padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn.showup{display:block;}@media(min-width:1100px){.container{max-width:1080px;}.docs-page .docs-sidebar.dark-sidebar{background:#191919;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select{border:1px solid #333;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control,.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control{background:#191919;border-color:#191919;color:#999;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control{background:#191919;border-color:#191919;color:#999;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control::placeholder{color:#999;opacity:.5;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select label{background:#333;border-color:#333;color:#ddd;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-filter .form-control{background:#333;color:#999;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-filter select{border:0;border-radius:6px;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-filter .filter-icon i.fa{color:#aaa;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#aaa;border-bottom:0;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a:hover{color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon{font-size:.85em;transition:.3s;width:18px;height:18px;text-align:center;padding:0;line-height:1;border-radius:50%;margin-right:4px;position:absolute;left:2px;top:11px;color:#aaa;cursor:default;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon .fa-long-arrow-right.no-link{color:#555;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon .fa-chevron-right{cursor:pointer;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon.last-link{top:11px;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li span.tree-toggle{color:#555;padding:7px 0;display:block;border-bottom:0;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#fff;transition:.4s;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a span .fa{color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a span:not(.last-link) .fa{transform:rotate(90deg);color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-top .navbar-logo .navbar-brand{color:#fff;text-transform:uppercase;white-space:unset;}.docs-page .docs-sidebar.dark-sidebar .docs-top .navbar-logo .go-back-site{color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-top .navbar-logo .navbar-logo-desc{color:#ddd;}}@media(min-width:1366px){.container{max-width:1340px;}}@media(min-width:1440px){.container{max-width:1400px;}}@media(max-width:767px){.docs-page .docs-content article.docs-body h1{padding-top:1.5rem;}.docs-page{background:#f5f7f9;}.docs-page>.container-fluid{display:block;}.docs-page>.container-fluid>.row{display:block;}.docs-page .docs-sidebar{position:fixed;max-width:100%;width:100%;display:block;padding:0 !important;top:0;left:0;z-index:100;right:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper{max-width:100%;width:100%;top:0;position:relative;margin:0 !important;height:72px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{padding:.5rem 1.5rem 2rem 1.5rem;position:fixed;top:70px;font-size:17px;left:0;width:100%;z-index:100;background:#f5f7f9;display:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-filter{padding:0 0 1rem !important;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version label{width:36px;text-align:center;padding-left:0;padding-right:0;display:inline-block;line-height:26px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version input.form-control{padding-left:12px !important;}.docs-page .docs-sidebar .docs-top .navbar-logo{padding:0;padding-top:.3rem;display:block;text-align:center;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:1.5rem;font-weight:700;display:block;margin-right:0;padding:7px 0 10px;text-transform:uppercase;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:110px;}.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site{display:none;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:1em;display:none;}.docs-page .docs-sidebar .docs-top .open-dmenu{position:absolute;top:10px;left:20px;}.docs-page .docs-content{padding-top:72px;max-width:100%;display:block !important;}.docs-page .docs-content .docs-text-field{padding:1rem 1.5rem;}.docs-page .docs-page-index{display:none;}}.for-mobile{display:none;}.for-desktop{display:inline-block;}pre[class*="language-"]{padding:1.4em 2em !important;margin:15px 0 25px !important;border-radius:6px;}code{padding:.2em .4em;margin:0;font-size:82%;background-color:#f0f1f3;border-radius:3px;color:#28a745;}pre code{padding:0;}pre .token.keyword{color:#569cd6;}pre .token.atrule,pre .token.attr-value,pre .token.function,pre .token.class-name{color:#d69d85;}:not(pre)>code[class*="language-"],pre[class*="language-"]{background:#191919 !important;}div.code-toolbar>.toolbar span{cursor:default;}div.code-toolbar>.toolbar a{cursor:copy;}@media(max-width:767px){body{font-size:14px;}.for-mobile{display:inline-block;}.for-desktop{display:none;}.close-mmenu,.close-dmenu{position:absolute;top:-78px;left:25px;color:#fff;font-size:68px;background:#fff;opacity:0;}.navbar{padding:.5rem 1.75rem;}.navbar .navbar-collapse{background:#38003d;position:fixed;top:86px;left:0;width:100%;height:100vh;height:calc(100vh - 86px);z-index:100 !important;}.navbar .navbar-collapse .navbar-nav{height:100vh;padding:20px 30px;overflow:auto;}.navbar .navbar-collapse .navbar-nav .nav-link{padding:1.2rem !important;}.navbar .navbar-toggler{padding:.5rem .75rem;font-size:1.5rem;line-height:1;background-color:transparent;border:0;border-radius:.25rem;color:#fff !important;margin-left:-1rem;}.section-with-logos img{margin:15px;opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}span.code-arrow{padding:0 0 0;display:block;transform:rotate(90deg);font-size:2em;}.mb-5,.my-5{margin-bottom:2rem !important;}}@media screen and (max-width:767px){.navbar-logo .navbar-brand{display:inline-block;margin:0 auto !important;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}}.alert-criteria{padding:1.25em 1.5em;max-width:100%;}.alert-criteria p.alert-p{font-size:.96em;}.alert-criteria .input-group .input-group-text,.alert-criteria .input-group .form-control{font-size:.96em;}@media screen and (max-width:767px){.alert-criteria .input-group .input-group-text,.alert-criteria .input-group .form-control{font-size:.88em;}}.alert-criteria .input-group .input-group-text{color:#004085;background-color:#bddcfd;border:1px solid #bddcfd;}@media screen and (max-width:1366px){.alert-criteria .input-group .input-group-text{display:none;}}.alert-criteria .input-group .form-control{color:#004085;background-color:#fff;border:1px solid #bddcfd;}@media screen and (max-width:1366px){.alert-criteria .input-group .form-control{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;}}.scrolledMore{padding-top:107px;}.scrolledMore .alert-criteria{position:fixed;top:0;z-index:10;border:0;border-radius:0;margin-left:-47px;padding:.5em .75em;}@media screen and (max-width:767px){.scrolledMore .alert-criteria{top:72px;margin-left:-36px;}}.scrolledMore .alert-criteria p.alert-p{display:none;} \ No newline at end of file +body{position:relative;}.docs-page{background:#f5f7f9;}.docs-page .anchorjs-link{transition:all .25s linear;}.docs-page *:hover>.anchorjs-link{margin-left:-1.125em !important;transition:color .25s linear;color:#808080;}.docs-page .anchorjs-link:hover{color:#007bff;text-decoration:none;}.docs-page .docs-sidebar{background:#f5f7f9;padding-right:1rem;position:relative;top:0;left:0;position:fixed;}.docs-page .docs-sidebar .docs-sidebar-wrapper{width:270px;float:right;}.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control{background:none;background:#fff;border:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:focus,.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:active,.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:hover,.docs-page .docs-sidebar .docs-sidebar-wrapper input.form-control:visited{box-shadow:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version{position:relative;padding:0 1rem;margin:.25rem 0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select{border-radius:3px;border:1px solid #e9ecef;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select .input-group-text{padding:.375rem .6rem;font-size:.9rem;width:32px;height:30px;line-height:1;border-radius:0;border:1px solid #e9ecef;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control{padding:0 10px;border:0;min-height:30px;height:30px;font-size:.85em;border-radius:1px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:focus,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:active,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:hover,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control:visited,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:focus,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:active,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:hover,.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control:visited{box-shadow:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control{padding-left:6px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-filter{padding:0 1rem;margin:.5rem 0;font-size:.9em;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-filter .filter-icon i.fa{color:#ddd;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{height:100vh;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list>ul{display:block;height:calc(100vh - 220px);overflow-y:auto;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul{font-size:.935em;list-style:none;padding:0 1rem;margin:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li{margin-left:0;padding-left:24px;display:block;width:100%;position:relative;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#999;font-weight:700;padding:7px 0;display:block;border-bottom:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a:hover{color:#000;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a.last-link{top:11px;color:#aaa;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li span.tree-toggle{color:#999;padding:7px 0;display:block;border-bottom:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li .plus-icon{font-size:.85em;transition:.3s;width:18px;height:18px;text-align:center;padding:0;line-height:1;border-radius:50%;margin-right:4px;position:absolute;left:2px;top:11px;color:#aaa;cursor:default;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li .plus-icon .fa-long-arrow-right.no-link{color:#555;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li .plus-icon .fa-chevron-right{cursor:pointer;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li a{font-weight:400;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul{padding:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li ul li ul li a{font-weight:300;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#000;transition:.4s;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>span .fa{transform:rotate(90deg);color:#007bff;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree.last-link>span .fa{transform:rotate(0deg);}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:1.5rem;color:#000;font-weight:700;padding:20px 0 10px;line-height:1;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong{font-weight:300;text-transform:uppercase;font-size:.9rem;opacity:.6;}.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site{color:#000;opacity:.15;transition:.4s;font-size:.75rem;font-weight:300;}.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site:hover{text-decoration:none;opacity:.5;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:.85em;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong{display:block;}.docs-page .docs-content{overflow-x:scroll;}.docs-page .docs-content .contributors{position:absolute;top:15px;right:5px;}.docs-page .docs-content .contributors .contributors-avatar{border-radius:21px;width:21px;height:21px;}.docs-page .docs-content .contributors a{padding:0;width:21px;height:21px;display:inline-block;margin:0 0 0 2px;}.docs-page .docs-content .contributors a:hover{text-decoration:none;}.docs-page .docs-content .docs-link-btns{border-bottom:1px solid #f4f5f7;background:#fdfdfd;padding:10px 20px;margin:0 -15px;text-align:right;font-size:.8em;min-height:40px;}.docs-page .docs-content .docs-link-btns a{color:#999;}.docs-page .docs-content .docs-link-btns a:hover{color:#444;text-decoration:none;}.docs-page .docs-content .docs-link-btns .twitter{color:#00acee;}.docs-page .docs-content .docs-link-btns .linkedin{color:#0077b5;}.docs-page .docs-content .docs-link-btns .email{color:#5a5a5a;}.docs-page .docs-content .docs-link-btns .share-button{margin-left:10px;}.docs-page .docs-content .docs-text-field{padding:2rem;}.docs-page .docs-content article.docs-body{word-break:break-word;}.docs-page .docs-content article.docs-body h1{padding-top:1rem;font-size:2.25rem;padding-bottom:10px;}.docs-page .docs-content article.docs-body h2{padding-top:2rem;padding-bottom:10px;font-size:2rem;}.docs-page .docs-content article.docs-body h3,.docs-page .docs-content article.docs-body h4,.docs-page .docs-content article.docs-body h5,.docs-page .docs-content article.docs-body h6{padding-top:20px;padding-bottom:5px;font-size:1.5rem;}.docs-page .docs-content article.docs-body h1,.docs-page .docs-content article.docs-body h2,.docs-page .docs-content article.docs-body h3,.docs-page .docs-content article.docs-body h4,.docs-page .docs-content article.docs-body h5,.docs-page .docs-content article.docs-body h6{position:relative;}.docs-page .docs-content article.docs-body h1 .anchor,.docs-page .docs-content article.docs-body h2 .anchor,.docs-page .docs-content article.docs-body h3 .anchor,.docs-page .docs-content article.docs-body h4 .anchor,.docs-page .docs-content article.docs-body h5 .anchor,.docs-page .docs-content article.docs-body h6 .anchor{position:absolute;right:-26px;font-size:18px;bottom:5px;color:#999;opacity:0;transition:.5s;}.docs-page .docs-content article.docs-body h1:hover .anchor,.docs-page .docs-content article.docs-body h2:hover .anchor,.docs-page .docs-content article.docs-body h3:hover .anchor,.docs-page .docs-content article.docs-body h4:hover .anchor,.docs-page .docs-content article.docs-body h5:hover .anchor,.docs-page .docs-content article.docs-body h6:hover .anchor{opacity:1;}.docs-page .docs-content article.docs-body .blockquote{margin-bottom:1rem;margin-left:0;border-left:2px solid #808080;padding:1em;background-color:#eee;padding-bottom:.2em;}.docs-page .docs-content article.docs-body img{max-width:100%;border:1px solid #f4f5f7;margin:15px 0 25px;box-shadow:0 0 45px #f8f9fa;border-radius:6px;}.docs-page .docs-content article.docs-body table{display:block;overflow:auto;width:100%;}.docs-page .docs-content article.docs-body table thead tr{border-bottom:2px inset;}.docs-page .docs-content article.docs-body table th{font-weight:600;}.docs-page .docs-content article.docs-body table td,.docs-page .docs-content article.docs-body table th{border:1px solid #dfe2e5;padding:6px 13px;}.docs-page .docs-content article.docs-body table tr{background-color:#fff;border-top:1px solid #c6cbd1;}.docs-page .docs-content article.docs-body table tr:nth-child(2n){background-color:#f6f8fa;}.docs-page .docs-content article.docs-body table img{background-color:initial;}.docs-page .docs-page-index{min-height:96vh;}.docs-page .docs-page-index #scroll-index{max-height:96vh;}.docs-page .docs-page-index .docs-inner-anchors{position:fixed;top:0;padding:10px;font-size:.9em;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills{font-size:.92em;margin-left:15px;border-left:1px solid #eee;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link{padding:3px 14px 4px;color:#aaa;line-height:1.2;position:relative;border-left:1px solid #eee;border-radius:0;margin-left:-1px;margin-top:1px;margin-bottom:1px;transition:.2s;font-weight:normal;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-link.active{border-left:1px solid #007bff;background:none;color:#007bff;font-weight:normal;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-link.active{color:#007bff;}.docs-page .docs-page-index .docs-inner-anchors .navbar .nav-pills .nav-pills .nav-pills .nav-link.active{color:#007bff;}.docs-page .docs-page-index .docs-inner-anchors .index-scroll{margin-left:-30px;}.docs-page .docs-page-index .docs-inner-anchors .docs-anchors-wrapper{max-width:300px;float:left;}.docs-page .docs-page-index .scroll-top-btn{display:none;font-size:.85em;color:#aaa;text-decoration:none;padding-left:18px;}.docs-page .docs-page-index .scroll-top-btn.showup{display:block;}@media(min-width:1100px){.container{max-width:1080px;}.docs-page .docs-sidebar.dark-sidebar{background:#191919;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select{border:1px solid #333;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select select.form-control,.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control{background:#191919;border-color:#191919;color:#999;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control{background:#191919;border-color:#191919;color:#999;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select input.form-control::placeholder{color:#999;opacity:.5;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-version .version-select label{background:#333;border-color:#333;color:#ddd;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-filter .form-control{background:#333;color:#999;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-filter select{border:0;border-radius:6px;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-filter .filter-icon i.fa{color:#aaa;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a{color:#aaa;border-bottom:0;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a:hover{color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon{font-size:.85em;transition:.3s;width:18px;height:18px;text-align:center;padding:0;line-height:1;border-radius:50%;margin-right:4px;position:absolute;left:2px;top:11px;color:#aaa;cursor:default;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon .fa-long-arrow-right.no-link{color:#555;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon .fa-chevron-right{cursor:pointer;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li a .plus-icon.last-link{top:11px;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li span.tree-toggle{color:#555;padding:7px 0;display:block;border-bottom:0;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a{color:#fff;transition:.4s;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a span .fa{color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-sidebar-wrapper .docs-tree-list ul li.selected-tree>a span:not(.last-link) .fa{transform:rotate(90deg);color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-top .navbar-logo .navbar-brand{color:#fff;text-transform:uppercase;white-space:unset;}.docs-page .docs-sidebar.dark-sidebar .docs-top .navbar-logo .go-back-site{color:#fff;}.docs-page .docs-sidebar.dark-sidebar .docs-top .navbar-logo .navbar-logo-desc{color:#ddd;}}@media(min-width:1366px){.container{max-width:1340px;}}@media(min-width:1440px){.container{max-width:1400px;}}@media(max-width:767px){.docs-page .docs-content article.docs-body h1{padding-top:1.5rem;}.docs-page{background:#f5f7f9;}.docs-page>.container-fluid{display:block;}.docs-page>.container-fluid>.row{display:block;}.docs-page .docs-sidebar{position:fixed;max-width:100%;width:100%;display:block;padding:0 !important;top:0;left:0;z-index:100;right:0;}.docs-page .docs-sidebar .docs-sidebar-wrapper{max-width:100%;width:100%;top:0;position:relative;margin:0 !important;height:72px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list{padding:.5rem 1.5rem 2rem 1.5rem;position:fixed;top:70px;font-size:17px;left:0;width:100%;z-index:100;background:#f5f7f9;display:none;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-tree-list .docs-filter{padding:0 0 1rem !important;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version label{width:36px;text-align:center;padding-left:0;padding-right:0;display:inline-block;line-height:26px;}.docs-page .docs-sidebar .docs-sidebar-wrapper .docs-version input.form-control{padding-left:12px !important;}.docs-page .docs-sidebar .docs-top .navbar-logo{padding:0;padding-top:.3rem;display:block;text-align:center;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand{font-size:1.5rem;font-weight:700;display:block;margin-right:0;padding:7px 0 10px;text-transform:uppercase;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand .docs-logo{width:110px;}.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site{display:none;}.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc{font-size:1em;display:none;}.docs-page .docs-sidebar .docs-top .open-dmenu{position:absolute;top:10px;left:20px;}.docs-page .docs-content{padding-top:72px;max-width:100%;display:block !important;}.docs-page .docs-content .docs-text-field{padding:1rem 1.5rem;}.docs-page .docs-page-index{display:none;}}.for-mobile{display:none;}.for-desktop{display:inline-block;}pre[class*="language-"]{padding:1.4em 2em !important;margin:15px 0 25px !important;border-radius:6px;}code{padding:.2em .4em;margin:0;font-size:82%;background-color:#f0f1f3;border-radius:3px;color:#28a745;}pre code{padding:0;}pre .token.keyword{color:#569cd6;}pre .token.atrule,pre .token.attr-value,pre .token.function,pre .token.class-name{color:#d69d85;}:not(pre)>code[class*="language-"],pre[class*="language-"]{background:#191919 !important;}div.code-toolbar>.toolbar span{cursor:default;}div.code-toolbar>.toolbar a{cursor:copy;}@media(max-width:767px){body{font-size:14px;}.for-mobile{display:inline-block;}.for-desktop{display:none;}.close-mmenu,.close-dmenu{position:absolute;top:-78px;left:25px;color:#fff;font-size:68px;background:#fff;opacity:0;}.navbar{padding:.5rem 1.75rem;}.navbar .navbar-collapse{background:#38003d;position:fixed;top:86px;left:0;width:100%;height:100vh;height:calc(100vh - 86px);z-index:100 !important;}.navbar .navbar-collapse .navbar-nav{height:100vh;padding:20px 30px;overflow:auto;}.navbar .navbar-collapse .navbar-nav .nav-link{padding:1.2rem !important;}.navbar .navbar-toggler{padding:.5rem .75rem;font-size:1.5rem;line-height:1;background-color:transparent;border:0;border-radius:.25rem;color:#fff !important;margin-left:-1rem;}.section-with-logos img{margin:15px;opacity:1;-webkit-filter:grayscale(0%);filter:grayscale(0%);}span.code-arrow{padding:0 0 0;display:block;transform:rotate(90deg);font-size:2em;}.mb-5,.my-5{margin-bottom:2rem !important;}}@media screen and (max-width:767px){.navbar-logo .navbar-brand{display:inline-block;margin:0 auto !important;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}}.alert-criteria{padding:1.25em 1.5em;max-width:100%;}.alert-criteria p.alert-p{font-size:.96em;}.alert-criteria .input-group .input-group-text,.alert-criteria .input-group .form-control{font-size:.96em;}@media screen and (max-width:767px){.alert-criteria .input-group .input-group-text,.alert-criteria .input-group .form-control{font-size:.88em;}}.alert-criteria .input-group .input-group-text{color:#004085;background-color:#bddcfd;border:1px solid #bddcfd;}@media screen and (max-width:1366px){.alert-criteria .input-group .input-group-text{display:none;}}.alert-criteria .input-group .form-control{color:#004085;background-color:#fff;border:1px solid #bddcfd;}@media screen and (max-width:1366px){.alert-criteria .input-group .form-control{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;}}.scrolledMore{padding-top:107px;}.scrolledMore .alert-criteria{position:fixed;top:0;z-index:10;border:0;border-radius:0;margin-left:-47px;padding:.5em .75em;}@media screen and (max-width:767px){.scrolledMore .alert-criteria{top:72px;margin-left:-36px;}}.scrolledMore .alert-criteria p.alert-p{display:none;} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss index cf6e577a28..1f696721d4 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss @@ -329,6 +329,8 @@ body { } article.docs-body { + word-break: break-word; + h1 { padding-top: 1rem; font-size: 2.25rem; diff --git a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj index 9577e4a500..2adfb50de0 100644 --- a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj +++ b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/modules/docs/test/Volo.Docs.Admin.Application.Tests/Volo.Docs.Admin.Application.Tests.csproj b/modules/docs/test/Volo.Docs.Admin.Application.Tests/Volo.Docs.Admin.Application.Tests.csproj index 28eb762481..1063314379 100644 --- a/modules/docs/test/Volo.Docs.Admin.Application.Tests/Volo.Docs.Admin.Application.Tests.csproj +++ b/modules/docs/test/Volo.Docs.Admin.Application.Tests/Volo.Docs.Admin.Application.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/docs/test/Volo.Docs.Application.Tests/Volo.Docs.Application.Tests.csproj b/modules/docs/test/Volo.Docs.Application.Tests/Volo.Docs.Application.Tests.csproj index 6ce42e6d8e..4b86efc543 100644 --- a/modules/docs/test/Volo.Docs.Application.Tests/Volo.Docs.Application.Tests.csproj +++ b/modules/docs/test/Volo.Docs.Application.Tests/Volo.Docs.Application.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/docs/test/Volo.Docs.Domain.Tests/Volo.Docs.Domain.Tests.csproj b/modules/docs/test/Volo.Docs.Domain.Tests/Volo.Docs.Domain.Tests.csproj index 6b4a73e803..ea4e45c897 100644 --- a/modules/docs/test/Volo.Docs.Domain.Tests/Volo.Docs.Domain.Tests.csproj +++ b/modules/docs/test/Volo.Docs.Domain.Tests/Volo.Docs.Domain.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/docs/test/Volo.Docs.EntityFrameworkCore.Tests/Volo.Docs.EntityFrameworkCore.Tests.csproj b/modules/docs/test/Volo.Docs.EntityFrameworkCore.Tests/Volo.Docs.EntityFrameworkCore.Tests.csproj index 2a0b4d6d22..c17dc2c2da 100644 --- a/modules/docs/test/Volo.Docs.EntityFrameworkCore.Tests/Volo.Docs.EntityFrameworkCore.Tests.csproj +++ b/modules/docs/test/Volo.Docs.EntityFrameworkCore.Tests/Volo.Docs.EntityFrameworkCore.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo.Docs.MongoDB.Tests.csproj b/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo.Docs.MongoDB.Tests.csproj index 1d1953d9b9..3a8d3cb7d9 100644 --- a/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo.Docs.MongoDB.Tests.csproj +++ b/modules/docs/test/Volo.Docs.MongoDB.Tests/Volo.Docs.MongoDB.Tests.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/modules/docs/test/Volo.Docs.TestBase/Volo.Docs.TestBase.csproj b/modules/docs/test/Volo.Docs.TestBase/Volo.Docs.TestBase.csproj index bc767d2094..aeed82e1dd 100644 --- a/modules/docs/test/Volo.Docs.TestBase/Volo.Docs.TestBase.csproj +++ b/modules/docs/test/Volo.Docs.TestBase/Volo.Docs.TestBase.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBase.cs b/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBase.cs index e8b7fa0126..ec8270ae01 100644 --- a/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBase.cs +++ b/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBase.cs @@ -6,6 +6,7 @@ using Octokit; using Volo.Abp; using Volo.Abp.Modularity; using Volo.Docs.GitHub.Documents; +using Volo.Abp.Testing; namespace Volo.Docs { @@ -32,6 +33,7 @@ namespace Volo.Docs "https://api.github.com/repos/abpframework/abp/releases/16293679/assets", "https://uploads.github.com/repos/abpframework/abp/releases/16293679/assets{?name,label}", 16293679, + "", "0.15.0", "master", "0.15.0", diff --git a/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBaseModule.cs b/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBaseModule.cs index a4661075d0..ffc11fd134 100644 --- a/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBaseModule.cs +++ b/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestBaseModule.cs @@ -3,6 +3,7 @@ using Volo.Abp; using Volo.Abp.Authorization; using Volo.Abp.Autofac; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Docs { @@ -28,9 +29,9 @@ namespace Volo.Docs { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestDataBuilder.cs b/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestDataBuilder.cs index 15fa70eee7..121d18b44a 100644 --- a/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestDataBuilder.cs +++ b/modules/docs/test/Volo.Docs.TestBase/Volo/Docs/DocsTestDataBuilder.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Data; +using System.Threading.Tasks; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Docs.GitHub.Documents; using Volo.Docs.Projects; @@ -18,7 +19,7 @@ namespace Volo.Docs _projectRepository = projectRepository; } - public void Build() + public async Task BuildAsync() { var project = new Project( _testData.PorjectId, @@ -36,7 +37,7 @@ namespace Volo.Docs .SetProperty("GitHubAccessToken", "123456") .SetProperty("GitHubUserAgent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); - _projectRepository.Insert(project); + await _projectRepository.InsertAsync(project); } } } \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs index 097ea7ffa0..2290e79f00 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.FeatureManagement public virtual async Task GetAsync([NotNull] string providerName, [NotNull] string providerKey) { - await CheckProviderPolicy(providerName); + await CheckProviderPolicy(providerName).ConfigureAwait(false); var featureDefinitions = _featureDefinitionManager.GetAll(); var features = new List(); @@ -48,7 +48,7 @@ namespace Volo.Abp.FeatureManagement ValueType = featureDefinition.ValueType, Description = featureDefinition.Description?.Localize(_stringLocalizerFactory), ParentName = featureDefinition.Parent?.Name, - Value = await _featureManager.GetOrNullAsync(featureDefinition.Name, providerName, providerKey) + Value = await _featureManager.GetOrNullAsync(featureDefinition.Name, providerName, providerKey).ConfigureAwait(false) }); } @@ -59,11 +59,11 @@ namespace Volo.Abp.FeatureManagement public virtual async Task UpdateAsync([NotNull] string providerName, [NotNull] string providerKey, UpdateFeaturesDto input) { - await CheckProviderPolicy(providerName); + await CheckProviderPolicy(providerName).ConfigureAwait(false); foreach (var feature in input.Features) { - await _featureManager.SetAsync(feature.Name, feature.Value, providerName, providerKey); + await _featureManager.SetAsync(feature.Name, feature.Value, providerName, providerKey).ConfigureAwait(false); } } @@ -88,7 +88,7 @@ namespace Volo.Abp.FeatureManagement throw new AbpException($"No policy defined to get/set permissions for the provider '{policyName}'. Use {nameof(FeatureManagementOptions)} to map the policy."); } - await AuthorizationService.CheckAsync(policyName); + await AuthorizationService.CheckAsync(policyName).ConfigureAwait(false); } } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj index 5990dc210c..bfa20270c8 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj @@ -13,7 +13,7 @@ - + diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs index f91fe28e5f..0c9a2e0f26 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs @@ -1,13 +1,14 @@ using Volo.Abp.FeatureManagement.Localization; using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.FeatureManagement { [DependsOn( - typeof(AbpLocalizationModule) + typeof(AbpValidationModule) )] public class AbpFeatureManagementDomainSharedModule : AbpModule { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json index 8cbecf08ab..47f49bbc50 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/cs.json @@ -1,6 +1,7 @@ { "culture": "cs", "texts": { - "Features": "Funkce" + "Features": "Funkce", + "NoFeatureFoundMessage": "Nejsou zde dostupné žádné funkce." } } \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json new file mode 100644 index 0000000000..bc4dbf268f --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "Features": "功能", + "NoFeatureFoundMessage": "沒有可用的功能." + } +} \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs index 1d0c59773b..58353321fa 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs @@ -16,17 +16,17 @@ namespace Volo.Abp.FeatureManagement public async Task GetOrNullAsync(FeatureDefinition feature, string providerKey) { - return await Store.GetOrNullAsync(feature.Name, Name, NormalizeProviderKey(providerKey)); + return await Store.GetOrNullAsync(feature.Name, Name, NormalizeProviderKey(providerKey)).ConfigureAwait(false); } public virtual async Task SetAsync(FeatureDefinition feature, string value, string providerKey) { - await Store.SetAsync(feature.Name, value, Name, NormalizeProviderKey(providerKey)); + await Store.SetAsync(feature.Name, value, Name, NormalizeProviderKey(providerKey)).ConfigureAwait(false); } public virtual async Task ClearAsync(FeatureDefinition feature, string providerKey) { - await Store.DeleteAsync(feature.Name, Name, NormalizeProviderKey(providerKey)); + await Store.DeleteAsync(feature.Name, Name, NormalizeProviderKey(providerKey)).ConfigureAwait(false); } protected virtual string NormalizeProviderKey(string providerKey) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs index 94c4d48067..2970296381 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs @@ -23,52 +23,52 @@ namespace Volo.Abp.FeatureManagement public async Task GetOrNullAsync(string name, string providerName, string providerKey) { - var cacheItem = await GetCacheItemAsync(name, providerName, providerKey); + var cacheItem = await GetCacheItemAsync(name, providerName, providerKey).ConfigureAwait(false); return cacheItem.Value; } public async Task SetAsync(string name, string value, string providerName, string providerKey) { - var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey); + var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey).ConfigureAwait(false); if (featureValue == null) { featureValue = new FeatureValue(GuidGenerator.Create(), name, value, providerName, providerKey); - await FeatureValueRepository.InsertAsync(featureValue); + await FeatureValueRepository.InsertAsync(featureValue).ConfigureAwait(false); } else { featureValue.Value = value; - await FeatureValueRepository.UpdateAsync(featureValue); + await FeatureValueRepository.UpdateAsync(featureValue).ConfigureAwait(false); } } public async Task DeleteAsync(string name, string providerName, string providerKey) { - var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey); + var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey).ConfigureAwait(false); if (featureValue != null) { - await FeatureValueRepository.DeleteAsync(featureValue); + await FeatureValueRepository.DeleteAsync(featureValue).ConfigureAwait(false); } } protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey) { var cacheKey = CalculateCacheKey(name, providerName, providerKey); - var cacheItem = await Cache.GetAsync(cacheKey); + var cacheItem = await Cache.GetAsync(cacheKey).ConfigureAwait(false); if (cacheItem != null) { return cacheItem; } - var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey); + var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey).ConfigureAwait(false); cacheItem = new FeatureValueCacheItem(featureValue?.Value); await Cache.SetAsync( cacheKey, cacheItem - ); + ).ConfigureAwait(false); return cacheItem; } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs index 06ca345bf6..8249166f20 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs @@ -82,7 +82,7 @@ namespace Volo.Abp.FeatureManagement var providerValue = await provider.GetOrNullAsync( feature, provider.Name == providerName ? providerKey : null - ); + ).ConfigureAwait(false); if (providerValue != null) { @@ -123,7 +123,7 @@ namespace Volo.Abp.FeatureManagement if (providers.Count > 1 && !forceToSet && value != null) { - var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null); + var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null).ConfigureAwait(false); if (fallbackValue == value) { //Clear the value if it's same as it's fallback value @@ -139,14 +139,14 @@ namespace Volo.Abp.FeatureManagement { foreach (var provider in providers) { - await provider.ClearAsync(feature, providerKey); + await provider.ClearAsync(feature, providerKey).ConfigureAwait(false); } } else { foreach (var provider in providers) { - await provider.SetAsync(feature, value, providerKey); + await provider.SetAsync(feature, value, providerKey).ConfigureAwait(false); } } } @@ -172,7 +172,7 @@ namespace Volo.Abp.FeatureManagement value = await provider.GetOrNullAsync( feature, provider.Name == providerName ? providerKey : null - ); + ).ConfigureAwait(false); if (value != null) { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs index 765e6c9b32..98d3c07e64 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs @@ -1,8 +1,10 @@ using System; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.FeatureManagement { [Serializable] + [IgnoreMultiTenancy] public class FeatureValueCacheItem { public string Value { get; set; } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs index 63e207b1e7..1d13d46e0a 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.FeatureManagement eventData.Entity.ProviderKey ); - await Cache.RemoveAsync(cacheKey); + await Cache.RemoveAsync(cacheKey).ConfigureAwait(false); } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo.Abp.FeatureManagement.EntityFrameworkCore.csproj b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo.Abp.FeatureManagement.EntityFrameworkCore.csproj index 297d7fcaa4..54b94c7eef 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo.Abp.FeatureManagement.EntityFrameworkCore.csproj +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo.Abp.FeatureManagement.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs index 9545ac36b4..87251ff366 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore return await DbSet .FirstOrDefaultAsync( s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey - ); + ).ConfigureAwait(false); } public async Task> GetListAsync(string providerName, string providerKey) @@ -28,7 +28,7 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore return await DbSet .Where( s => s.ProviderName == providerName && s.ProviderKey == providerKey - ).ToListAsync(); + ).ToListAsync().ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs index f57d125dce..62e112b764 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs @@ -19,14 +19,14 @@ namespace Volo.Abp.FeatureManagement.MongoDB public async Task FindAsync(string name, string providerName, string providerKey) { return await GetMongoQueryable() - .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); + .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ConfigureAwait(false); } public async Task> GetListAsync(string providerName, string providerKey) { return await GetMongoQueryable() .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml index 59e80e236c..221b46bea6 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml @@ -24,7 +24,7 @@ @feature.Name - + @if (feature.ValueType is FreeTextStringValueType) { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs index d9e0d7b2c4..4360e0d72c 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs @@ -36,7 +36,7 @@ namespace Volo.Abp.FeatureManagement.Web.Pages.FeatureManagement public async Task OnGetAsync() { - FeatureListDto = await _featureAppService.GetAsync(ProviderName, ProviderKey); + FeatureListDto = await _featureAppService.GetAsync(ProviderName, ProviderKey).ConfigureAwait(false); } public async Task OnPostAsync() @@ -50,7 +50,7 @@ namespace Volo.Abp.FeatureManagement.Web.Pages.FeatureManagement }).ToList() }; - await _featureAppService.UpdateAsync(ProviderName, ProviderKey, features); + await _featureAppService.UpdateAsync(ProviderName, ProviderKey, features).ConfigureAwait(false); return NoContent(); } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo.Abp.FeatureManagement.Application.Tests.csproj b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo.Abp.FeatureManagement.Application.Tests.csproj index e155dc4425..ef81b4b9ea 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo.Abp.FeatureManagement.Application.Tests.csproj +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo.Abp.FeatureManagement.Application.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs index b86e6be013..8987a232b0 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs @@ -39,7 +39,7 @@ namespace Volo.Abp.FeatureManagement Login(_testData.User1Id); var featureList = await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()); + TestEditionIds.Regular.ToString()).ConfigureAwait(false); featureList.ShouldNotBeNull(); featureList.Features.ShouldContain(feature => feature.Name == TestFeatureDefinitionProvider.SocialLogins); @@ -61,10 +61,10 @@ namespace Volo.Abp.FeatureManagement Value = false.ToString().ToLowerInvariant() } } - }); + }).ConfigureAwait(false); (await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).Features.Any(x => + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).Features.Any(x => x.Name == TestFeatureDefinitionProvider.SocialLogins && x.Value == false.ToString().ToLowerInvariant()) .ShouldBeTrue(); diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo.Abp.FeatureManagement.Domain.Tests.csproj b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo.Abp.FeatureManagement.Domain.Tests.csproj index 80e20e1c81..585f399d3e 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo.Abp.FeatureManagement.Domain.Tests.csproj +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo.Abp.FeatureManagement.Domain.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs index bae9041a51..ac75fdd86e 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs @@ -1,6 +1,8 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Shouldly; using Volo.Abp.Features; +using Volo.Abp.MultiTenancy; using Xunit; namespace Volo.Abp.FeatureManagement @@ -8,10 +10,14 @@ namespace Volo.Abp.FeatureManagement public class FeatureManager_Tests : FeatureManagementDomainTestBase { private readonly IFeatureManager _featureManager; + private readonly ICurrentTenant _currentTenant; + private readonly IFeatureChecker _featureChecker; public FeatureManager_Tests() { _featureManager = GetRequiredService(); + _featureChecker = GetRequiredService(); + _currentTenant = GetRequiredService(); } [Fact] @@ -21,63 +27,89 @@ namespace Volo.Abp.FeatureManagement (await _featureManager.GetOrNullDefaultAsync( TestFeatureDefinitionProvider.SocialLogins - )).ShouldBeNull(); + ).ConfigureAwait(false)).ShouldBeNull(); (await _featureManager.GetOrNullDefaultAsync( TestFeatureDefinitionProvider.DailyAnalysis - )).ShouldBe(false.ToString().ToLowerInvariant()); + ).ConfigureAwait(false)).ShouldBe(false.ToString().ToLowerInvariant()); (await _featureManager.GetOrNullDefaultAsync( TestFeatureDefinitionProvider.ProjectCount - )).ShouldBe("1"); + ).ConfigureAwait(false)).ShouldBe("1"); (await _featureManager.GetOrNullDefaultAsync( TestFeatureDefinitionProvider.BackupCount - )).ShouldBe("0"); + ).ConfigureAwait(false)).ShouldBe("0"); //"Enterprise" edition values (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.SocialLogins, TestEditionIds.Enterprise - )).ShouldBe(true.ToString().ToLowerInvariant()); + ).ConfigureAwait(false)).ShouldBe(true.ToString().ToLowerInvariant()); (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.DailyAnalysis, TestEditionIds.Enterprise - )).ShouldBe(false.ToString().ToLowerInvariant()); + ).ConfigureAwait(false)).ShouldBe(false.ToString().ToLowerInvariant()); (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.ProjectCount, TestEditionIds.Enterprise - )).ShouldBe("3"); + ).ConfigureAwait(false)).ShouldBe("3"); (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.BackupCount, TestEditionIds.Enterprise - )).ShouldBe("5"); + ).ConfigureAwait(false)).ShouldBe("5"); //"Ultimate" edition values (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.SocialLogins, TestEditionIds.Ultimate - )).ShouldBe(true.ToString().ToLowerInvariant()); + ).ConfigureAwait(false)).ShouldBe(true.ToString().ToLowerInvariant()); (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.DailyAnalysis, TestEditionIds.Ultimate - )).ShouldBe(true.ToString().ToLowerInvariant()); + ).ConfigureAwait(false)).ShouldBe(true.ToString().ToLowerInvariant()); (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.ProjectCount, TestEditionIds.Ultimate - )).ShouldBe("10"); + ).ConfigureAwait(false)).ShouldBe("10"); (await _featureManager.GetOrNullForEditionAsync( TestFeatureDefinitionProvider.BackupCount, TestEditionIds.Ultimate - )).ShouldBe("10"); + ).ConfigureAwait(false)).ShouldBe("10"); + } + + [Fact] + public async Task Should_Change_Feature_Value_And_Refresh_Cache() + { + var tenantId = Guid.NewGuid(); + + //It is "False" at the beginning + using (_currentTenant.Change(tenantId)) + { + (await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse(); + } + + //Set to "True" by host for the tenant + using (_currentTenant.Change(null)) + { + (await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse(); + await _featureManager.SetForTenantAsync(tenantId, TestFeatureDefinitionProvider.SocialLogins, "True"); + (await _featureManager.GetOrNullForTenantAsync(TestFeatureDefinitionProvider.SocialLogins, tenantId)).ShouldBe("True"); + } + + //Now, it should be "True" + using (_currentTenant.Change(tenantId)) + { + (await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeTrue(); + } } } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs index ce74094f97..7b3aa9f256 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs @@ -26,21 +26,31 @@ namespace Volo.Abp.FeatureManagement public async Task Cache_Should_Invalidator_WhenFeatureChanged() { // Arrange cache feature. - await _featureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, - EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()); + (await _featureManagementStore.GetOrNullAsync( + TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString() + ).ConfigureAwait(false) + ).ShouldNotBeNull(); - var feature = await _featureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins, + var feature = await _featureValueRepository.FindAsync( + TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()); + TestEditionIds.Regular.ToString() + ).ConfigureAwait(false); // Act - await _featureValueRepository.DeleteAsync(feature); + await _featureValueRepository.DeleteAsync(feature).ConfigureAwait(false); // Assert - (await _cache.GetAsync(FeatureValueCacheItem.CalculateCacheKey(TestFeatureDefinitionProvider.SocialLogins, - EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()))).ShouldBeNull(); + (await _cache.GetAsync( + FeatureValueCacheItem.CalculateCacheKey( + TestFeatureDefinitionProvider.SocialLogins, + EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString() + ) + ).ConfigureAwait(false) + ).ShouldBeNull(); } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests.csproj b/modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests.csproj index 2c84ab25bb..8a8b62a666 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests.csproj +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo.Abp.FeatureManagement.MongoDB.Tests.csproj b/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo.Abp.FeatureManagement.MongoDB.Tests.csproj index 8c217b529c..37ebd8aa4a 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo.Abp.FeatureManagement.MongoDB.Tests.csproj +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo.Abp.FeatureManagement.MongoDB.Tests.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo.Abp.FeatureManagement.TestBase.csproj b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo.Abp.FeatureManagement.TestBase.csproj index 21d4cbc76c..571adf02c8 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo.Abp.FeatureManagement.TestBase.csproj +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo.Abp.FeatureManagement.TestBase.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs index a6f040dde3..500e28233c 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs @@ -27,11 +27,11 @@ namespace Volo.Abp.FeatureManagement // Act (await FeatureManagementStore.GetOrNullAsync(Guid.NewGuid().ToString(), EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).ShouldBeNull(); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).ShouldBeNull(); (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).ShouldNotBeNull(); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] @@ -40,17 +40,17 @@ namespace Volo.Abp.FeatureManagement // Arrange (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).ShouldNotBeNull(); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).ShouldNotBeNull(); // Act await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()); + TestEditionIds.Regular.ToString()).ConfigureAwait(false); // Assert (await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).ShouldBeNull(); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).ShouldBeNull(); } [Fact] @@ -59,18 +59,18 @@ namespace Volo.Abp.FeatureManagement // Arrange (await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).Value.ShouldBe(true.ToString().ToLowerInvariant()); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).Value.ShouldBe(true.ToString().ToLowerInvariant()); // Act await FeatureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins, false.ToString().ToUpperInvariant(), EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()); + TestEditionIds.Regular.ToString()).ConfigureAwait(false); // Assert (await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).Value.ShouldBe(false.ToString().ToUpperInvariant()); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).Value.ShouldBe(false.ToString().ToUpperInvariant()); } [Fact] @@ -79,18 +79,18 @@ namespace Volo.Abp.FeatureManagement // Arrange (await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).ShouldNotBeNull(); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).ShouldNotBeNull(); // Act await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString()); + TestEditionIds.Regular.ToString()).ConfigureAwait(false); // Assert (await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins, EditionFeatureValueProvider.ProviderName, - TestEditionIds.Regular.ToString())).ShouldBeNull(); + TestEditionIds.Regular.ToString()).ConfigureAwait(false)).ShouldBeNull(); } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBase.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBase.cs index 66ab983ebe..b5b72ab0d0 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBase.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.FeatureManagement { diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBaseModule.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBaseModule.cs index 48a90400c8..1de262fd7b 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBaseModule.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBaseModule.cs @@ -3,6 +3,7 @@ using Volo.Abp.Authorization; using Volo.Abp.Autofac; using Volo.Abp.Features; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.FeatureManagement { @@ -37,9 +38,9 @@ namespace Volo.Abp.FeatureManagement { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestDataBuilder.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestDataBuilder.cs index 6c6a835109..dc286e6782 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestDataBuilder.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestDataBuilder.cs @@ -1,4 +1,5 @@ -using Volo.Abp.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; using Volo.Abp.Features; using Volo.Abp.Guids; @@ -20,12 +21,12 @@ namespace Volo.Abp.FeatureManagement _featureValueRepository = featureValueRepository; } - public void Build() + public async Task BuildAsync() { #region "Regular" edition features //SocialLogins - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.SocialLogins, @@ -33,10 +34,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Regular.ToString() ) - ); + ).ConfigureAwait(false); //UserCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.UserCount, @@ -44,10 +45,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Regular.ToString() ) - ); + ).ConfigureAwait(false); //ProjectCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.ProjectCount, @@ -55,14 +56,14 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Regular.ToString() ) - ); + ).ConfigureAwait(false); #endregion #region "Enterprise" edition features //SocialLogins - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.SocialLogins, @@ -70,10 +71,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() ) - ); + ).ConfigureAwait(false); //EmailSupport - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.EmailSupport, @@ -81,10 +82,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() ) - ); + ).ConfigureAwait(false); //UserCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.UserCount, @@ -92,10 +93,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() ) - ); + ).ConfigureAwait(false); //ProjectCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.ProjectCount, @@ -103,10 +104,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() ) - ); + ).ConfigureAwait(false); //BackupCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.BackupCount, @@ -114,14 +115,14 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() ) - ); + ).ConfigureAwait(false); #endregion #region "Ultimate" edition features //SocialLogins - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.SocialLogins, @@ -129,10 +130,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Ultimate.ToString() ) - ); + ).ConfigureAwait(false); //EmailSupport - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.EmailSupport, @@ -140,10 +141,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Ultimate.ToString() ) - ); + ).ConfigureAwait(false); //EmailSupport - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.DailyAnalysis, @@ -151,10 +152,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Ultimate.ToString() ) - ); + ).ConfigureAwait(false); //UserCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.UserCount, @@ -162,10 +163,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Ultimate.ToString() ) - ); + ).ConfigureAwait(false); //ProjectCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.ProjectCount, @@ -173,10 +174,10 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Ultimate.ToString() ) - ); + ).ConfigureAwait(false); //BackupCount - _featureValueRepository.Insert( + await _featureValueRepository.InsertAsync( new FeatureValue( _guidGenerator.Create(), TestFeatureDefinitionProvider.BackupCount, @@ -184,7 +185,7 @@ namespace Volo.Abp.FeatureManagement EditionFeatureValueProvider.ProviderName, TestEditionIds.Ultimate.ToString() ) - ); + ).ConfigureAwait(false); #endregion } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs index c7cbb0d8ae..8c3904ef24 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.FeatureManagement TestFeatureDefinitionProvider.ProjectCount, EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() - ); + ).ConfigureAwait(false); featureValue.ShouldNotBeNull(); featureValue.Value.ShouldBe("3"); @@ -35,7 +35,7 @@ namespace Volo.Abp.FeatureManagement TestFeatureDefinitionProvider.ProjectCount, EditionFeatureValueProvider.ProviderName, "undefined-edition-id" - ); + ).ConfigureAwait(false); featureValue.ShouldBeNull(); } @@ -46,7 +46,7 @@ namespace Volo.Abp.FeatureManagement var featureValues = await Repository.GetListAsync( EditionFeatureValueProvider.ProviderName, TestEditionIds.Enterprise.ToString() - ); + ).ConfigureAwait(false); featureValues.Count.ShouldBeGreaterThan(0); diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs index 3fec60599d..0f573634a4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.Identity { public interface IIdentityRoleAppService : IApplicationService { - Task> GetListAsync(); + Task> GetListAsync(PagedAndSortedResultRequestDto input); Task CreateAsync(IdentityRoleCreateDto input); diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs index 0c1750f2fb..44b97a82ea 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs @@ -24,15 +24,18 @@ namespace Volo.Abp.Identity public virtual async Task GetAsync(Guid id) { return ObjectMapper.Map( - await _roleManager.GetByIdAsync(id) - ); + await _roleManager.GetByIdAsync(id).ConfigureAwait(false)); } - public virtual async Task> GetListAsync() + public virtual async Task> GetListAsync(PagedAndSortedResultRequestDto input) { - var list = await _roleRepository.GetListAsync(); + var list = await _roleRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount).ConfigureAwait(false); + var totalCount = await _roleRepository.GetCountAsync().ConfigureAwait(false); - return new ListResultDto(ObjectMapper.Map, List>(list)); + return new PagedResultDto( + totalCount, + ObjectMapper.Map, List>(list) + ); } [Authorize(IdentityPermissions.Roles.Create)] @@ -43,8 +46,8 @@ namespace Volo.Abp.Identity role.IsDefault = input.IsDefault; role.IsPublic = input.IsPublic; - (await _roleManager.CreateAsync(role)).CheckErrors(); - await CurrentUnitOfWork.SaveChangesAsync(); + (await _roleManager.CreateAsync(role).ConfigureAwait(false)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync().ConfigureAwait(false); return ObjectMapper.Map(role); } @@ -52,16 +55,16 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Roles.Update)] public virtual async Task UpdateAsync(Guid id, IdentityRoleUpdateDto input) { - var role = await _roleManager.GetByIdAsync(id); + var role = await _roleManager.GetByIdAsync(id).ConfigureAwait(false); role.ConcurrencyStamp = input.ConcurrencyStamp; - (await _roleManager.SetRoleNameAsync(role, input.Name)).CheckErrors(); + (await _roleManager.SetRoleNameAsync(role, input.Name).ConfigureAwait(false)).CheckErrors(); role.IsDefault = input.IsDefault; role.IsPublic = input.IsPublic; - (await _roleManager.UpdateAsync(role)).CheckErrors(); - await CurrentUnitOfWork.SaveChangesAsync(); + (await _roleManager.UpdateAsync(role).ConfigureAwait(false)).CheckErrors(); + await CurrentUnitOfWork.SaveChangesAsync().ConfigureAwait(false); return ObjectMapper.Map(role); } @@ -69,13 +72,13 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Roles.Delete)] public virtual async Task DeleteAsync(Guid id) { - var role = await _roleManager.FindByIdAsync(id.ToString()); + var role = await _roleManager.FindByIdAsync(id.ToString()).ConfigureAwait(false); if (role == null) { return; } - (await _roleManager.DeleteAsync(role)).CheckErrors(); + (await _roleManager.DeleteAsync(role).ConfigureAwait(false)).CheckErrors(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index c1d0f8f28b..365fac604f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -26,14 +26,14 @@ namespace Volo.Abp.Identity { return ObjectMapper.Map( await _userManager.GetByIdAsync(id) - ); +.ConfigureAwait(false)); } [Authorize(IdentityPermissions.Users.Default)] public virtual async Task> GetListAsync(GetIdentityUsersInput input) { - var count = await _userRepository.GetCountAsync(input.Filter); - var list = await _userRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter); + var count = await _userRepository.GetCountAsync(input.Filter).ConfigureAwait(false); + var list = await _userRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter).ConfigureAwait(false); return new PagedResultDto( count, @@ -44,7 +44,7 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Users.Default)] public virtual async Task> GetRolesAsync(Guid id) { - var roles = await _userRepository.GetRolesAsync(id); + var roles = await _userRepository.GetRolesAsync(id).ConfigureAwait(false); return new ListResultDto( ObjectMapper.Map, List>(roles) ); @@ -55,10 +55,10 @@ namespace Volo.Abp.Identity { var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.Email, CurrentTenant.Id); - (await _userManager.CreateAsync(user, input.Password)).CheckErrors(); - await UpdateUserByInput(user, input); + (await _userManager.CreateAsync(user, input.Password).ConfigureAwait(false)).CheckErrors(); + await UpdateUserByInput(user, input).ConfigureAwait(false); - await CurrentUnitOfWork.SaveChangesAsync(); + await CurrentUnitOfWork.SaveChangesAsync().ConfigureAwait(false); return ObjectMapper.Map(user); } @@ -66,20 +66,20 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Users.Update)] public virtual async Task UpdateAsync(Guid id, IdentityUserUpdateDto input) { - var user = await _userManager.GetByIdAsync(id); + var user = await _userManager.GetByIdAsync(id).ConfigureAwait(false); user.ConcurrencyStamp = input.ConcurrencyStamp; - (await _userManager.SetUserNameAsync(user, input.UserName)).CheckErrors(); - await UpdateUserByInput(user, input); - (await _userManager.UpdateAsync(user)).CheckErrors(); + (await _userManager.SetUserNameAsync(user, input.UserName).ConfigureAwait(false)).CheckErrors(); + await UpdateUserByInput(user, input).ConfigureAwait(false); + (await _userManager.UpdateAsync(user).ConfigureAwait(false)).CheckErrors(); if (!input.Password.IsNullOrEmpty()) { - (await _userManager.RemovePasswordAsync(user)).CheckErrors(); - (await _userManager.AddPasswordAsync(user, input.Password)).CheckErrors(); + (await _userManager.RemovePasswordAsync(user).ConfigureAwait(false)).CheckErrors(); + (await _userManager.AddPasswordAsync(user, input.Password).ConfigureAwait(false)).CheckErrors(); } - await CurrentUnitOfWork.SaveChangesAsync(); + await CurrentUnitOfWork.SaveChangesAsync().ConfigureAwait(false); return ObjectMapper.Map(user); } @@ -92,21 +92,21 @@ namespace Volo.Abp.Identity throw new BusinessException(code: IdentityErrorCodes.UserSelfDeletion); } - var user = await _userManager.FindByIdAsync(id.ToString()); + var user = await _userManager.FindByIdAsync(id.ToString()).ConfigureAwait(false); if (user == null) { return; } - (await _userManager.DeleteAsync(user)).CheckErrors(); + (await _userManager.DeleteAsync(user).ConfigureAwait(false)).CheckErrors(); } [Authorize(IdentityPermissions.Users.Update)] public virtual async Task UpdateRolesAsync(Guid id, IdentityUserUpdateRolesDto input) { - var user = await _userManager.GetByIdAsync(id); - (await _userManager.SetRolesAsync(user, input.RoleNames)).CheckErrors(); - await _userRepository.UpdateAsync(user); + var user = await _userManager.GetByIdAsync(id).ConfigureAwait(false); + (await _userManager.SetRolesAsync(user, input.RoleNames).ConfigureAwait(false)).CheckErrors(); + await _userRepository.UpdateAsync(user).ConfigureAwait(false); } [Authorize(IdentityPermissions.Users.Default)] @@ -114,7 +114,7 @@ namespace Volo.Abp.Identity { return ObjectMapper.Map( await _userManager.FindByNameAsync(username) - ); +.ConfigureAwait(false)); } [Authorize(IdentityPermissions.Users.Default)] @@ -122,30 +122,30 @@ namespace Volo.Abp.Identity { return ObjectMapper.Map( await _userManager.FindByEmailAsync(email) - ); +.ConfigureAwait(false)); } private async Task UpdateUserByInput(IdentityUser user, IdentityUserCreateOrUpdateDtoBase input) { if (!string.Equals(user.Email, input.Email, StringComparison.InvariantCultureIgnoreCase)) { - (await _userManager.SetEmailAsync(user, input.Email)).CheckErrors(); + (await _userManager.SetEmailAsync(user, input.Email).ConfigureAwait(false)).CheckErrors(); } if (!string.Equals(user.PhoneNumber, input.PhoneNumber, StringComparison.InvariantCultureIgnoreCase)) { - (await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors(); + (await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber).ConfigureAwait(false)).CheckErrors(); } - (await _userManager.SetTwoFactorEnabledAsync(user, input.TwoFactorEnabled)).CheckErrors(); - (await _userManager.SetLockoutEnabledAsync(user, input.LockoutEnabled)).CheckErrors(); + (await _userManager.SetTwoFactorEnabledAsync(user, input.TwoFactorEnabled).ConfigureAwait(false)).CheckErrors(); + (await _userManager.SetLockoutEnabledAsync(user, input.LockoutEnabled).ConfigureAwait(false)).CheckErrors(); user.Name = input.Name; user.Surname = input.Surname; if (input.RoleNames != null) { - (await _userManager.SetRolesAsync(user, input.RoleNames)).CheckErrors(); + (await _userManager.SetRolesAsync(user, input.RoleNames).ConfigureAwait(false)).CheckErrors(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs index 48d42c4579..ca2b25f83b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserLookupAppService.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.Identity public virtual async Task FindByIdAsync(Guid id) { - var userData = await UserLookupServiceProvider.FindByIdAsync(id); + var userData = await UserLookupServiceProvider.FindByIdAsync(id).ConfigureAwait(false); if (userData == null) { return null; @@ -29,7 +29,7 @@ namespace Volo.Abp.Identity public virtual async Task FindByUserNameAsync(string userName) { - var userData = await UserLookupServiceProvider.FindByUserNameAsync(userName); + var userData = await UserLookupServiceProvider.FindByUserNameAsync(userName).ConfigureAwait(false); if (userData == null) { return null; diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs index 0b8712b93d..04d2c55a0b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs @@ -21,39 +21,39 @@ namespace Volo.Abp.Identity { return ObjectMapper.Map( await _userManager.GetByIdAsync(CurrentUser.GetId()) - ); +.ConfigureAwait(false)); } public virtual async Task UpdateAsync(UpdateProfileDto input) { - var user = await _userManager.GetByIdAsync(CurrentUser.GetId()); + var user = await _userManager.GetByIdAsync(CurrentUser.GetId()).ConfigureAwait(false); - if (await SettingProvider.IsTrueAsync(IdentitySettingNames.User.IsUserNameUpdateEnabled)) + if (await SettingProvider.IsTrueAsync(IdentitySettingNames.User.IsUserNameUpdateEnabled).ConfigureAwait(false)) { - (await _userManager.SetUserNameAsync(user, input.UserName)).CheckErrors(); + (await _userManager.SetUserNameAsync(user, input.UserName).ConfigureAwait(false)).CheckErrors(); } - if (await SettingProvider.IsTrueAsync(IdentitySettingNames.User.IsEmailUpdateEnabled)) + if (await SettingProvider.IsTrueAsync(IdentitySettingNames.User.IsEmailUpdateEnabled).ConfigureAwait(false)) { - (await _userManager.SetEmailAsync(user, input.Email)).CheckErrors(); + (await _userManager.SetEmailAsync(user, input.Email).ConfigureAwait(false)).CheckErrors(); } - (await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors(); + (await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber).ConfigureAwait(false)).CheckErrors(); user.Name = input.Name; user.Surname = input.Surname; - (await _userManager.UpdateAsync(user)).CheckErrors(); + (await _userManager.UpdateAsync(user).ConfigureAwait(false)).CheckErrors(); - await CurrentUnitOfWork.SaveChangesAsync(); + await CurrentUnitOfWork.SaveChangesAsync().ConfigureAwait(false); return ObjectMapper.Map(user); } public virtual async Task ChangePasswordAsync(ChangePasswordInput input) { - var currentUser = await _userManager.GetByIdAsync(CurrentUser.GetId()); - (await _userManager.ChangePasswordAsync(currentUser, input.CurrentPassword, input.NewPassword)).CheckErrors(); + var currentUser = await _userManager.GetByIdAsync(CurrentUser.GetId()).ConfigureAwait(false); + (await _userManager.ChangePasswordAsync(currentUser, input.CurrentPassword, input.NewPassword).ConfigureAwait(false)).CheckErrors(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo.Abp.Identity.Domain.Shared.csproj b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo.Abp.Identity.Domain.Shared.csproj index 6b58f2e433..460f5285e4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo.Abp.Identity.Domain.Shared.csproj +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo.Abp.Identity.Domain.Shared.csproj @@ -20,7 +20,7 @@ - + diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/AbpIdentityDomainSharedModule.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/AbpIdentityDomainSharedModule.cs index 5133e0dc03..4bff33d58a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/AbpIdentityDomainSharedModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/AbpIdentityDomainSharedModule.cs @@ -1,15 +1,18 @@ using Volo.Abp.Identity.Localization; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; using Volo.Abp.Users; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Identity { - [DependsOn(typeof(AbpUsersDomainSharedModule))] - [DependsOn(typeof(AbpLocalizationModule))] + [DependsOn( + typeof(AbpUsersDomainSharedModule), + typeof(AbpValidationModule) + )] public class AbpIdentityDomainSharedModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs index f56a59e967..ef2cc57ef4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.Identity public const int MaxPhoneNumberLength = AbpUserConsts.MaxPhoneNumberLength; - public const int MaxPasswordLength = 32; + public const int MaxPasswordLength = 128; public const int MaxPasswordHashLength = 256; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json index 0f87bec5e5..8517adcf12 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json @@ -71,6 +71,32 @@ "Permission:Delete": "Smazat", "Permission:ChangePermissions": "Změnit oprávnění", "Permission:UserManagement": "Správa uživatelů", - "Permission:UserLookup": "Vyhledání uživatele" + "Permission:UserLookup": "Vyhledání uživatele", + "DisplayName:Abp.Identity.Password.RequiredLength": "Požadovaná délka", + "DisplayName:Abp.Identity.Password.RequiredUniqueChars": "Požadovaný počet unikátních znaků", + "DisplayName:Abp.Identity.Password.RequireNonAlphanumeric": "Požadován nealfanumerický znak", + "DisplayName:Abp.Identity.Password.RequireLowercase": "Požadováno malé písmeno", + "DisplayName:Abp.Identity.Password.RequireUppercase": "Požadováno velké písmeno", + "DisplayName:Abp.Identity.Password.RequireDigit": "Požadováno číslo", + "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Povoleno pro nové uživatele", + "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Délka blokování (sekundy)", + "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maximální počet neúspěšných pokusů o přístup", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedEmail": "Požadovat potvrzený email", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "Požadovat potvrzené telefonní číslo", + "DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled": "Je povolena změna uživatelského jména", + "DisplayName:Abp.Identity.User.IsEmailUpdateEnabled": "Je povolena změna emailu", + "Description:Abp.Identity.Password.RequiredLength": "Minimální délka hesla.", + "Description:Abp.Identity.Password.RequiredUniqueChars": "Minimální počet jedinečných znaků, které musí heslo obsahovat.", + "Description:Abp.Identity.Password.RequireNonAlphanumeric": "Hesla musí obsahovat nealfanumerický znak.", + "Description:Abp.Identity.Password.RequireLowercase": "Pokud hesla musí obsahovat ASCII znak malých písmen.", + "Description:Abp.Identity.Password.RequireUppercase": "Pokud hesla musí obsahovat ASCII znak velkých písmen.", + "Description:Abp.Identity.Password.RequireDigit": "Pokud hesla musí obsahovat číslici.", + "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Zda může být uzamčen nový uživatel.", + "Description:Abp.Identity.Lockout.LockoutDuration": "Doba, po kterou je uživatel zablokován, když dojde k zablokování.", + "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Počet neúspěšných pokusů o přístup než je uživatel uzamčen, za předpokladu, že je uzamčení povoleno.", + "Description:Abp.Identity.SignIn.RequireConfirmedEmail": "Zda je k přihlášení vyžadována potvrzená emailová adresa.", + "Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "Zda je pro přihlášení vyžadováno potvrzené telefonní číslo.", + "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Zda může uživatel změnit uživatelské jméno.", + "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Zda může uživatel změnit email." } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json index 5b5927b9a1..886594ac84 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json @@ -7,7 +7,7 @@ "UserName": "User name", "EmailAddress": "Email address", "PhoneNumber": "Phone number", - "UserInformations": "User informations", + "UserInformations": "User information", "DisplayName:IsDefault": "Default", "DisplayName:IsStatic": "Static", "DisplayName:IsPublic": "Public", @@ -71,6 +71,32 @@ "Permission:Delete": "Delete", "Permission:ChangePermissions": "Change permissions", "Permission:UserManagement": "User management", - "Permission:UserLookup": "User lookup" + "Permission:UserLookup": "User lookup", + "DisplayName:Abp.Identity.Password.RequiredLength": "Required length", + "DisplayName:Abp.Identity.Password.RequiredUniqueChars": "Required unique characters number", + "DisplayName:Abp.Identity.Password.RequireNonAlphanumeric": "Required non-alphanumeric character", + "DisplayName:Abp.Identity.Password.RequireLowercase": "Required lower case character", + "DisplayName:Abp.Identity.Password.RequireUppercase": "Required upper case character", + "DisplayName:Abp.Identity.Password.RequireDigit": "Required digit", + "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Allowed for new users", + "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Lockout duration(seconds)", + "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max failed access attempts", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedEmail": "Require confirmed email", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "Require confirmed phoneNumber", + "DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled": "Is username update enabled", + "DisplayName:Abp.Identity.User.IsEmailUpdateEnabled": "Is email update enabled", + "Description:Abp.Identity.Password.RequiredLength": "The minimum length a password must be.", + "Description:Abp.Identity.Password.RequiredUniqueChars": "The minimum number of unique characters which a password must contain.", + "Description:Abp.Identity.Password.RequireNonAlphanumeric": "If passwords must contain a non-alphanumeric character.", + "Description:Abp.Identity.Password.RequireLowercase": "If passwords must contain a lower case ASCII character.", + "Description:Abp.Identity.Password.RequireUppercase": "If passwords must contain a upper case ASCII character.", + "Description:Abp.Identity.Password.RequireDigit": "If passwords must contain a digit.", + "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Whether a new user can be locked out.", + "Description:Abp.Identity.Lockout.LockoutDuration": "The duration a user is locked out for when a lockout occurs.", + "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "The number of failed access attempts allowed before a user is locked out, assuming lock out is enabled.", + "Description:Abp.Identity.SignIn.RequireConfirmedEmail": "Whether a confirmed email address is required to sign in.", + "Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "Whether a confirmed telephone number is required to sign in.", + "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Whether the username can be updated by the user.", + "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Whether the email can be updated by the user." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json index 28786b8767..4908f170fa 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json @@ -71,6 +71,33 @@ "Permission:Delete": "删除", "Permission:ChangePermissions": "更改权限", "Permission:UserManagement": "用户管理", - "Permission:UserLookup": "用户查询" + "Permission:UserLookup": "用户查询", + "DisplayName:Abp.Identity.Password.RequiredLength": "要求长度", + "DisplayName:Abp.Identity.Password.RequiredUniqueChars": "要求唯一字符数量", + "DisplayName:Abp.Identity.Password.RequireNonAlphanumeric": "要求非字母数字", + "DisplayName:Abp.Identity.Password.RequireLowercase": "要求小写字母", + "DisplayName:Abp.Identity.Password.RequireUppercase": "要求大写字母", + "DisplayName:Abp.Identity.Password.RequireDigit": "要求数字", + "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "允许新用户", + "DisplayName:Abp.Identity.Lockout.LockoutDuration": "锁定时间(秒)", + "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "最大失败访问尝试次数", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedEmail": "要求验证的电子邮箱", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "要求验证的手机号码", + "DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled": "启用用户名更新", + "DisplayName:Abp.Identity.User.IsEmailUpdateEnabled": "启用电子邮箱更新", + "Description:Abp.Identity.Password.RequiredLength": "密码的最小长度.", + "Description:Abp.Identity.Password.RequiredUniqueChars": "密码必须包含唯一字符的数量.", + "Description:Abp.Identity.Password.RequireNonAlphanumeric": "密码是否必须包含非字母数字.", + "Description:Abp.Identity.Password.RequireLowercase": "密码是否必须包含小写字母.", + "Description:Abp.Identity.Password.RequireUppercase": "密码是否必须包含大写字母.", + "Description:Abp.Identity.Password.RequireDigit": "密码是否必须包含数字.", + "Description:Abp.Identity.Lockout.AllowedForNewUsers": "允许新用户被锁定.", + "Description:Abp.Identity.Lockout.LockoutDuration": "当锁定发生时用户被的锁定的时间(秒).", + "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "如果启用锁定, 当用户被锁定前失败的访问尝试次数.", + "Description:Abp.Identity.SignIn.RequireConfirmedEmail": "登录时是否需要验证的电子邮箱.", + "Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "登录时是否需要验证的手机号码.", + "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "是否允许用户更新用户名.", + "Description:Abp.Identity.User.IsEmailUpdateEnabled": "是否允许用户更新电子邮箱." + } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json new file mode 100644 index 0000000000..240b7babdf --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json @@ -0,0 +1,103 @@ +{ + "culture": "zh-Hant", + "texts": { + "Menu:IdentityManagement": "身份識別管理", + "Users": "使用者", + "NewUser": "新使用者", + "UserName": "使用者名稱", + "EmailAddress": "電子信箱地址", + "PhoneNumber": "手機號碼", + "UserInformations": "用戶資訊", + "DisplayName:IsDefault": "預設", + "DisplayName:IsStatic": "靜態", + "DisplayName:IsPublic": "公開", + "Roles": "角色", + "Password": "密碼", + "PersonalInfo": " 個人資料", + "PersonalSettings": "個人設置", + "UserDeletionConfirmationMessage": "使用者 '{0}' 將被刪除. 你確定嗎?", + "RoleDeletionConfirmationMessage": "角色 '{0}' 將被刪除. 你確定嗎?", + "DisplayName:RoleName": "角色名稱", + "DisplayName:UserName": "使用者名稱", + "DisplayName:Name": "名子", + "DisplayName:Surname": "姓", + "DisplayName:Password": "密碼", + "DisplayName:Email": "電子信箱地址", + "DisplayName:PhoneNumber": "手機號碼", + "DisplayName:TwoFactorEnabled": "二次認證", + "DisplayName:LockoutEnabled": "登入失敗,帳號被鎖定", + "NewRole": "新角色", + "RoleName": "角色名稱", + "CreationTime": "建立時間", + "Permissions": "權限", + "DisplayName:CurrentPassword": "目前密碼", + "DisplayName:NewPassword": "新密碼", + "DisplayName:NewPasswordConfirm": "確認新密碼", + "PasswordChangedMessage": "你已成功更改密碼.", + "PersonalSettingsSavedMessage": "你的個人設置保存成功.", + "Identity.DefaultError": "發生了一個未知錯誤.", + "Identity.ConcurrencyFailure": "對象已被修改,因樂觀並行控制導致失敗.", + "Identity.DuplicateEmail": "電子信箱 '{0}' 已存在.", + "Identity.DuplicateRoleName": "角色名 '{0}' 已存在.", + "Identity.DuplicateUserName": "使用者名稱 '{0}' 已存在.", + "Identity.InvalidEmail": "電子信箱 '{0}' 無效.", + "Identity.InvalidPasswordHasherCompatibilityMode": "提供的 PasswordHasherCompatibilityMode 無效.", + "Identity.InvalidPasswordHasherIterationCount": "迭代計數必須是正整數.", + "Identity.InvalidRoleName": "角色名 '{0}' 無效.", + "Identity.InvalidToken": "token無效.", + "Identity.InvalidUserName": "使用者名稱 '{0}' 無效, 只能包含字母或數字.", + "Identity.LoginAlreadyAssociated": "此登入名的使用者已存在.", + "Identity.PasswordMismatch": "密碼錯誤.", + "Identity.PasswordRequiresDigit": "密碼至少包含一位數字 ('0'-'9').", + "Identity.PasswordRequiresLower": "密碼至少包含一位小寫字母 ('a'-'z').", + "Identity.PasswordRequiresNonAlphanumeric": "密碼至少包含一位非字母數字字元.", + "Identity.PasswordRequiresUpper": "密碼至少包含一位大寫字母 ('A'-'Z').", + "Identity.PasswordTooShort": "密碼至少為{0}個字元.", + "Identity.RoleNotFound": "角色 {0} 不存在.", + "Identity.UserAlreadyHasPassword": "使用者已設置密碼.", + "Identity.UserAlreadyInRole": "使用者已具有角色 '{0}'.", + "Identity.UserLockedOut": "使用者被鎖定.", + "Identity.UserLockoutNotEnabled": "該使用者未啟用鎖定.", + "Identity.UserNameNotFound": "使用者 {0} 不存在.", + "Identity.UserNotInRole": "使用者不具有 '{0}' 角色.", + "Identity.PasswordConfirmationFailed": "密碼或確認密碼不一致.", + "Identity.StaticRoleRenamingErrorMessage": "無法重命名靜態角色.", + "Identity.StaticRoleDeletionErrorMessage": "無法刪除靜態角色.", + "Volo.Abp.Identity:010001": "您無法刪除自己的帳號!", + "Permission:IdentityManagement": "身份識別管理", + "Permission:RoleManagement": "角色管理", + "Permission:Create": "建立", + "Permission:Edit": "編輯", + "Permission:Delete": "刪除", + "Permission:ChangePermissions": "更改權限", + "Permission:UserManagement": "使用者管理", + "Permission:UserLookup": "使用者查詢", + "DisplayName:Abp.Identity.Password.RequiredLength": "要求長度", + "DisplayName:Abp.Identity.Password.RequiredUniqueChars": "要求唯一字元數量", + "DisplayName:Abp.Identity.Password.RequireNonAlphanumeric": "要求非字母數字", + "DisplayName:Abp.Identity.Password.RequireLowercase": "要求小寫字母", + "DisplayName:Abp.Identity.Password.RequireUppercase": "要求大寫字母", + "DisplayName:Abp.Identity.Password.RequireDigit": "要求數字", + "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "允許新使用者", + "DisplayName:Abp.Identity.Lockout.LockoutDuration": "鎖定時間(秒)", + "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "最大失敗存取嘗試次數", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedEmail": "要求驗證的電子信箱", + "DisplayName:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "要求驗證的手機號碼", + "DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled": "啟用使用者名稱更新", + "DisplayName:Abp.Identity.User.IsEmailUpdateEnabled": "啟用電子信箱更新", + "Description:Abp.Identity.Password.RequiredLength": "密碼的最小長度.", + "Description:Abp.Identity.Password.RequiredUniqueChars": "密碼必須包含唯一字元的數量.", + "Description:Abp.Identity.Password.RequireNonAlphanumeric": "密碼是否必須包含非字母數字.", + "Description:Abp.Identity.Password.RequireLowercase": "密碼是否必須包含小寫字母.", + "Description:Abp.Identity.Password.RequireUppercase": "密碼是否必須包含大小字母.", + "Description:Abp.Identity.Password.RequireDigit": "密碼是否必須包含數字.", + "Description:Abp.Identity.Lockout.AllowedForNewUsers": "允許新使用者被鎖定.", + "Description:Abp.Identity.Lockout.LockoutDuration": "當鎖定發生時使用者被鎖定的時間(秒).", + "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "如果啟用鎖定,當使用者被鎖定前失敗的存取嘗試次數.", + "Description:Abp.Identity.SignIn.RequireConfirmedEmail": "登入時是否需要驗證電子信箱.", + "Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "登入時是否需要驗證手機號碼.", + "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "是否允許使用者更新使用者名稱.", + "Description:Abp.Identity.User.IsEmailUpdateEnabled": "是否允許使用者更新電子信箱." + + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsFactory.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsFactory.cs index 89f2b11bc2..3836783a01 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsFactory.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityOptionsFactory.cs @@ -39,19 +39,19 @@ namespace Volo.Abp.Identity protected virtual async Task OverrideOptionsAsync(IdentityOptions options) { - options.Password.RequiredLength = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength); - options.Password.RequiredUniqueChars = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars); - options.Password.RequireNonAlphanumeric = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric); - options.Password.RequireLowercase = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase); - options.Password.RequireUppercase = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase); - options.Password.RequireDigit = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit); - - options.Lockout.AllowedForNewUsers = await _settingProvider.GetAsync(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers); + options.Password.RequiredLength = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength).ConfigureAwait(false); + options.Password.RequiredUniqueChars = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars).ConfigureAwait(false); + options.Password.RequireNonAlphanumeric = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric).ConfigureAwait(false); + options.Password.RequireLowercase = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase).ConfigureAwait(false); + options.Password.RequireUppercase = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase).ConfigureAwait(false); + options.Password.RequireDigit = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit).ConfigureAwait(false); + + options.Lockout.AllowedForNewUsers = await _settingProvider.GetAsync(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers).ConfigureAwait(false); options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(await _settingProvider.GetAsync(IdentitySettingNames.Lockout.LockoutDuration, options.Lockout.DefaultLockoutTimeSpan.TotalSeconds.To())); - options.Lockout.MaxFailedAccessAttempts = await _settingProvider.GetAsync(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts); + options.Lockout.MaxFailedAccessAttempts = await _settingProvider.GetAsync(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts).ConfigureAwait(false); - options.SignIn.RequireConfirmedEmail = await _settingProvider.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail); - options.SignIn.RequireConfirmedPhoneNumber = await _settingProvider.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber); + options.SignIn.RequireConfirmedEmail = await _settingProvider.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail).ConfigureAwait(false); + options.SignIn.RequireConfirmedPhoneNumber = await _settingProvider.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber).ConfigureAwait(false); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs index 0edeacf848..efae6e467a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs @@ -1,4 +1,6 @@ -using Volo.Abp.Identity.Settings; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Identity.Settings; +using Volo.Abp.Localization; using Volo.Abp.Settings; namespace Volo.Abp.Identity @@ -8,23 +10,91 @@ namespace Volo.Abp.Identity public override void Define(ISettingDefinitionContext context) { context.Add( - new SettingDefinition(IdentitySettingNames.Password.RequiredLength, 6.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Password.RequiredUniqueChars, 1.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Password.RequireNonAlphanumeric, true.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Password.RequireLowercase, true.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Password.RequireUppercase, true.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Password.RequireDigit, true.ToString(), null, null, true), - - new SettingDefinition(IdentitySettingNames.Lockout.AllowedForNewUsers, true.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Lockout.LockoutDuration, (5*60).ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, 5.ToString(), null, null, true), - - new SettingDefinition(IdentitySettingNames.SignIn.RequireConfirmedEmail, false.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, false.ToString(), null, null, true), - - new SettingDefinition(IdentitySettingNames.User.IsUserNameUpdateEnabled, true.ToString(), null, null, true), - new SettingDefinition(IdentitySettingNames.User.IsEmailUpdateEnabled, true.ToString(), null, null, true) + new SettingDefinition( + IdentitySettingNames.Password.RequiredLength, + 6.ToString(), + L("DisplayName:Abp.Identity.Password.RequiredLength"), + L("Description:Abp.Identity.Password.RequiredLength"), + true), + + new SettingDefinition( + IdentitySettingNames.Password.RequiredUniqueChars, + 1.ToString(), + L("DisplayName:Abp.Identity.Password.RequiredUniqueChars"), + L("Description:Abp.Identity.Password.RequiredUniqueChars"), + true), + + new SettingDefinition( + IdentitySettingNames.Password.RequireNonAlphanumeric, + true.ToString(), + L("DisplayName:Abp.Identity.Password.RequireNonAlphanumeric"), + L("Description:Abp.Identity.Password.RequireNonAlphanumeric"), + true), + + new SettingDefinition( + IdentitySettingNames.Password.RequireLowercase, + true.ToString(), L("DisplayName:Abp.Identity.Password.RequireLowercase"), + L("Description:Abp.Identity.Password.RequireLowercase"), + true), + + new SettingDefinition( + IdentitySettingNames.Password.RequireUppercase, + true.ToString(), L("DisplayName:Abp.Identity.Password.RequireUppercase"), + L("Description:Abp.Identity.Password.RequireUppercase"), + true), + + new SettingDefinition( + IdentitySettingNames.Password.RequireDigit, + true.ToString(), L("DisplayName:Abp.Identity.Password.RequireDigit"), + L("Description:Abp.Identity.Password.RequireDigit"), + true), + + new SettingDefinition( + IdentitySettingNames.Lockout.AllowedForNewUsers, + true.ToString(), L("DisplayName:Abp.Identity.Lockout.AllowedForNewUsers"), + L("Description:Abp.Identity.Lockout.AllowedForNewUsers"), + true), + + new SettingDefinition( + IdentitySettingNames.Lockout.LockoutDuration, + (5*60).ToString(), L("DisplayName:Abp.Identity.Lockout.LockoutDuration"), + L("Description:Abp.Identity.Lockout.LockoutDuration"), + true), + + new SettingDefinition( + IdentitySettingNames.Lockout.MaxFailedAccessAttempts, + 5.ToString(), L("DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts"), + L("Description:Abp.Identity.Lockout.MaxFailedAccessAttempts"), + true), + + new SettingDefinition( + IdentitySettingNames.SignIn.RequireConfirmedEmail, + false.ToString(), L("DisplayName:Abp.Identity.SignIn.RequireConfirmedEmail"), + L("Description:Abp.Identity.SignIn.RequireConfirmedEmail"), + true), + new SettingDefinition( + IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, + false.ToString(), L("DisplayName:Abp.Identity.SignIn.RequireConfirmedPhoneNumber"), + L("Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber"), + true), + + new SettingDefinition( + IdentitySettingNames.User.IsUserNameUpdateEnabled, + true.ToString(), L("DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled"), + L("Description:Abp.Identity.User.IsUserNameUpdateEnabled"), + true), + + new SettingDefinition( + IdentitySettingNames.User.IsEmailUpdateEnabled, + true.ToString(), L("DisplayName:Abp.Identity.User.IsEmailUpdateEnabled"), + L("Description:Abp.Identity.User.IsEmailUpdateEnabled"), + true) ); } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs index 8db2b95942..9425a91cdc 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Identity [UnitOfWork] public override async Task CreateAsync(IdentityUser user) { - var principal = await base.CreateAsync(user); + var principal = await base.CreateAsync(user).ConfigureAwait(false); if (user.TenantId.HasValue) { diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs index d27de75865..6ce3ce3c0c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs @@ -21,9 +21,5 @@ namespace Volo.Abp.Identity bool includeDetails = false, CancellationToken cancellationToken = default ); - - Task GetCountAsync( - CancellationToken cancellationToken = default - ); } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs index 6e79b29d98..ae468d272a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityClaimTypeManager.cs @@ -15,17 +15,17 @@ namespace Volo.Abp.Identity public virtual async Task CreateAsync(IdentityClaimType claimType) { - if (await _identityClaimTypeRepository.AnyAsync(claimType.Name)) + if (await _identityClaimTypeRepository.AnyAsync(claimType.Name).ConfigureAwait(false)) { throw new AbpException($"Name Exist: {claimType.Name}"); } - return await _identityClaimTypeRepository.InsertAsync(claimType); + return await _identityClaimTypeRepository.InsertAsync(claimType).ConfigureAwait(false); } public virtual async Task UpdateAsync(IdentityClaimType claimType) { - if (await _identityClaimTypeRepository.AnyAsync(claimType.Name, claimType.Id)) + if (await _identityClaimTypeRepository.AnyAsync(claimType.Name, claimType.Id).ConfigureAwait(false)) { throw new AbpException($"Name Exist: {claimType.Name}"); } @@ -36,7 +36,7 @@ namespace Volo.Abp.Identity } - return await _identityClaimTypeRepository.UpdateAsync(claimType); + return await _identityClaimTypeRepository.UpdateAsync(claimType).ConfigureAwait(false); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs index 70945c2546..92ebe6adfb 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDataSeeder.cs @@ -47,7 +47,7 @@ namespace Volo.Abp.Identity const string adminUserName = "admin"; var adminUser = await _userRepository.FindByNormalizedUserNameAsync( _lookupNormalizer.NormalizeName(adminUserName) - ); + ).ConfigureAwait(false); if (adminUser != null) { @@ -64,12 +64,12 @@ namespace Volo.Abp.Identity Name = adminUserName }; - (await _userManager.CreateAsync(adminUser, adminPassword)).CheckErrors(); + (await _userManager.CreateAsync(adminUser, adminPassword).ConfigureAwait(false)).CheckErrors(); result.CreatedAdminUser = true; //"admin" role const string adminRoleName = "admin"; - var adminRole = await _roleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName(adminRoleName)); + var adminRole = await _roleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName(adminRoleName)).ConfigureAwait(false); if (adminRole == null) { adminRole = new IdentityRole( @@ -82,11 +82,11 @@ namespace Volo.Abp.Identity IsPublic = true }; - (await _roleManager.CreateAsync(adminRole)).CheckErrors(); + (await _roleManager.CreateAsync(adminRole).ConfigureAwait(false)).CheckErrors(); result.CreatedAdminRole = true; } - (await _userManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors(); + (await _userManager.AddToRoleAsync(adminUser, adminRoleName).ConfigureAwait(false)).CheckErrors(); return result; } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs index 825266e993..dac173719a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs @@ -100,6 +100,22 @@ namespace Volo.Abp.Identity Claims.RemoveAll(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value); } + public virtual void ChangeName(string name) + { + Check.NotNullOrWhiteSpace(name, nameof(name)); + + var oldName = Name; + Name = name; + + AddLocalEvent( + new IdentityRoleNameChangedEvent + { + IdentityRole = this, + OldName = oldName + } + ); + } + public override string ToString() { return $"{base.ToString()}, Name = {Name}"; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs index 92e6d9893c..17f1b817aa 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleManager.cs @@ -41,7 +41,7 @@ namespace Volo.Abp.Identity public virtual async Task GetByIdAsync(Guid id) { - var role = await Store.FindByIdAsync(id.ToString(), CancellationToken); + var role = await Store.FindByIdAsync(id.ToString(), CancellationToken).ConfigureAwait(false); if (role == null) { throw new EntityNotFoundException(typeof(IdentityRole), id); @@ -57,7 +57,7 @@ namespace Volo.Abp.Identity throw new BusinessException(_localizer["Identity.StaticRoleRenamingErrorMessage"]); // TODO: localize & change exception type } - return await base.SetRoleNameAsync(role,name); + return await base.SetRoleNameAsync(role, name).ConfigureAwait(false); } public override async Task DeleteAsync(IdentityRole role) @@ -67,7 +67,7 @@ namespace Volo.Abp.Identity throw new BusinessException(_localizer["Identity.StaticRoleDeletionErrorMessage"]); // TODO: localize & change exception type } - return await base.DeleteAsync(role); + return await base.DeleteAsync(role).ConfigureAwait(false); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs new file mode 100644 index 0000000000..f14f0a71ed --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.Identity +{ + public class IdentityRoleNameChangedEvent + { + public IdentityRole IdentityRole { get; set; } + public string OldName { get; set; } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs index 175b051a48..004fc0c20c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs @@ -67,7 +67,7 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); - await _roleRepository.InsertAsync(role, AutoSaveChanges, cancellationToken); + await _roleRepository.InsertAsync(role, AutoSaveChanges, cancellationToken).ConfigureAwait(false); return IdentityResult.Success; } @@ -86,7 +86,7 @@ namespace Volo.Abp.Identity try { - await _roleRepository.UpdateAsync(role, AutoSaveChanges, cancellationToken); + await _roleRepository.UpdateAsync(role, AutoSaveChanges, cancellationToken).ConfigureAwait(false); } catch (AbpDbConcurrencyException ex) { @@ -111,7 +111,7 @@ namespace Volo.Abp.Identity try { - await _roleRepository.DeleteAsync(role, AutoSaveChanges, cancellationToken); + await _roleRepository.DeleteAsync(role, AutoSaveChanges, cancellationToken).ConfigureAwait(false); } catch (AbpDbConcurrencyException ex) { @@ -165,7 +165,7 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); - role.Name = roleName; + role.ChangeName(roleName); return Task.CompletedTask; } @@ -249,7 +249,7 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); - await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken); + await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken).ConfigureAwait(false); return role.Claims.Select(c => c.ToClaim()).ToList(); } @@ -268,7 +268,7 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); Check.NotNull(claim, nameof(claim)); - await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken); + await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken).ConfigureAwait(false); role.AddClaim(_guidGenerator, claim); } @@ -285,7 +285,7 @@ namespace Volo.Abp.Identity Check.NotNull(role, nameof(role)); Check.NotNull(claim, nameof(claim)); - await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken); + await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken).ConfigureAwait(false); role.RemoveClaim(claim); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs index aca1535c3c..c6ad077456 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs @@ -130,16 +130,17 @@ namespace Volo.Abp.Identity ExtraProperties = new Dictionary(); } - public IdentityUser(Guid id, [NotNull] string userName, string email = null, Guid? tenantId = null) + public IdentityUser(Guid id, [NotNull] string userName, [NotNull] string email, Guid? tenantId = null) { Check.NotNull(userName, nameof(userName)); + Check.NotNull(email, nameof(email)); Id = id; TenantId = tenantId; UserName = userName; NormalizedUserName = userName.ToUpperInvariant(); Email = email; - NormalizedEmail = email?.ToUpperInvariant(); + NormalizedEmail = email.ToUpperInvariant(); ConcurrencyStamp = Guid.NewGuid().ToString(); SecurityStamp = Guid.NewGuid().ToString(); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs index 0f732a8dd7..9e66b7b824 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs @@ -45,7 +45,7 @@ namespace Volo.Abp.Identity public virtual async Task GetByIdAsync(Guid id) { - var user = await Store.FindByIdAsync(id.ToString(), CancellationToken); + var user = await Store.FindByIdAsync(id.ToString(), CancellationToken).ConfigureAwait(false); if (user == null) { throw new EntityNotFoundException(typeof(IdentityUser), id); @@ -59,15 +59,15 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); Check.NotNull(roleNames, nameof(roleNames)); - var currentRoleNames = await GetRolesAsync(user); + var currentRoleNames = await GetRolesAsync(user).ConfigureAwait(false); - var result = await RemoveFromRolesAsync(user, currentRoleNames.Except(roleNames).Distinct()); + var result = await RemoveFromRolesAsync(user, currentRoleNames.Except(roleNames).Distinct()).ConfigureAwait(false); if (!result.Succeeded) { return result; } - result = await AddToRolesAsync(user, roleNames.Except(currentRoleNames).Distinct()); + result = await AddToRolesAsync(user, roleNames.Except(currentRoleNames).Distinct()).ConfigureAwait(false); if (!result.Succeeded) { return result; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs index cb380de5c7..1fdc6ff934 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserRepositoryExternalUserLookupServiceProvider.cs @@ -30,7 +30,7 @@ namespace Volo.Abp.Identity includeDetails: false, cancellationToken: cancellationToken ) - )?.ToAbpUserData(); +.ConfigureAwait(false))?.ToAbpUserData(); } public virtual async Task FindByUserNameAsync( @@ -43,7 +43,7 @@ namespace Volo.Abp.Identity includeDetails: false, cancellationToken: cancellationToken ) - )?.ToAbpUserData(); +.ConfigureAwait(false))?.ToAbpUserData(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs index bac63a0c11..cb03869ae6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs @@ -163,7 +163,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - await _userRepository.InsertAsync(user, AutoSaveChanges, cancellationToken); + await _userRepository.InsertAsync(user, AutoSaveChanges, cancellationToken).ConfigureAwait(false); return IdentityResult.Success; } @@ -182,7 +182,7 @@ namespace Volo.Abp.Identity try { - await _userRepository.UpdateAsync(user, AutoSaveChanges, cancellationToken); + await _userRepository.UpdateAsync(user, AutoSaveChanges, cancellationToken).ConfigureAwait(false); } catch (AbpDbConcurrencyException ex) { @@ -207,7 +207,7 @@ namespace Volo.Abp.Identity try { - await _userRepository.DeleteAsync(user, AutoSaveChanges, cancellationToken); + await _userRepository.DeleteAsync(user, AutoSaveChanges, cancellationToken).ConfigureAwait(false); } catch (AbpDbConcurrencyException ex) { @@ -313,14 +313,14 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); Check.NotNull(normalizedRoleName, nameof(normalizedRoleName)); - var role = await _roleRepository.FindByNormalizedNameAsync(normalizedRoleName, cancellationToken: cancellationToken); + var role = await _roleRepository.FindByNormalizedNameAsync(normalizedRoleName, cancellationToken: cancellationToken).ConfigureAwait(false); if (role == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Role {0} does not exist!", normalizedRoleName)); } - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken).ConfigureAwait(false); user.AddRole(role.Id); } @@ -343,13 +343,13 @@ namespace Volo.Abp.Identity throw new ArgumentException(nameof(normalizedRoleName) + " can not be null or whitespace"); } - var role = await _roleRepository.FindByNormalizedNameAsync(normalizedRoleName, cancellationToken: cancellationToken); + var role = await _roleRepository.FindByNormalizedNameAsync(normalizedRoleName, cancellationToken: cancellationToken).ConfigureAwait(false); if (role == null) { return; } - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken).ConfigureAwait(false); user.RemoveRole(role.Id); } @@ -388,13 +388,13 @@ namespace Volo.Abp.Identity throw new ArgumentException(nameof(normalizedRoleName) + " can not be null or whitespace"); } - var role = await _roleRepository.FindByNormalizedNameAsync(normalizedRoleName, cancellationToken: cancellationToken); + var role = await _roleRepository.FindByNormalizedNameAsync(normalizedRoleName, cancellationToken: cancellationToken).ConfigureAwait(false); if (role == null) { return false; } - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Roles, cancellationToken).ConfigureAwait(false); return user.IsInRole(role.Id); } @@ -411,7 +411,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken).ConfigureAwait(false); return user.Claims.Select(c => c.ToClaim()).ToList(); } @@ -430,7 +430,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); Check.NotNull(claims, nameof(claims)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken).ConfigureAwait(false); user.AddClaims(_guidGenerator, claims); } @@ -451,7 +451,7 @@ namespace Volo.Abp.Identity Check.NotNull(claim, nameof(claim)); Check.NotNull(newClaim, nameof(newClaim)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken).ConfigureAwait(false); user.ReplaceClaim(claim, newClaim); } @@ -470,7 +470,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); Check.NotNull(claims, nameof(claims)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken).ConfigureAwait(false); user.RemoveClaims(claims); } @@ -489,7 +489,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); Check.NotNull(login, nameof(login)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken).ConfigureAwait(false); user.AddLogin(login); } @@ -510,7 +510,7 @@ namespace Volo.Abp.Identity Check.NotNull(loginProvider, nameof(loginProvider)); Check.NotNull(providerKey, nameof(providerKey)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken).ConfigureAwait(false); user.RemoveLogin(loginProvider, providerKey); } @@ -529,7 +529,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken).ConfigureAwait(false); return user.Logins.Select(l => l.ToUserLoginInfo()).ToList(); } @@ -597,11 +597,12 @@ namespace Volo.Abp.Identity /// The email to set. /// The used to propagate notifications that the operation should be canceled. /// The task object representing the asynchronous operation. - public virtual Task SetEmailAsync([NotNull] IdentityUser user, string email, CancellationToken cancellationToken = default) + public virtual Task SetEmailAsync([NotNull] IdentityUser user, [NotNull] string email, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); + Check.NotNull(email, nameof(email)); user.Email = email; @@ -987,7 +988,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken).ConfigureAwait(false); user.SetToken(loginProvider, name, value); } @@ -1006,7 +1007,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken).ConfigureAwait(false); user.RemoveToken(loginProvider, name); } @@ -1025,7 +1026,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken).ConfigureAwait(false); return user.FindToken(loginProvider, name)?.Value; } @@ -1052,7 +1053,7 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); - var mergedCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, cancellationToken) ?? ""; + var mergedCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, cancellationToken).ConfigureAwait(false) ?? ""; if (mergedCodes.Length > 0) { return mergedCodes.Split(';').Length; @@ -1089,12 +1090,12 @@ namespace Volo.Abp.Identity Check.NotNull(user, nameof(user)); Check.NotNull(code, nameof(code)); - var mergedCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, cancellationToken) ?? ""; + var mergedCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, cancellationToken).ConfigureAwait(false) ?? ""; var splitCodes = mergedCodes.Split(';'); if (splitCodes.Contains(code)) { var updatedCodes = new List(splitCodes.Where(s => s != code)); - await ReplaceCodesAsync(user, updatedCodes, cancellationToken); + await ReplaceCodesAsync(user, updatedCodes, cancellationToken).ConfigureAwait(false); return true; } return false; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs index d2de24a568..c366591a57 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.Identity public virtual async Task GetRolesAsync(Guid userId) { - return (await _identityUserRepository.GetRoleNamesAsync(userId)).ToArray(); + return (await _identityUserRepository.GetRoleNamesAsync(userId).ConfigureAwait(false)).ToArray(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo.Abp.Identity.EntityFrameworkCore.csproj b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo.Abp.Identity.EntityFrameworkCore.csproj index 945905d75f..87c5e27bd5 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo.Abp.Identity.EntityFrameworkCore.csproj +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo.Abp.Identity.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.Identity.EntityFrameworkCore Volo.Abp.Identity.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs index 95b7a7fe42..d7cb57d396 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { return await DbSet .WhereIf(ignoredId != null, ct => ct.Id != ignoredId) - .CountAsync(ct => ct.Name == name) > 0; + .CountAsync(ct => ct.Name == name).ConfigureAwait(false) > 0; } public async Task> GetListAsync(string sorting, int maxResultCount, int skipCount, string filter) @@ -34,7 +34,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore ) .OrderBy(sorting ?? "name desc") .PageBy(skipCount, maxResultCount) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); return identityClaimTypes; } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs index a9850164ef..731cc6df23 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { return await DbSet .IncludeDetails(includeDetails) - .FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync( @@ -39,7 +39,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .IncludeDetails(includeDetails) .OrderBy(sorting ?? nameof(IdentityRole.Name)) .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override IQueryable WithDetails() diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index cab891bc94..e3dfe6ee8c 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .FirstOrDefaultAsync( u => u.NormalizedUserName == normalizedUserName, GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); } public virtual async Task> GetRoleNamesAsync( @@ -40,7 +40,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore where userRole.UserId == id select role.Name; - return await query.ToListAsync(GetCancellationToken(cancellationToken)); + return await query.ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task FindByLoginAsync( @@ -52,7 +52,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await DbSet .IncludeDetails(includeDetails) .Where(u => u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey)) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task FindByNormalizedEmailAsync( @@ -62,7 +62,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { return await DbSet .IncludeDetails(includeDetails) - .FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListByClaimAsync( @@ -73,7 +73,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await DbSet .IncludeDetails(includeDetails) .Where(u => u.Claims.Any(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListByNormalizedRoleNameAsync( @@ -83,7 +83,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore { var role = await DbContext.Roles .Where(x => x.NormalizedName == normalizedRoleName) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); if (role == null) { @@ -93,7 +93,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await DbSet .IncludeDetails(includeDetails) .Where(u => u.Roles.Any(r => r.RoleId == role.Id)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync( @@ -114,7 +114,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore ) .OrderBy(sorting ?? nameof(IdentityUser.UserName)) .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetRolesAsync( @@ -127,7 +127,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore where userRole.UserId == id select role; - return await query.ToListAsync(GetCancellationToken(cancellationToken)); + return await query.ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task GetCountAsync( @@ -140,7 +140,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore u.UserName.Contains(filter) || u.Email.Contains(filter) ) - .LongCountAsync(GetCancellationToken(cancellationToken)); + .LongCountAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override IQueryable WithDetails() diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index a2a63062d3..76ac038c05 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -29,7 +29,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore b.ConfigureAbpUser(); b.Property(u => u.NormalizedUserName).IsRequired().HasMaxLength(IdentityUserConsts.MaxNormalizedUserNameLength).HasColumnName(nameof(IdentityUser.NormalizedUserName)); - b.Property(u => u.NormalizedEmail).HasMaxLength(IdentityUserConsts.MaxNormalizedEmailLength).HasColumnName(nameof(IdentityUser.NormalizedEmail)); + b.Property(u => u.NormalizedEmail).IsRequired().HasMaxLength(IdentityUserConsts.MaxNormalizedEmailLength).HasColumnName(nameof(IdentityUser.NormalizedEmail)); b.Property(u => u.PasswordHash).HasMaxLength(IdentityUserConsts.MaxPasswordHashLength).HasColumnName(nameof(IdentityUser.PasswordHash)); b.Property(u => u.SecurityStamp).IsRequired().HasMaxLength(IdentityUserConsts.MaxSecurityStampLength).HasColumnName(nameof(IdentityUser.SecurityStamp)); b.Property(u => u.TwoFactorEnabled).HasDefaultValue(false).HasColumnName(nameof(IdentityUser.TwoFactorEnabled)); diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs index a5fffe9848..1e5934cee5 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.Identity public async Task GetRolesAsync(Guid userId) { - var output = await _userAppService.GetRolesAsync(userId); + var output = await _userAppService.GetRolesAsync(userId).ConfigureAwait(false); return output.Items.Select(r => r.Name).ToArray(); } } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs index 35ec928f5c..09760109d0 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityRoleController.cs @@ -20,9 +20,9 @@ namespace Volo.Abp.Identity } [HttpGet] - public virtual Task> GetListAsync() + public virtual Task> GetListAsync(PagedAndSortedResultRequestDto input) { - return _roleAppService.GetListAsync(); + return _roleAppService.GetListAsync(input); } [HttpGet] diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs index 16ba528412..beed5130f1 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs @@ -22,13 +22,13 @@ namespace Volo.Abp.Identity.MongoDB { return await GetMongoQueryable() .Where(ct => ct.Name == name) - .AnyAsync(); + .AnyAsync().ConfigureAwait(false); } else { return await GetMongoQueryable() .Where(ct => ct.Id != ignoredId && ct.Name == name) - .AnyAsync(); + .AnyAsync().ConfigureAwait(false); } } @@ -43,7 +43,7 @@ namespace Volo.Abp.Identity.MongoDB .OrderBy(sorting ?? nameof(IdentityClaimType.Name)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(); + .ToListAsync().ConfigureAwait(false); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs index 81c6106b7d..4bae372c8e 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs @@ -27,7 +27,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken)); + return await GetMongoQueryable().FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetListAsync( @@ -41,13 +41,7 @@ namespace Volo.Abp.Identity.MongoDB .OrderBy(sorting ?? nameof(IdentityRole.Name)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); - } - - public async Task GetCountAsync(CancellationToken cancellationToken = default) - { - return await GetMongoQueryable() - .LongCountAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index 3d6f188c56..9c3b8bcd0e 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -32,16 +32,16 @@ namespace Volo.Abp.Identity.MongoDB .FirstOrDefaultAsync( u => u.NormalizedUserName == normalizedUserName, GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); } public async Task> GetRoleNamesAsync( Guid id, CancellationToken cancellationToken = default) { - var user = await GetAsync(id, cancellationToken: GetCancellationToken(cancellationToken)); + var user = await GetAsync(id, cancellationToken: GetCancellationToken(cancellationToken)).ConfigureAwait(false); var roleIds = user.Roles.Select(r => r.RoleId).ToArray(); - return await DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)).Select(r => r.Name).ToListAsync(GetCancellationToken(cancellationToken)); + return await DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)).Select(r => r.Name).ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task FindByLoginAsync( @@ -51,8 +51,8 @@ namespace Volo.Abp.Identity.MongoDB CancellationToken cancellationToken = default) { return await GetMongoQueryable() - .Where(u=> u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey)) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .Where(u => u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey)) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task FindByNormalizedEmailAsync( @@ -60,7 +60,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, GetCancellationToken(cancellationToken)); + return await GetMongoQueryable().FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetListByClaimAsync( @@ -70,7 +70,7 @@ namespace Volo.Abp.Identity.MongoDB { return await GetMongoQueryable() .Where(u => u.Claims.Any(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetListByNormalizedRoleNameAsync( @@ -78,7 +78,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var role = await DbContext.Roles.AsQueryable().Where(x => x.NormalizedName == normalizedRoleName).FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + var role = await DbContext.Roles.AsQueryable().Where(x => x.NormalizedName == normalizedRoleName).FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); if (role == null) { @@ -87,7 +87,7 @@ namespace Volo.Abp.Identity.MongoDB return await GetMongoQueryable() .Where(u => u.Roles.Any(r => r.RoleId == role.Id)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetListAsync( @@ -108,7 +108,7 @@ namespace Volo.Abp.Identity.MongoDB .OrderBy(sorting ?? nameof(IdentityUser.UserName)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetRolesAsync( @@ -116,9 +116,9 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var user = await GetAsync(id, cancellationToken: GetCancellationToken(cancellationToken)); + var user = await GetAsync(id, cancellationToken: GetCancellationToken(cancellationToken)).ConfigureAwait(false); var roleIds = user.Roles.Select(r => r.RoleId).ToArray(); - return await DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)).ToListAsync(GetCancellationToken(cancellationToken)); + return await DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)).ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task GetCountAsync( @@ -132,7 +132,7 @@ namespace Volo.Abp.Identity.MongoDB u.UserName.Contains(filter) || u.Email.Contains(filter) ) - .LongCountAsync(GetCancellationToken(cancellationToken)); + .LongCountAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs b/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs index 34dc3dd4cd..d6d61dcff4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs @@ -18,8 +18,8 @@ namespace Volo.Abp.Identity.Web.Navigation var authorizationService = context.ServiceProvider.GetRequiredService(); - var hasRolePermission = await authorizationService.IsGrantedAsync(IdentityPermissions.Roles.Default); - var hasUserPermission = await authorizationService.IsGrantedAsync(IdentityPermissions.Users.Default); + var hasRolePermission = await authorizationService.IsGrantedAsync(IdentityPermissions.Roles.Default).ConfigureAwait(false); + var hasUserPermission = await authorizationService.IsGrantedAsync(IdentityPermissions.Users.Default).ConfigureAwait(false); if (hasRolePermission || hasUserPermission) { diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs index b3fdad3a95..4861944c7f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/CreateModal.cshtml.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Roles ValidateModel(); var input = ObjectMapper.Map(Role); - await _identityRoleAppService.CreateAsync(input); + await _identityRoleAppService.CreateAsync(input).ConfigureAwait(false); return NoContent(); } diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs index 8416e171b0..42f13b4bf5 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/EditModal.cshtml.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Roles { Role = ObjectMapper.Map( await _identityRoleAppService.GetAsync(id) - ); +.ConfigureAwait(false)); } public async Task OnPostAsync() @@ -30,7 +30,7 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Roles ValidateModel(); var input = ObjectMapper.Map(Role); - await _identityRoleAppService.UpdateAsync(Role.Id, input); + await _identityRoleAppService.UpdateAsync(Role.Id, input).ConfigureAwait(false); return NoContent(); } diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js index 6127dfe9c1..8332a95ac7 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Roles/index.js @@ -14,9 +14,11 @@ var _dataTable = _$table.DataTable(abp.libs.datatables.normalizeConfiguration({ order: [[1, "asc"]], - searching:false, - paging:false, - info:false, + searching: false, + processing: true, + serverSide: true, + scrollX: true, + paging: true, ajax: abp.libs.datatables.createAjax(_identityRoleAppService.getList), columnDefs: [ { diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs index 3c5451208a..e2dbedc660 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs @@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Application.Dtos; namespace Volo.Abp.Identity.Web.Pages.Identity.Users { @@ -27,7 +28,7 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users { UserInfo = new UserInfoViewModel(); - var roleDtoList = await _identityRoleAppService.GetListAsync(); + var roleDtoList = await _identityRoleAppService.GetListAsync(new PagedAndSortedResultRequestDto()).ConfigureAwait(false); Roles = ObjectMapper.Map, AssignedRoleViewModel[]>(roleDtoList.Items); @@ -44,7 +45,7 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users var input = ObjectMapper.Map(UserInfo); input.RoleNames = Roles.Where(r => r.IsAssigned).Select(r => r.Name).ToArray(); - await _identityUserAppService.CreateAsync(input); + await _identityUserAppService.CreateAsync(input).ConfigureAwait(false); return NoContent(); } diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs index 364a1b4049..7a55711bd3 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Entities; namespace Volo.Abp.Identity.Web.Pages.Identity.Users @@ -27,13 +28,13 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users public async Task OnGetAsync(Guid id) { - UserInfo = ObjectMapper.Map(await _identityUserAppService.GetAsync(id)); + UserInfo = ObjectMapper.Map(await _identityUserAppService.GetAsync(id).ConfigureAwait(false)); Roles = ObjectMapper.Map, AssignedRoleViewModel[]>( - (await _identityRoleAppService.GetListAsync()).Items + (await _identityRoleAppService.GetListAsync(new PagedAndSortedResultRequestDto()).ConfigureAwait(false)).Items ); - var userRoleNames = (await _identityUserAppService.GetRolesAsync(UserInfo.Id)).Items.Select(r => r.Name).ToList(); + var userRoleNames = (await _identityUserAppService.GetRolesAsync(UserInfo.Id).ConfigureAwait(false)).Items.Select(r => r.Name).ToList(); foreach (var role in Roles) { if (userRoleNames.Contains(role.Name)) @@ -49,7 +50,7 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users var input = ObjectMapper.Map(UserInfo); input.RoleNames = Roles.Where(r => r.IsAssigned).Select(r => r.Name).ToArray(); - await _identityUserAppService.UpdateAsync(UserInfo.Id, input); + await _identityUserAppService.UpdateAsync(UserInfo.Id, input).ConfigureAwait(false); return NoContent(); } diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js index 4d8486d256..64505509ba 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js @@ -15,6 +15,7 @@ order: [[1, "asc"]], processing: true, serverSide: true, + scrollX: true, paging: true, ajax: abp.libs.datatables.createAjax(_identityUserAppService.getList), columnDefs: [ diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo.Abp.PermissionManagement.Domain.Identity.csproj b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo.Abp.PermissionManagement.Domain.Identity.csproj index ea663ba49b..ee8e336088 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo.Abp.PermissionManagement.Domain.Identity.csproj +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo.Abp.PermissionManagement.Domain.Identity.csproj @@ -16,6 +16,7 @@ + diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs index 09fb389163..2c7920539c 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs @@ -39,11 +39,11 @@ namespace Volo.Abp.PermissionManagement.Identity if (providerName == UserPermissionValueProvider.ProviderName) { var userId = Guid.Parse(providerKey); - var roleNames = await _userRoleFinder.GetRolesAsync(userId); + var roleNames = await _userRoleFinder.GetRolesAsync(userId).ConfigureAwait(false); foreach (var roleName in roleNames) { - var permissionGrant = await PermissionGrantRepository.FindAsync(name, Name, roleName); + var permissionGrant = await PermissionGrantRepository.FindAsync(name, Name, roleName).ConfigureAwait(false); if (permissionGrant != null) { return new PermissionValueProviderGrantInfo(true, roleName); diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs new file mode 100644 index 0000000000..54e8bec3b1 --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.Identity; + +namespace Volo.Abp.PermissionManagement.Identity +{ + public class RoleUpdateEventHandler : + ILocalEventHandler, + ITransientDependency + { + protected IIdentityRoleRepository RoleRepository { get; } + protected IPermissionManager PermissionManager { get; } + protected IPermissionGrantRepository PermissionGrantRepository { get; } + + public RoleUpdateEventHandler( + IIdentityRoleRepository roleRepository, + IPermissionManager permissionManager, + IPermissionGrantRepository permissionGrantRepository) + { + RoleRepository = roleRepository; + PermissionManager = permissionManager; + PermissionGrantRepository = permissionGrantRepository; + } + + public async Task HandleEventAsync(IdentityRoleNameChangedEvent eventData) + { + var role = await RoleRepository.FindAsync(eventData.IdentityRole.Id, false).ConfigureAwait(false); + if (role == null) + { + return; + } + + var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync(RolePermissionValueProvider.ProviderName, eventData.OldName).ConfigureAwait(false); + foreach (var permissionGrant in permissionGrantsInRole) + { + await PermissionManager.UpdateProviderKeyAsync(permissionGrant, eventData.IdentityRole.Name).ConfigureAwait(false); + } + } + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo.Abp.Identity.Application.Tests.csproj b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo.Abp.Identity.Application.Tests.csproj index 46ced70f5a..58a34d0198 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo.Abp.Identity.Application.Tests.csproj +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo.Abp.Identity.Application.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityRoleAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityRoleAppService_Tests.cs index 03e872271f..b743ee54e9 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityRoleAppService_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityRoleAppService_Tests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Xunit; using Shouldly; +using Volo.Abp.Application.Dtos; namespace Volo.Abp.Identity { @@ -22,11 +23,11 @@ namespace Volo.Abp.Identity { //Arrange - var moderator = await GetRoleAsync("moderator"); + var moderator = await GetRoleAsync("moderator").ConfigureAwait(false); //Act - var result = await _roleAppService.GetAsync(moderator.Id); + var result = await _roleAppService.GetAsync(moderator.Id).ConfigureAwait(false); //Assert @@ -38,7 +39,7 @@ namespace Volo.Abp.Identity { //Act - var result = await _roleAppService.GetListAsync(); + var result = await _roleAppService.GetListAsync(new PagedAndSortedResultRequestDto()).ConfigureAwait(false); //Assert @@ -57,14 +58,14 @@ namespace Volo.Abp.Identity //Act - var result = await _roleAppService.CreateAsync(input); + var result = await _roleAppService.CreateAsync(input).ConfigureAwait(false); //Assert result.Id.ShouldNotBe(Guid.Empty); result.Name.ShouldBe(input.Name); - var role = await _roleRepository.GetAsync(result.Id); + var role = await _roleRepository.GetAsync(result.Id).ConfigureAwait(false); role.Name.ShouldBe(input.Name); } @@ -73,7 +74,7 @@ namespace Volo.Abp.Identity { //Arrange - var moderator = await GetRoleAsync("moderator"); + var moderator = await GetRoleAsync("moderator").ConfigureAwait(false); var input = new IdentityRoleUpdateDto { @@ -85,14 +86,14 @@ namespace Volo.Abp.Identity //Act - var result = await _roleAppService.UpdateAsync(moderator.Id, input); + var result = await _roleAppService.UpdateAsync(moderator.Id, input).ConfigureAwait(false); //Assert result.Id.ShouldBe(moderator.Id); result.Name.ShouldBe(input.Name); - var updatedRole = await _roleRepository.GetAsync(moderator.Id); + var updatedRole = await _roleRepository.GetAsync(moderator.Id).ConfigureAwait(false); updatedRole.Name.ShouldBe(input.Name); } @@ -101,15 +102,15 @@ namespace Volo.Abp.Identity { //Arrange - var moderator = await GetRoleAsync("moderator"); + var moderator = await GetRoleAsync("moderator").ConfigureAwait(false); //Act - await _roleAppService.DeleteAsync(moderator.Id); + await _roleAppService.DeleteAsync(moderator.Id).ConfigureAwait(false); //Assert - (await FindRoleAsync("moderator")).ShouldBeNull(); + (await FindRoleAsync("moderator").ConfigureAwait(false)).ShouldBeNull(); } private async Task GetRoleAsync(string roleName) diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs index 6fbf23ed73..19cfb705fd 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.Identity //Act - var result = await _userAppService.GetAsync(johnNash.Id); + var result = await _userAppService.GetAsync(johnNash.Id).ConfigureAwait(false); //Assert @@ -44,7 +44,7 @@ namespace Volo.Abp.Identity { //Act - var result = await _userAppService.GetListAsync(new GetIdentityUsersInput()); + var result = await _userAppService.GetListAsync(new GetIdentityUsersInput()).ConfigureAwait(false); //Assert @@ -69,7 +69,7 @@ namespace Volo.Abp.Identity //Act - var result = await _userAppService.CreateAsync(input); + var result = await _userAppService.CreateAsync(input).ConfigureAwait(false); //Assert @@ -79,7 +79,7 @@ namespace Volo.Abp.Identity result.LockoutEnabled.ShouldBe(input.LockoutEnabled); result.PhoneNumber.ShouldBe(input.PhoneNumber); - var user = await _userRepository.GetAsync(result.Id); + var user = await _userRepository.GetAsync(result.Id).ConfigureAwait(false); user.Id.ShouldBe(result.Id); user.UserName.ShouldBe(input.UserName); user.Email.ShouldBe(input.Email); @@ -110,7 +110,7 @@ namespace Volo.Abp.Identity //Act - var result = await _userAppService.UpdateAsync(johnNash.Id, input); + var result = await _userAppService.UpdateAsync(johnNash.Id, input).ConfigureAwait(false); //Assert @@ -120,7 +120,7 @@ namespace Volo.Abp.Identity result.LockoutEnabled.ShouldBe(input.LockoutEnabled); result.PhoneNumber.ShouldBe(input.PhoneNumber); - var user = await _userRepository.GetAsync(result.Id); + var user = await _userRepository.GetAsync(result.Id).ConfigureAwait(false); user.Id.ShouldBe(result.Id); user.UserName.ShouldBe(input.UserName); user.Email.ShouldBe(input.Email); @@ -134,7 +134,7 @@ namespace Volo.Abp.Identity public async Task UpdateAsync_Concurrency_Exception() { //Get user - var johnNash = await _userAppService.GetAsync(_testData.UserJohnId); + var johnNash = await _userAppService.GetAsync(_testData.UserJohnId).ConfigureAwait(false); //Act @@ -151,13 +151,13 @@ namespace Volo.Abp.Identity ConcurrencyStamp = johnNash.ConcurrencyStamp }; - await _userAppService.UpdateAsync(johnNash.Id, input); + await _userAppService.UpdateAsync(johnNash.Id, input).ConfigureAwait(false); //Second update with same input will throw exception because the entity has been modified (await Assert.ThrowsAsync(async () => { - await _userAppService.UpdateAsync(johnNash.Id, input); - })).Message.ShouldContain("Optimistic concurrency failure"); + await _userAppService.UpdateAsync(johnNash.Id, input).ConfigureAwait(false); + }).ConfigureAwait(false)).Message.ShouldContain("Optimistic concurrency failure"); } [Fact] @@ -169,7 +169,7 @@ namespace Volo.Abp.Identity //Act - await _userAppService.DeleteAsync(johnNash.Id); + await _userAppService.DeleteAsync(johnNash.Id).ConfigureAwait(false); //Assert @@ -185,7 +185,7 @@ namespace Volo.Abp.Identity //Act - var result = await _userAppService.GetRolesAsync(johnNash.Id); + var result = await _userAppService.GetRolesAsync(johnNash.Id).ConfigureAwait(false); //Assert @@ -209,11 +209,11 @@ namespace Volo.Abp.Identity { RoleNames = new[] { "admin", "moderator" } } - ); + ).ConfigureAwait(false); //Assert - var roleNames = await _userRepository.GetRoleNamesAsync(johnNash.Id); + var roleNames = await _userRepository.GetRoleNamesAsync(johnNash.Id).ConfigureAwait(false); roleNames.Count.ShouldBe(2); roleNames.ShouldContain("admin"); roleNames.ShouldContain("moderator"); diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs index 227977cf15..f28c65be83 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserLookupAppService_Tests.cs @@ -24,32 +24,32 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByIdAsync() { - var user = await _identityUserRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _identityUserRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserLookupAppService.FindByIdAsync(user.Id)).UserName.ShouldBe(user.UserName); + (await _identityUserLookupAppService.FindByIdAsync(user.Id).ConfigureAwait(false)).UserName.ShouldBe(user.UserName); } [Fact] public async Task FindById_NotExist_Should_Return_Null() { - var user = await _identityUserLookupAppService.FindByIdAsync(Guid.NewGuid()); + var user = await _identityUserLookupAppService.FindByIdAsync(Guid.NewGuid()).ConfigureAwait(false); user.ShouldBeNull(); } [Fact] public async Task FindByUserNameAsync() { - var user = await _identityUserRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _identityUserRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserLookupAppService.FindByUserNameAsync(user.UserName)).UserName.ShouldBe(user.UserName); + (await _identityUserLookupAppService.FindByUserNameAsync(user.UserName).ConfigureAwait(false)).UserName.ShouldBe(user.UserName); } [Fact] public async Task FindByUserName_NotExist_Should_Return_Null() { - var user = await _identityUserLookupAppService.FindByUserNameAsync(Guid.NewGuid().ToString()); + var user = await _identityUserLookupAppService.FindByUserNameAsync(Guid.NewGuid().ToString()).ConfigureAwait(false); user.ShouldBeNull(); } } diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs index fc0334ce05..c6e2d45055 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.Identity _currentUser.IsAuthenticated.Returns(true); //Act - var result = await _profileAppService.GetAsync(); + var result = await _profileAppService.GetAsync().ConfigureAwait(false); //Assert var johnNash = GetUser("john.nash"); @@ -62,7 +62,7 @@ namespace Volo.Abp.Identity }; //Act - var result = await _profileAppService.UpdateAsync(input); + var result = await _profileAppService.UpdateAsync(input).ConfigureAwait(false); //Assert result.UserName.ShouldBe(input.UserName); diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo.Abp.Identity.Domain.Tests.csproj b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo.Abp.Identity.Domain.Tests.csproj index 2c9ecaef14..59614115e4 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo.Abp.Identity.Domain.Tests.csproj +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo.Abp.Identity.Domain.Tests.csproj @@ -18,7 +18,7 @@ - + diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs index cbb52f02ba..d9fb330a02 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs @@ -3,6 +3,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.Identity; +using Volo.Abp.Threading; namespace Volo.Abp.Identity { @@ -22,9 +23,9 @@ namespace Volo.Abp.Identity { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .Build()); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs index 6f81d8dcf5..cc349fd3f3 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Identity ) ); - using (AbpCultureHelper.Use("tr")) + using (CultureHelper.Use("tr")) { var localizeMessage = exception.LocalizeMessage(new LocalizationContext(ServiceProvider)); diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs index 95e8f925c4..e16228290c 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs @@ -40,11 +40,11 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); - await _userManager.SetEmailAsync(user, "john.nash_UPDATED@abp.io"); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); + await _userManager.SetEmailAsync(user, "john.nash_UPDATED@abp.io").ConfigureAwait(false); _testCounter.GetValue("EntityUpdatedEto").ShouldBe(0); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } _testCounter.GetValue("EntityUpdatedEto").ShouldBe(1); diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs index c27967e704..c7622bec8b 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.Identity { var claimType = await _claimTypeManager.CreateAsync(new IdentityClaimType(Guid.NewGuid(), "Phone", false, false, null, - null, null, IdentityClaimValueType.String)); + null, null, IdentityClaimValueType.String)).ConfigureAwait(false); claimType.ShouldNotBeNull(); claimType.Name.ShouldBe("Phone"); @@ -36,17 +36,17 @@ namespace Volo.Abp.Identity { await Assert.ThrowsAnyAsync(async () => await _claimTypeManager.CreateAsync( new IdentityClaimType( - Guid.NewGuid(), "Age"))); + Guid.NewGuid(), "Age")).ConfigureAwait(false)).ConfigureAwait(false); } [Fact] public async Task UpdateAsync() { - var ageClaim = _identityClaimTypeRepository.Find(_testData.AgeClaimId); + var ageClaim = await _identityClaimTypeRepository.FindAsync(_testData.AgeClaimId).ConfigureAwait(false); ageClaim.ShouldNotBeNull(); ageClaim.Description = "this is age"; - var updatedAgeClaimType = await _claimTypeManager.UpdateAsync(ageClaim); + var updatedAgeClaimType = await _claimTypeManager.UpdateAsync(ageClaim).ConfigureAwait(false); updatedAgeClaimType.ShouldNotBeNull(); updatedAgeClaimType.Description.ShouldBe("this is age"); } @@ -57,7 +57,7 @@ namespace Volo.Abp.Identity { await Assert.ThrowsAnyAsync(async () => await _claimTypeManager.UpdateAsync( new IdentityClaimType( - Guid.NewGuid(), "Age"))); + Guid.NewGuid(), "Age")).ConfigureAwait(false)).ConfigureAwait(false); } @@ -65,9 +65,9 @@ namespace Volo.Abp.Identity public async Task Static_IdentityClaimType_Cant_Not_Update() { var phoneClaim = new IdentityClaimType(Guid.NewGuid(), "Phone", true, true); - _identityClaimTypeRepository.Insert(phoneClaim); + await _identityClaimTypeRepository.InsertAsync(phoneClaim).ConfigureAwait(false); - await Assert.ThrowsAnyAsync(async () => await _claimTypeManager.UpdateAsync(phoneClaim)); + await Assert.ThrowsAnyAsync(async () => await _claimTypeManager.UpdateAsync(phoneClaim).ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleManager_Tests.cs index 4314f3eac6..fbb2a3c023 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleManager_Tests.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.Identity [Fact] public async Task GetByIdAsync() { - var role = await _identityRoleManager.FindByIdAsync(_testData.RoleModeratorId.ToString()); + var role = await _identityRoleManager.FindByIdAsync(_testData.RoleModeratorId.ToString()).ConfigureAwait(false); role.ShouldNotBeNull(); role.Name.ShouldBe("moderator"); @@ -37,10 +37,10 @@ namespace Volo.Abp.Identity [Fact] public async Task SetRoleNameAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - (await _identityRoleManager.SetRoleNameAsync(role, "teacher")).Succeeded.ShouldBeTrue(); + (await _identityRoleManager.SetRoleNameAsync(role, "teacher").ConfigureAwait(false)).Succeeded.ShouldBeTrue(); role.Name.ShouldBe("teacher"); } @@ -48,12 +48,12 @@ namespace Volo.Abp.Identity [Fact] public async Task DeleteAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - await _identityRoleManager.DeleteAsync(role); + await _identityRoleManager.DeleteAsync(role).ConfigureAwait(false); - (await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator"))).ShouldBeNull(); + (await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false)).ShouldBeNull(); } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleStore_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleStore_Tests.cs index 11345a4a46..9a4d9d194d 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleStore_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityRoleStore_Tests.cs @@ -32,9 +32,9 @@ namespace Volo.Abp.Identity { var roleId = Guid.NewGuid(); var role = new IdentityRole(roleId, "teacher"); - (await _identityRoleStore.CreateAsync(role)).Succeeded.ShouldBeTrue(); + (await _identityRoleStore.CreateAsync(role).ConfigureAwait(false)).Succeeded.ShouldBeTrue(); - var teacher = await _identityRoleStore.FindByIdAsync(roleId.ToString()); + var teacher = await _identityRoleStore.FindByIdAsync(roleId.ToString()).ConfigureAwait(false); teacher.ShouldNotBeNull(); teacher.Name.ShouldBe("teacher"); @@ -43,11 +43,11 @@ namespace Volo.Abp.Identity [Fact] public async Task UpdateAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); role.IsDefault = true; - await _identityRoleStore.UpdateAsync(role); + await _identityRoleStore.UpdateAsync(role).ConfigureAwait(false); role.IsDefault.ShouldBeTrue(); } @@ -56,40 +56,40 @@ namespace Volo.Abp.Identity [Fact] public async Task DeleteAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - await _identityRoleStore.DeleteAsync(role); + await _identityRoleStore.DeleteAsync(role).ConfigureAwait(false); - (await _identityRoleStore.FindByIdAsync(_testData.RoleModeratorId.ToString())).ShouldBeNull(); + (await _identityRoleStore.FindByIdAsync(_testData.RoleModeratorId.ToString()).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task GetRoleIdAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - (await _identityRoleStore.GetRoleIdAsync(role)).ShouldBe(_testData.RoleModeratorId.ToString()); + (await _identityRoleStore.GetRoleIdAsync(role).ConfigureAwait(false)).ShouldBe(_testData.RoleModeratorId.ToString()); } [Fact] public async Task GetRoleNameAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - (await _identityRoleStore.GetRoleNameAsync(role)).ShouldBe(role.Name); + (await _identityRoleStore.GetRoleNameAsync(role).ConfigureAwait(false)).ShouldBe(role.Name); } [Fact] public async Task SetRoleNameAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - await _identityRoleStore.SetRoleNameAsync(role, "teacher"); + await _identityRoleStore.SetRoleNameAsync(role, "teacher").ConfigureAwait(false); role.Name.ShouldBe("teacher"); } @@ -97,7 +97,7 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByIdAsync() { - var role = await _identityRoleStore.FindByIdAsync(_testData.RoleModeratorId.ToString()); + var role = await _identityRoleStore.FindByIdAsync(_testData.RoleModeratorId.ToString()).ConfigureAwait(false); role.ShouldNotBeNull(); role.Name.ShouldBe("moderator"); @@ -106,7 +106,7 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByNameAsync() { - var role = await _identityRoleStore.FindByNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleStore.FindByNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); role.Name.ShouldBe("moderator"); @@ -115,19 +115,19 @@ namespace Volo.Abp.Identity [Fact] public async Task GetNormalizedRoleNameAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - (await _identityRoleStore.GetNormalizedRoleNameAsync(role)).ShouldBe(role.NormalizedName); + (await _identityRoleStore.GetNormalizedRoleNameAsync(role).ConfigureAwait(false)).ShouldBe(role.NormalizedName); } [Fact] public async Task SetNormalizedRoleNameAsync() { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - await _identityRoleStore.SetNormalizedRoleNameAsync(role, _lookupNormalizer.NormalizeName("teacher")); + await _identityRoleStore.SetNormalizedRoleNameAsync(role, _lookupNormalizer.NormalizeName("teacher")).ConfigureAwait(false); role.NormalizedName.ShouldBe(_lookupNormalizer.NormalizeName("teacher")); } @@ -137,15 +137,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - var claims = await _identityRoleStore.GetClaimsAsync(role); + var claims = await _identityRoleStore.GetClaimsAsync(role).ConfigureAwait(false); claims.ShouldNotBeEmpty(); claims.ShouldContain(x => x.Type == "test-claim" && x.Value == "test-value"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -156,7 +156,7 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); role.Claims.Add(new IdentityRoleClaim(Guid.NewGuid(), role.Id, "my-claim", "my-value", role.TenantId)); @@ -164,7 +164,7 @@ namespace Volo.Abp.Identity //role.Claims.ShouldContain(x => x.ClaimType == "my-claim" && x.ClaimValue == "my-value"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -173,7 +173,7 @@ namespace Volo.Abp.Identity throw; } - var role2 = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role2 = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role2.ShouldNotBeNull(); role2.Claims.ShouldContain(x => x.ClaimType == "my-claim" && x.ClaimValue == "my-value"); } @@ -183,14 +183,14 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")); + var role = await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.ShouldNotBeNull(); - await _identityRoleStore.RemoveClaimAsync(role, new Claim("test-claim", "test-value")); + await _identityRoleStore.RemoveClaimAsync(role, new Claim("test-claim", "test-value")).ConfigureAwait(false); role.Claims.ShouldNotContain(x => x.ClaimType == "test-claim" && x.ClaimValue == "test-value"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs index 761655deb2..bc03f35c49 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs @@ -31,7 +31,7 @@ namespace Volo.Abp.Identity [Fact] public async Task GetByIdAsync() { - var user = await _identityUserManager.GetByIdAsync(_testData.UserJohnId); + var user = await _identityUserManager.GetByIdAsync(_testData.UserJohnId).ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("john.nash"); @@ -43,18 +43,18 @@ namespace Volo.Abp.Identity using (var uow = _unitOfWorkManager.Begin()) { var user = await _identityUserRepository.FindByNormalizedUserNameAsync( - _lookupNormalizer.NormalizeName("david")); + _lookupNormalizer.NormalizeName("david")).ConfigureAwait(false); user.ShouldNotBeNull(); var identityResult = await _identityUserManager.SetRolesAsync(user, new List() { "moderator", - }); + }).ConfigureAwait(false); identityResult.Succeeded.ShouldBeTrue(); user.Roles.ShouldContain(x => x.RoleId == _testData.RoleModeratorId); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -64,23 +64,23 @@ namespace Volo.Abp.Identity using (var uow = _unitOfWorkManager.Begin()) { var roleSupporter = - await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("supporter")); + await _identityRoleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("supporter")).ConfigureAwait(false); roleSupporter.ShouldNotBeNull(); var user = await _identityUserRepository.FindByNormalizedUserNameAsync( - _lookupNormalizer.NormalizeName("john.nash")); + _lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var identityResult = await _identityUserManager.SetRolesAsync(user, new List() { "admin", - }); + }).ConfigureAwait(false); identityResult.Succeeded.ShouldBeTrue(); user.Roles.ShouldNotContain(x => x.RoleId == _testData.RoleModeratorId); user.Roles.ShouldNotContain(x => x.RoleId == roleSupporter.Id); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs index 6e84a88450..6c7b6610ae 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs @@ -29,29 +29,29 @@ namespace Volo.Abp.Identity [Fact] public async Task GetUserIdAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetUserIdAsync(user)).ShouldBe(user.Id.ToString()); + (await _identityUserStore.GetUserIdAsync(user).ConfigureAwait(false)).ShouldBe(user.Id.ToString()); } [Fact] public async Task GetUserNameAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetUserNameAsync(user)).ShouldBe(user.UserName); + (await _identityUserStore.GetUserNameAsync(user).ConfigureAwait(false)).ShouldBe(user.UserName); } [Fact] public async Task SetUserNameAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetUserNameAsync(user, "bob.lee"); + await _identityUserStore.SetUserNameAsync(user, "bob.lee").ConfigureAwait(false); user.UserName.ShouldBe("bob.lee"); //user.NormalizedUserName.ShouldBe(_lookupNormalizer.Normalize("bob.lee")); } @@ -60,19 +60,19 @@ namespace Volo.Abp.Identity [Fact] public async Task GetNormalizedUserNameAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetNormalizedUserNameAsync(user)).ShouldBe(user.NormalizedUserName); + (await _identityUserStore.GetNormalizedUserNameAsync(user).ConfigureAwait(false)).ShouldBe(user.NormalizedUserName); } [Fact] public async Task SetNormalizedUserNameAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetNormalizedUserNameAsync(user, _lookupNormalizer.NormalizeName("bob.lee")); + await _identityUserStore.SetNormalizedUserNameAsync(user, _lookupNormalizer.NormalizeName("bob.lee")).ConfigureAwait(false); user.NormalizedUserName.ShouldBe(_lookupNormalizer.NormalizeName("bob.lee")); } @@ -83,9 +83,9 @@ namespace Volo.Abp.Identity var userId = Guid.NewGuid(); var user = new IdentityUser(userId, "bob.lee", "bob.lee@abp.io"); - await _identityUserStore.CreateAsync(user); + await _identityUserStore.CreateAsync(user).ConfigureAwait(false); - var bobLee = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("bob.lee")); + var bobLee = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("bob.lee")).ConfigureAwait(false); bobLee.ShouldNotBeNull(); bobLee.UserName.ShouldBe("bob.lee"); bobLee.Email.ShouldBe("bob.lee@abp.io"); @@ -94,26 +94,26 @@ namespace Volo.Abp.Identity [Fact] public async Task UpdateAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Name = "lee"; - (await _identityUserStore.UpdateAsync(user)).Succeeded.ShouldBeTrue(); + (await _identityUserStore.UpdateAsync(user).ConfigureAwait(false)).Succeeded.ShouldBeTrue(); - (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash"))).Name + (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false)).Name .ShouldBe("lee"); } [Fact] public async Task Update_Concurrency() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.UpdateAsync(user)).Succeeded.ShouldBeTrue(); + (await _identityUserStore.UpdateAsync(user).ConfigureAwait(false)).Succeeded.ShouldBeTrue(); user.ConcurrencyStamp = Guid.NewGuid().ToString(); - var identityResult = await _identityUserStore.UpdateAsync(user); + var identityResult = await _identityUserStore.UpdateAsync(user).ConfigureAwait(false); identityResult.Succeeded.ShouldBeFalse(); identityResult.Errors.ShouldContain(x => @@ -126,19 +126,19 @@ namespace Volo.Abp.Identity [Fact] public async Task DeleteAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.DeleteAsync(user)).Succeeded.ShouldBeTrue(); + (await _identityUserStore.DeleteAsync(user).ConfigureAwait(false)).Succeeded.ShouldBeTrue(); - (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash"))).ShouldBeNull(); + (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task FindByIdAsync() { - var user = await _identityUserStore.FindByIdAsync(_testData.UserJohnId.ToString()); + var user = await _identityUserStore.FindByIdAsync(_testData.UserJohnId.ToString()).ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("john.nash"); @@ -148,7 +148,7 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByNameAsync() { - var user = await _identityUserStore.FindByNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _identityUserStore.FindByNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("john.nash"); @@ -158,11 +158,11 @@ namespace Volo.Abp.Identity [Fact] public async Task SetPasswordHashAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.PasswordHash.ShouldBeNull(); - await _identityUserStore.SetPasswordHashAsync(user, "P@ssw0rd"); + await _identityUserStore.SetPasswordHashAsync(user, "P@ssw0rd").ConfigureAwait(false); user.PasswordHash.ShouldBe("P@ssw0rd"); } @@ -170,23 +170,23 @@ namespace Volo.Abp.Identity [Fact] public async Task GetPasswordHashAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetPasswordHashAsync(user, "P@ssw0rd"); + await _identityUserStore.SetPasswordHashAsync(user, "P@ssw0rd").ConfigureAwait(false); - (await _identityUserStore.GetPasswordHashAsync(user)).ShouldBe("P@ssw0rd"); + (await _identityUserStore.GetPasswordHashAsync(user).ConfigureAwait(false)).ShouldBe("P@ssw0rd"); } [Fact] public async Task HasPasswordAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.HasPasswordAsync(user)).ShouldBeFalse(); + (await _identityUserStore.HasPasswordAsync(user).ConfigureAwait(false)).ShouldBeFalse(); - await _identityUserStore.SetPasswordHashAsync(user, "P@ssw0rd"); - (await _identityUserStore.HasPasswordAsync(user)).ShouldBeTrue(); + await _identityUserStore.SetPasswordHashAsync(user, "P@ssw0rd").ConfigureAwait(false); + (await _identityUserStore.HasPasswordAsync(user).ConfigureAwait(false)).ShouldBeTrue(); } [Fact] @@ -194,15 +194,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("david")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("david")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Roles.ShouldBeEmpty(); - await _identityUserStore.AddToRoleAsync(user, _lookupNormalizer.NormalizeName("moderator")); + await _identityUserStore.AddToRoleAsync(user, _lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); user.Roles.ShouldContain(x => x.RoleId == _testData.RoleModeratorId); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -211,15 +211,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Roles.ShouldContain(x => x.RoleId == _testData.RoleModeratorId); - await _identityUserStore.RemoveFromRoleAsync(user, _lookupNormalizer.NormalizeName("moderator")); + await _identityUserStore.RemoveFromRoleAsync(user, _lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); user.Roles.ShouldNotContain(x => x.RoleId == _testData.RoleModeratorId); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -227,10 +227,10 @@ namespace Volo.Abp.Identity [Fact] public async Task GetRolesAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - var roleNames = await _identityUserStore.GetRolesAsync(user); + var roleNames = await _identityUserStore.GetRolesAsync(user).ConfigureAwait(false); roleNames.ShouldNotBeEmpty(); roleNames.ShouldContain(x => x == "moderator"); roleNames.ShouldContain(x => x == "supporter"); @@ -241,13 +241,13 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.IsInRoleAsync(user, _lookupNormalizer.NormalizeName("moderator"))).ShouldBeTrue(); - (await _identityUserStore.IsInRoleAsync(user, _lookupNormalizer.NormalizeName("moderatorNotExist"))).ShouldBeFalse(); + (await _identityUserStore.IsInRoleAsync(user, _lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false)).ShouldBeTrue(); + (await _identityUserStore.IsInRoleAsync(user, _lookupNormalizer.NormalizeName("moderatorNotExist")).ConfigureAwait(false)).ShouldBeFalse(); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -256,14 +256,14 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - var claims = await _identityUserStore.GetClaimsAsync(user); + var claims = await _identityUserStore.GetClaimsAsync(user).ConfigureAwait(false); claims.ShouldNotBeEmpty(); claims.ShouldContain(x => x.Type == "TestClaimType" && x.Value == "42"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -272,18 +272,18 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Claims.ShouldNotContain(x => x.ClaimType == "MyClaimType" && x.ClaimValue == "MyClaimValue"); await _identityUserStore.AddClaimsAsync(user, new List() { new Claim("MyClaimType", "MyClaimValue") - }); + }).ConfigureAwait(false); user.Claims.ShouldContain(x => x.ClaimType == "MyClaimType" && x.ClaimValue == "MyClaimValue"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -292,15 +292,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.ReplaceClaimAsync(user, new Claim("TestClaimType", "42"), new Claim("MyClaimType", "MyClaimValue")); + await _identityUserStore.ReplaceClaimAsync(user, new Claim("TestClaimType", "42"), new Claim("MyClaimType", "MyClaimValue")).ConfigureAwait(false); user.Claims.ShouldNotContain(x => x.ClaimType == "TestClaimType" && x.ClaimValue == "42"); user.Claims.ShouldContain(x => x.ClaimType == "MyClaimType" && x.ClaimValue == "MyClaimValue"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -309,17 +309,17 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); await _identityUserStore.RemoveClaimsAsync(user, new List() { new Claim("TestClaimType", "42") - }); + }).ConfigureAwait(false); user.Claims.ShouldNotContain(x => x.ClaimType == "TestClaimType" && x.ClaimValue == "42"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -328,15 +328,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Logins.ShouldNotContain(x => x.LoginProvider == "facebook" && x.ProviderKey == "john"); - await _identityUserStore.AddLoginAsync(user, new UserLoginInfo("facebook", "john", "John Nash")); + await _identityUserStore.AddLoginAsync(user, new UserLoginInfo("facebook", "john", "John Nash")).ConfigureAwait(false); user.Logins.ShouldContain(x => x.LoginProvider == "facebook" && x.ProviderKey == "john"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -345,15 +345,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Logins.ShouldContain(x => x.LoginProvider == "github" && x.ProviderKey == "john"); - await _identityUserStore.RemoveLoginAsync(user, "github", "john"); + await _identityUserStore.RemoveLoginAsync(user, "github", "john").ConfigureAwait(false); user.Logins.ShouldNotContain(x => x.LoginProvider == "github" && x.ProviderKey == "john"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -363,16 +363,16 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - var logins = await _identityUserStore.GetLoginsAsync(user); + var logins = await _identityUserStore.GetLoginsAsync(user).ConfigureAwait(false); logins.ShouldNotBeNull(); logins.ShouldContain(x => x.LoginProvider == "github" && x.ProviderKey == "john"); logins.ShouldContain(x => x.LoginProvider == "twitter" && x.ProviderKey == "johnx"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -380,7 +380,7 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByLoginAsync() { - var user = await _identityUserStore.FindByLoginAsync("github", "john"); + var user = await _identityUserStore.FindByLoginAsync("github", "john").ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("john.nash"); } @@ -389,21 +389,21 @@ namespace Volo.Abp.Identity [Fact] public async Task GetEmailConfirmedAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetEmailConfirmedAsync(user)).ShouldBe(user.EmailConfirmed); + (await _identityUserStore.GetEmailConfirmedAsync(user).ConfigureAwait(false)).ShouldBe(user.EmailConfirmed); } [Fact] public async Task SetEmailConfirmedAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var emailConfirmed = user.EmailConfirmed; - await _identityUserStore.SetEmailConfirmedAsync(user, !emailConfirmed); + await _identityUserStore.SetEmailConfirmedAsync(user, !emailConfirmed).ConfigureAwait(false); user.EmailConfirmed.ShouldBe(!emailConfirmed); } @@ -411,10 +411,10 @@ namespace Volo.Abp.Identity [Fact] public async Task SetEmailAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetEmailAsync(user, "john.nash.kobe@abp.io"); + await _identityUserStore.SetEmailAsync(user, "john.nash.kobe@abp.io").ConfigureAwait(false); user.Email.ShouldBe("john.nash.kobe@abp.io"); //user.NormalizedEmail.ShouldBe(_lookupNormalizer.Normalize("john.nash.kobe@abp.io")); @@ -423,28 +423,28 @@ namespace Volo.Abp.Identity [Fact] public async Task GetEmailAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetEmailAsync(user)).ShouldBe(user.Email); + (await _identityUserStore.GetEmailAsync(user).ConfigureAwait(false)).ShouldBe(user.Email); } [Fact] public async Task GetNormalizedEmailAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetNormalizedEmailAsync(user)).ShouldBe(user.NormalizedEmail); + (await _identityUserStore.GetNormalizedEmailAsync(user).ConfigureAwait(false)).ShouldBe(user.NormalizedEmail); } [Fact] public async Task SetNormalizedEmailAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetNormalizedEmailAsync(user, _lookupNormalizer.NormalizeEmail("john.nash.kobe@abp.io")); + await _identityUserStore.SetNormalizedEmailAsync(user, _lookupNormalizer.NormalizeEmail("john.nash.kobe@abp.io")).ConfigureAwait(false); user.NormalizedEmail.ShouldBe(_lookupNormalizer.NormalizeEmail("john.nash.kobe@abp.io")); } @@ -452,7 +452,7 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByEmailAsync() { - var user = await _identityUserStore.FindByEmailAsync(_lookupNormalizer.NormalizeEmail("john.nash@abp.io")); + var user = await _identityUserStore.FindByEmailAsync(_lookupNormalizer.NormalizeEmail("john.nash@abp.io")).ConfigureAwait(false); user.ShouldNotBeNull(); user.Email.ShouldBe("john.nash@abp.io"); @@ -461,19 +461,19 @@ namespace Volo.Abp.Identity [Fact] public async Task GetLockoutEndDateAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetLockoutEndDateAsync(user)).ShouldBe(user.LockoutEnd); + (await _identityUserStore.GetLockoutEndDateAsync(user).ConfigureAwait(false)).ShouldBe(user.LockoutEnd); } [Fact] public async Task SetLockoutEndDateAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetLockoutEndDateAsync(user, DateTimeOffset.Parse("01/01/2019")); + await _identityUserStore.SetLockoutEndDateAsync(user, DateTimeOffset.Parse("01/01/2019")).ConfigureAwait(false); user.LockoutEnd.ShouldBe(DateTimeOffset.Parse("01/01/2019")); } @@ -482,11 +482,11 @@ namespace Volo.Abp.Identity [Fact] public async Task IncrementAccessFailedCountAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var count = user.AccessFailedCount; - await _identityUserStore.IncrementAccessFailedCountAsync(user); + await _identityUserStore.IncrementAccessFailedCountAsync(user).ConfigureAwait(false); user.AccessFailedCount.ShouldBe(count + 1); } @@ -494,10 +494,10 @@ namespace Volo.Abp.Identity [Fact] public async Task ResetAccessFailedCountAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.ResetAccessFailedCountAsync(user); + await _identityUserStore.ResetAccessFailedCountAsync(user).ConfigureAwait(false); user.AccessFailedCount.ShouldBe(0); } @@ -505,29 +505,29 @@ namespace Volo.Abp.Identity [Fact] public async Task GetAccessFailedCountAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetAccessFailedCountAsync(user)).ShouldBe(user.AccessFailedCount); + (await _identityUserStore.GetAccessFailedCountAsync(user).ConfigureAwait(false)).ShouldBe(user.AccessFailedCount); } [Fact] public async Task GetLockoutEnabledAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetLockoutEnabledAsync(user)).ShouldBe(user.LockoutEnabled); + (await _identityUserStore.GetLockoutEnabledAsync(user).ConfigureAwait(false)).ShouldBe(user.LockoutEnabled); } [Fact] public async Task SetLockoutEnabledAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var lockoutEnabled = user.LockoutEnabled; - await _identityUserStore.SetLockoutEnabledAsync(user, !lockoutEnabled); + await _identityUserStore.SetLockoutEnabledAsync(user, !lockoutEnabled).ConfigureAwait(false); user.LockoutEnabled.ShouldBe(!lockoutEnabled); } @@ -536,10 +536,10 @@ namespace Volo.Abp.Identity [Fact] public async Task SetPhoneNumberAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetPhoneNumberAsync(user, "13800138000"); + await _identityUserStore.SetPhoneNumberAsync(user, "13800138000").ConfigureAwait(false); user.PhoneNumber.ShouldBe("13800138000"); } @@ -548,30 +548,30 @@ namespace Volo.Abp.Identity [Fact] public async Task GetPhoneNumberAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetPhoneNumberAsync(user)).ShouldBe(user.PhoneNumber); + (await _identityUserStore.GetPhoneNumberAsync(user).ConfigureAwait(false)).ShouldBe(user.PhoneNumber); } [Fact] public async Task GetPhoneNumberConfirmedAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetPhoneNumberConfirmedAsync(user)).ShouldBe(user.PhoneNumberConfirmed); + (await _identityUserStore.GetPhoneNumberConfirmedAsync(user).ConfigureAwait(false)).ShouldBe(user.PhoneNumberConfirmed); } [Fact] public async Task SetPhoneNumberConfirmedAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var phoneNumberConfirmed = user.PhoneNumberConfirmed; - await _identityUserStore.SetPhoneNumberConfirmedAsync(user, !phoneNumberConfirmed); + await _identityUserStore.SetPhoneNumberConfirmedAsync(user, !phoneNumberConfirmed).ConfigureAwait(false); user.PhoneNumberConfirmed.ShouldBe(!phoneNumberConfirmed); } @@ -580,11 +580,11 @@ namespace Volo.Abp.Identity [Fact] public async Task SetSecurityStampAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var securityStamp = Guid.NewGuid().ToString(); - await _identityUserStore.SetSecurityStampAsync(user, securityStamp); + await _identityUserStore.SetSecurityStampAsync(user, securityStamp).ConfigureAwait(false); user.SecurityStamp.ShouldBe(securityStamp); } @@ -592,21 +592,21 @@ namespace Volo.Abp.Identity [Fact] public async Task GetSecurityStampAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetSecurityStampAsync(user)).ShouldBe(user.SecurityStamp); + (await _identityUserStore.GetSecurityStampAsync(user).ConfigureAwait(false)).ShouldBe(user.SecurityStamp); } [Fact] public async Task SetTwoFactorEnabledAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); var twoFactorEnabled = user.TwoFactorEnabled; - await _identityUserStore.SetTwoFactorEnabledAsync(user, !twoFactorEnabled); + await _identityUserStore.SetTwoFactorEnabledAsync(user, !twoFactorEnabled).ConfigureAwait(false); user.TwoFactorEnabled.ShouldBe(!twoFactorEnabled); } @@ -615,16 +615,16 @@ namespace Volo.Abp.Identity [Fact] public async Task GetTwoFactorEnabledAsync() { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetTwoFactorEnabledAsync(user)).ShouldBe(user.TwoFactorEnabled); + (await _identityUserStore.GetTwoFactorEnabledAsync(user).ConfigureAwait(false)).ShouldBe(user.TwoFactorEnabled); } [Fact] public async Task GetUsersForClaimAsync() { - var user = await _identityUserStore.GetUsersForClaimAsync(new Claim("TestClaimType", "42")); + var user = await _identityUserStore.GetUsersForClaimAsync(new Claim("TestClaimType", "42")).ConfigureAwait(false); user.ShouldNotBeNull(); user.ShouldNotBeEmpty(); user.ShouldContain(x => x.UserName == "john.nash"); @@ -633,7 +633,7 @@ namespace Volo.Abp.Identity [Fact] public async Task GetUsersInRoleAsync() { - var user = await _identityUserStore.GetUsersInRoleAsync(_lookupNormalizer.NormalizeName("moderator")); + var user = await _identityUserStore.GetUsersInRoleAsync(_lookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); user.ShouldNotBeNull(); user.ShouldContain(x => x.UserName == "john.nash"); } @@ -643,15 +643,15 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetTokenAsync(user, "test-provider", "test-name", "123123"); + await _identityUserStore.SetTokenAsync(user, "test-provider", "test-name", "123123").ConfigureAwait(false); user.Tokens.ShouldNotBeEmpty(); user.Tokens.ShouldContain(x => x.LoginProvider == "test-provider" && x.Name == "test-name" && x.Value == "123123"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -660,14 +660,14 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.RemoveTokenAsync(user, "test-provider", "test-name"); + await _identityUserStore.RemoveTokenAsync(user, "test-provider", "test-name").ConfigureAwait(false); user.Tokens.ShouldNotContain(x => x.LoginProvider == "test-provider" && x.Name == "test-name" && x.Value == "123123"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -676,12 +676,12 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - (await _identityUserStore.GetTokenAsync(user, "test-provider", "test-name")).ShouldBe("test-value"); + (await _identityUserStore.GetTokenAsync(user, "test-provider", "test-name").ConfigureAwait(false)).ShouldBe("test-value"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -690,14 +690,14 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetAuthenticatorKeyAsync(user, "testKey"); + await _identityUserStore.SetAuthenticatorKeyAsync(user, "testKey").ConfigureAwait(false); user.Tokens.ShouldContain(x => x.LoginProvider == "[AspNetUserStore]" && x.Name == "AuthenticatorKey" && x.Value == "testKey"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -706,13 +706,13 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetAuthenticatorKeyAsync(user, "testKey"); + await _identityUserStore.SetAuthenticatorKeyAsync(user, "testKey").ConfigureAwait(false); - (await _identityUserStore.GetAuthenticatorKeyAsync(user)).ShouldBe("testKey"); + (await _identityUserStore.GetAuthenticatorKeyAsync(user).ConfigureAwait(false)).ShouldBe("testKey"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -722,13 +722,13 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetTokenAsync(user, "[AspNetUserStore]", "RecoveryCodes", "testKey;testKey2"); + await _identityUserStore.SetTokenAsync(user, "[AspNetUserStore]", "RecoveryCodes", "testKey;testKey2").ConfigureAwait(false); - (await _identityUserStore.CountCodesAsync(user)).ShouldBe(2); + (await _identityUserStore.CountCodesAsync(user).ConfigureAwait(false)).ShouldBe(2); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -737,18 +737,18 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); await _identityUserStore.ReplaceCodesAsync(user, new List() { "testKey", "testKey2" - }); + }).ConfigureAwait(false); user.Tokens.ShouldContain(x => x.LoginProvider == "[AspNetUserStore]" && x.Name == "RecoveryCodes" && x.Value == "testKey;testKey2"); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -757,13 +757,13 @@ namespace Volo.Abp.Identity { using (var uow = _unitOfWorkManager.Begin()) { - var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")); + var user = await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); user.ShouldNotBeNull(); - await _identityUserStore.SetTokenAsync(user, "[AspNetUserStore]", "RecoveryCodes", "testKey;testKey2"); + await _identityUserStore.SetTokenAsync(user, "[AspNetUserStore]", "RecoveryCodes", "testKey;testKey2").ConfigureAwait(false); - (await _identityUserStore.RedeemCodeAsync(user, "testKey")).ShouldBeTrue(); + (await _identityUserStore.RedeemCodeAsync(user, "testKey").ConfigureAwait(false)).ShouldBeTrue(); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs index 621cb4621f..a098ba92c6 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs @@ -24,19 +24,19 @@ namespace Volo.Abp.Identity public async Task Roles_Should_Have_Configured_Permissions() { //admin - var grantInfos = await _permissionManager.GetAllForRoleAsync("admin"); + var grantInfos = await _permissionManager.GetAllForRoleAsync("admin").ConfigureAwait(false); RoleShouldHavePermission(grantInfos, "admin", TestPermissionNames.MyPermission1); RoleShouldHavePermission(grantInfos, "admin", TestPermissionNames.MyPermission2); RoleShouldHavePermission(grantInfos, "admin", TestPermissionNames.MyPermission2_ChildPermission1); //moderator - grantInfos = await _permissionManager.GetAllForRoleAsync("moderator"); + grantInfos = await _permissionManager.GetAllForRoleAsync("moderator").ConfigureAwait(false); RoleShouldHavePermission(grantInfos, "moderator", TestPermissionNames.MyPermission1); RoleShouldHavePermission(grantInfos, "moderator", TestPermissionNames.MyPermission2); ShouldNotHavePermission(grantInfos, TestPermissionNames.MyPermission2_ChildPermission1); //supporter - grantInfos = await _permissionManager.GetAllForRoleAsync("supporter"); + grantInfos = await _permissionManager.GetAllForRoleAsync("supporter").ConfigureAwait(false); RoleShouldHavePermission(grantInfos, "supporter", TestPermissionNames.MyPermission1); ShouldNotHavePermission(grantInfos, TestPermissionNames.MyPermission2); ShouldNotHavePermission(grantInfos, TestPermissionNames.MyPermission2_ChildPermission1); @@ -45,21 +45,21 @@ namespace Volo.Abp.Identity [Fact] public async Task Should_Grant_Permission_To_Role() { - (await _permissionManager.GetForRoleAsync("supporter", TestPermissionNames.MyPermission2)).IsGranted.ShouldBeFalse(); - (await _permissionStore.IsGrantedAsync(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "supporter")).ShouldBeFalse(); + (await _permissionManager.GetForRoleAsync("supporter", TestPermissionNames.MyPermission2).ConfigureAwait(false)).IsGranted.ShouldBeFalse(); + (await _permissionStore.IsGrantedAsync(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "supporter").ConfigureAwait(false)).ShouldBeFalse(); - await _permissionManager.SetForRoleAsync("supporter", TestPermissionNames.MyPermission2, true); + await _permissionManager.SetForRoleAsync("supporter", TestPermissionNames.MyPermission2, true).ConfigureAwait(false); - (await _permissionManager.GetForRoleAsync("supporter", TestPermissionNames.MyPermission2)).IsGranted.ShouldBeTrue(); - (await _permissionStore.IsGrantedAsync(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "supporter")).ShouldBeTrue(); + (await _permissionManager.GetForRoleAsync("supporter", TestPermissionNames.MyPermission2).ConfigureAwait(false)).IsGranted.ShouldBeTrue(); + (await _permissionStore.IsGrantedAsync(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "supporter").ConfigureAwait(false)).ShouldBeTrue(); } [Fact] public async Task Should_Revoke_Permission_From_Role() { - (await _permissionManager.GetForRoleAsync("moderator", TestPermissionNames.MyPermission1)).IsGranted.ShouldBeTrue(); - await _permissionManager.SetForRoleAsync("moderator", TestPermissionNames.MyPermission1, false); - (await _permissionManager.GetForRoleAsync("moderator", TestPermissionNames.MyPermission1)).IsGranted.ShouldBeFalse(); + (await _permissionManager.GetForRoleAsync("moderator", TestPermissionNames.MyPermission1).ConfigureAwait(false)).IsGranted.ShouldBeTrue(); + await _permissionManager.SetForRoleAsync("moderator", TestPermissionNames.MyPermission1, false).ConfigureAwait(false); + (await _permissionManager.GetForRoleAsync("moderator", TestPermissionNames.MyPermission1).ConfigureAwait(false)).IsGranted.ShouldBeFalse(); } [Fact] @@ -67,21 +67,21 @@ namespace Volo.Abp.Identity { //administrator var user = GetUser("administrator"); - var grantInfos = await _permissionManager.GetAllForUserAsync(user.Id); + var grantInfos = await _permissionManager.GetAllForUserAsync(user.Id).ConfigureAwait(false); UserShouldHavePermission(grantInfos, user.Id, TestPermissionNames.MyPermission1, "admin"); UserShouldHavePermission(grantInfos, user.Id, TestPermissionNames.MyPermission2, "admin"); UserShouldHavePermission(grantInfos, user.Id, TestPermissionNames.MyPermission2_ChildPermission1, "admin"); //john.nash user = GetUser("john.nash"); - grantInfos = await _permissionManager.GetAllForUserAsync(user.Id); + grantInfos = await _permissionManager.GetAllForUserAsync(user.Id).ConfigureAwait(false); UserShouldHavePermission(grantInfos, user.Id, TestPermissionNames.MyPermission1, "moderator", "supporter"); UserShouldHavePermission(grantInfos, user.Id, TestPermissionNames.MyPermission2, "moderator"); ShouldNotHavePermission(grantInfos, TestPermissionNames.MyPermission2_ChildPermission1); //john.nash user = GetUser("david"); - grantInfos = await _permissionManager.GetAllForUserAsync(user.Id); + grantInfos = await _permissionManager.GetAllForUserAsync(user.Id).ConfigureAwait(false); UserShouldHavePermission(grantInfos, user.Id, TestPermissionNames.MyPermission1); ShouldNotHavePermission(grantInfos, TestPermissionNames.MyPermission2); ShouldNotHavePermission(grantInfos, TestPermissionNames.MyPermission2_ChildPermission1); diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RoleChangingEvents_Test.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RoleChangingEvents_Test.cs new file mode 100644 index 0000000000..1a4405c9e4 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RoleChangingEvents_Test.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.Identity; +using Shouldly; +using System.Threading.Tasks; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Guids; +using Volo.Abp.PermissionManagement; +using Volo.Abp.Uow; +using Xunit; + +namespace Volo.Abp.Identity +{ + public class RoleChangingEvents_Test : AbpIdentityDomainTestBase + { + protected readonly IIdentityRoleRepository RoleRepository; + protected readonly IPermissionGrantRepository PermissionGrantRepository; + protected readonly IdentityRoleManager RoleManager; + protected readonly ILookupNormalizer LookupNormalizer; + protected readonly IGuidGenerator GuidGenerator; + protected readonly IUnitOfWorkManager UowManager; + + public RoleChangingEvents_Test() + { + RoleRepository = GetRequiredService(); ; + PermissionGrantRepository = GetRequiredService(); ; + RoleManager = GetRequiredService(); ; + LookupNormalizer = GetRequiredService(); ; + GuidGenerator = GetRequiredService(); + UowManager = GetRequiredService(); + } + + [Fact] + public async Task Role_Update_Event_Test() + { + var role = await RoleRepository + .FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator")) + .ConfigureAwait(false); + + var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name).ConfigureAwait(false); + permissionGrantsInRole.ShouldNotBeNull(); + permissionGrantsInRole.Count.ShouldBeGreaterThan(0); + var count = permissionGrantsInRole.Count; + + using (var uow = UowManager.Begin()) + { + var identityResult = await RoleManager.SetRoleNameAsync(role, "TestModerator").ConfigureAwait(false); + identityResult.Succeeded.ShouldBeTrue(); + var xx = await RoleRepository.UpdateAsync(role).ConfigureAwait(false); + await uow.CompleteAsync().ConfigureAwait(false); + } + + role = await RoleRepository.GetAsync(role.Id).ConfigureAwait(false); + role.Name.ShouldBe("TestModerator"); + + permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name).ConfigureAwait(false); + permissionGrantsInRole.Count.ShouldBe(count); + } + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestPermissionDataBuilder.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestPermissionDataBuilder.cs index b84860a5cc..c53592d567 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestPermissionDataBuilder.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestPermissionDataBuilder.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Identity; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; @@ -26,40 +27,40 @@ namespace Volo.Abp.Identity _lookupNormalizer = lookupNormalizer; } - public void Build() + public async Task Build() { - AddRolePermissions(); - AddUserPermissions(); + await AddRolePermissions().ConfigureAwait(false); + await AddUserPermissions().ConfigureAwait(false); } - private void AddRolePermissions() + private async Task AddRolePermissions() { - AddPermission(TestPermissionNames.MyPermission1, RolePermissionValueProvider.ProviderName, "admin"); - AddPermission(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "admin"); - AddPermission(TestPermissionNames.MyPermission2_ChildPermission1, RolePermissionValueProvider.ProviderName, "admin"); + await AddPermission(TestPermissionNames.MyPermission1, RolePermissionValueProvider.ProviderName, "admin").ConfigureAwait(false); + await AddPermission(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "admin").ConfigureAwait(false); + await AddPermission(TestPermissionNames.MyPermission2_ChildPermission1, RolePermissionValueProvider.ProviderName, "admin").ConfigureAwait(false); - AddPermission(TestPermissionNames.MyPermission1, RolePermissionValueProvider.ProviderName, "moderator"); - AddPermission(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "moderator"); + await AddPermission(TestPermissionNames.MyPermission1, RolePermissionValueProvider.ProviderName, "moderator").ConfigureAwait(false); + await AddPermission(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "moderator").ConfigureAwait(false); - AddPermission(TestPermissionNames.MyPermission1, RolePermissionValueProvider.ProviderName, "supporter"); + await AddPermission(TestPermissionNames.MyPermission1, RolePermissionValueProvider.ProviderName, "supporter").ConfigureAwait(false); } - private void AddUserPermissions() + private async Task AddUserPermissions() { var david = AsyncHelper.RunSync(() => _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("david"))); - AddPermission(TestPermissionNames.MyPermission1, UserPermissionValueProvider.ProviderName, david.Id.ToString()); + await AddPermission(TestPermissionNames.MyPermission1, UserPermissionValueProvider.ProviderName, david.Id.ToString()).ConfigureAwait(false); } - private void AddPermission(string permissionName, string providerName, string providerKey) + private async Task AddPermission(string permissionName, string providerName, string providerKey) { - _permissionGrantRepository.Insert( + await _permissionGrantRepository.InsertAsync( new PermissionGrant( _guidGenerator.Create(), permissionName, providerName, providerKey ) - ); + ).ConfigureAwait(false); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs index ef06949500..a8f2159fc2 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.Identity [Fact] public async Task GetRolesAsync() { - var roleNames = await _userRoleFinder.GetRolesAsync(_testData.UserJohnId); + var roleNames = await _userRoleFinder.GetRolesAsync(_testData.UserJohnId).ConfigureAwait(false); roleNames.ShouldNotBeEmpty(); roleNames.ShouldContain(x => x == "moderator"); roleNames.ShouldContain(x => x == "supporter"); diff --git a/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo.Abp.Identity.EntityFrameworkCore.Tests.csproj b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo.Abp.Identity.EntityFrameworkCore.Tests.csproj index 988d327a6d..5e01379951 100644 --- a/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo.Abp.Identity.EntityFrameworkCore.Tests.csproj +++ b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo.Abp.Identity.EntityFrameworkCore.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo.Abp.Identity.MongoDB.Tests.csproj b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo.Abp.Identity.MongoDB.Tests.csproj index 8c70ffe772..22edeae68a 100644 --- a/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo.Abp.Identity.MongoDB.Tests.csproj +++ b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo.Abp.Identity.MongoDB.Tests.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo.Abp.Identity.TestBase.csproj b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo.Abp.Identity.TestBase.csproj index 306ee09327..de9dc07587 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo.Abp.Identity.TestBase.csproj +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo.Abp.Identity.TestBase.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBase.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBase.cs index b603612525..ac75b16b02 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBase.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.Identity { diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBaseModule.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBaseModule.cs index b52136a082..0c8c545b8c 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBaseModule.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestBaseModule.cs @@ -30,11 +30,13 @@ namespace Volo.Abp.Identity using (var scope = context.ServiceProvider.CreateScope()) { var dataSeeder = scope.ServiceProvider.GetRequiredService(); - AsyncHelper.RunSync(() => dataSeeder.SeedAsync()); - - scope.ServiceProvider - .GetRequiredService() - .Build(); + AsyncHelper.RunSync(async () => + { + await dataSeeder.SeedAsync().ConfigureAwait(false); + await scope.ServiceProvider + .GetRequiredService() + .Build().ConfigureAwait(false); + }); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs index ae6b7befc2..ad36fe69a7 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs @@ -1,8 +1,8 @@ using System.Security.Claims; +using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; -using Volo.Abp.Threading; namespace Volo.Abp.Identity { @@ -35,31 +35,31 @@ namespace Volo.Abp.Identity _testData = testData; } - public void Build() + public async Task Build() { - AddRoles(); - AddUsers(); - AddClaimTypes(); + await AddRoles().ConfigureAwait(false); + await AddUsers().ConfigureAwait(false); + await AddClaimTypes().ConfigureAwait(false); } - private void AddRoles() + private async Task AddRoles() { - _adminRole = AsyncHelper.RunSync(()=> _roleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("admin"))); + _adminRole = await _roleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("admin")).ConfigureAwait(false); _moderator = new IdentityRole(_testData.RoleModeratorId, "moderator"); _moderator.AddClaim(_guidGenerator, new Claim("test-claim", "test-value")); - _roleRepository.Insert(_moderator); + await _roleRepository.InsertAsync(_moderator).ConfigureAwait(false); _supporterRole = new IdentityRole(_guidGenerator.Create(), "supporter"); - _roleRepository.Insert(_supporterRole); + await _roleRepository.InsertAsync(_supporterRole).ConfigureAwait(false); } - private void AddUsers() + private async Task AddUsers() { var adminUser = new IdentityUser(_guidGenerator.Create(), "administrator", "admin@abp.io"); adminUser.AddRole(_adminRole.Id); adminUser.AddClaim(_guidGenerator, new Claim("TestClaimType", "42")); - _userRepository.Insert(adminUser); + await _userRepository.InsertAsync(adminUser).ConfigureAwait(false); var john = new IdentityUser(_testData.UserJohnId, "john.nash", "john.nash@abp.io"); john.AddRole(_moderator.Id); @@ -68,23 +68,23 @@ namespace Volo.Abp.Identity john.AddLogin(new UserLoginInfo("twitter", "johnx", "John Nash")); john.AddClaim(_guidGenerator, new Claim("TestClaimType", "42")); john.SetToken("test-provider", "test-name", "test-value"); - _userRepository.Insert(john); + await _userRepository.InsertAsync(john).ConfigureAwait(false); var david = new IdentityUser(_testData.UserDavidId, "david", "david@abp.io"); - _userRepository.Insert(david); + await _userRepository.InsertAsync(david).ConfigureAwait(false); var neo = new IdentityUser(_testData.UserNeoId, "neo", "neo@abp.io"); neo.AddRole(_supporterRole.Id); neo.AddClaim(_guidGenerator, new Claim("TestClaimType", "43")); - _userRepository.Insert(neo); + await _userRepository.InsertAsync(neo).ConfigureAwait(false); } - private void AddClaimTypes() + private async Task AddClaimTypes() { var ageClaim = new IdentityClaimType(_testData.AgeClaimId, "Age", false, false, null, null, null,IdentityClaimValueType.Int); - _identityClaimTypeRepository.Insert(ageClaim); + await _identityClaimTypeRepository.InsertAsync(ageClaim).ConfigureAwait(false); var educationClaim = new IdentityClaimType(_testData.EducationClaimId, "Education", true, false, null, null, null); - _identityClaimTypeRepository.Insert(educationClaim); + await _identityClaimTypeRepository.InsertAsync(educationClaim).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs index 3250c0b04a..afe117d421 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityClaimTypeRepository_Tests.cs @@ -28,11 +28,11 @@ namespace Volo.Abp.Identity { var claim = (await ClaimTypeRepository.GetListAsync()).FirstOrDefault(); - var result1 = await ClaimTypeRepository.AnyAsync(claim.Name); + var result1 = await ClaimTypeRepository.AnyAsync(claim.Name).ConfigureAwait(false); result1.ShouldBe(true); - var result2 = await ClaimTypeRepository.AnyAsync(Guid.NewGuid().ToString()); + var result2 = await ClaimTypeRepository.AnyAsync(Guid.NewGuid().ToString()).ConfigureAwait(false); result2.ShouldBe(false); } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityDataSeeder_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityDataSeeder_Tests.cs index 65eac5bc9d..0b6692f419 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityDataSeeder_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityDataSeeder_Tests.cs @@ -25,11 +25,11 @@ namespace Volo.Abp.Identity [Fact] public async Task Should_Create_Admin_User_And_Role() { - await _identityDataSeeder.SeedAsync("admin@abp.io", "1q2w3E*"); + await _identityDataSeeder.SeedAsync("admin@abp.io", "1q2w3E*").ConfigureAwait(false); - (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("admin"))).ShouldNotBeNull(); - (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("admin"))).Name.ShouldBe("admin"); - (await _roleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("admin"))).ShouldNotBeNull(); + (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("admin")).ConfigureAwait(false)).ShouldNotBeNull(); + (await _userRepository.FindByNormalizedUserNameAsync(_lookupNormalizer.NormalizeName("admin")).ConfigureAwait(false)).Name.ShouldBe("admin"); + (await _roleRepository.FindByNormalizedNameAsync(_lookupNormalizer.NormalizeName("admin")).ConfigureAwait(false)).ShouldNotBeNull(); } } } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityRoleRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityRoleRepository_Tests.cs index e4a15d15f1..cd7ee1eb32 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityRoleRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityRoleRepository_Tests.cs @@ -23,14 +23,14 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByNormalizedNameAsync() { - (await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("admin"))).ShouldNotBeNull(); - (await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("undefined-role"))).ShouldBeNull(); + (await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("admin")).ConfigureAwait(false)).ShouldNotBeNull(); + (await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("undefined-role")).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task GetListAsync() { - var roles = await RoleRepository.GetListAsync(); + var roles = await RoleRepository.GetListAsync().ConfigureAwait(false); roles.ShouldContain(r => r.Name == "admin"); roles.ShouldContain(r => r.Name == "moderator"); roles.ShouldContain(r => r.Name == "supporter"); @@ -39,13 +39,13 @@ namespace Volo.Abp.Identity [Fact] public async Task GetCountAsync() { - (await RoleRepository.GetCountAsync()).ShouldBeGreaterThan(0); + (await RoleRepository.GetCountAsync().ConfigureAwait(false)).ShouldBeGreaterThan(0); } [Fact] public async Task Should_Eager_Load_Role_Collections() { - var role = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator")); + var role = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator")).ConfigureAwait(false); role.Claims.ShouldNotBeNull(); role.Claims.Any().ShouldBeTrue(); } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs index dca811da0b..98f25f6aee 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserRepository_Tests.cs @@ -25,23 +25,23 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByNormalizedUserNameAsync() { - (await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash"))).ShouldNotBeNull(); - (await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("undefined-user"))).ShouldBeNull(); + (await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false)).ShouldNotBeNull(); + (await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("undefined-user")).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task FindByNormalizedEmailAsync() { - (await UserRepository.FindByNormalizedEmailAsync(LookupNormalizer.NormalizeEmail("john.nash@abp.io"))).ShouldNotBeNull(); - (await UserRepository.FindByNormalizedEmailAsync(LookupNormalizer.NormalizeEmail("david@abp.io"))).ShouldNotBeNull(); - (await UserRepository.FindByNormalizedEmailAsync(LookupNormalizer.NormalizeEmail("undefined-user@abp.io"))).ShouldBeNull(); + (await UserRepository.FindByNormalizedEmailAsync(LookupNormalizer.NormalizeEmail("john.nash@abp.io")).ConfigureAwait(false)).ShouldNotBeNull(); + (await UserRepository.FindByNormalizedEmailAsync(LookupNormalizer.NormalizeEmail("david@abp.io")).ConfigureAwait(false)).ShouldNotBeNull(); + (await UserRepository.FindByNormalizedEmailAsync(LookupNormalizer.NormalizeEmail("undefined-user@abp.io")).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task GetRoleNamesAsync() { - var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")); - var roles = await UserRepository.GetRoleNamesAsync(john.Id); + var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); + var roles = await UserRepository.GetRoleNamesAsync(john.Id).ConfigureAwait(false); roles.Count.ShouldBe(2); roles.ShouldContain("moderator"); roles.ShouldContain("supporter"); @@ -50,37 +50,37 @@ namespace Volo.Abp.Identity [Fact] public async Task FindByLoginAsync() { - var user = await UserRepository.FindByLoginAsync("github", "john"); + var user = await UserRepository.FindByLoginAsync("github", "john").ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("john.nash"); - user = await UserRepository.FindByLoginAsync("twitter", "johnx"); + user = await UserRepository.FindByLoginAsync("twitter", "johnx").ConfigureAwait(false); user.ShouldNotBeNull(); user.UserName.ShouldBe("john.nash"); - (await UserRepository.FindByLoginAsync("github", "undefinedid")).ShouldBeNull(); + (await UserRepository.FindByLoginAsync("github", "undefinedid").ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task GetListByClaimAsync() { - var users = await UserRepository.GetListByClaimAsync(new Claim("TestClaimType", "42")); + var users = await UserRepository.GetListByClaimAsync(new Claim("TestClaimType", "42")).ConfigureAwait(false); users.Count.ShouldBe(2); users.ShouldContain(u => u.UserName == "administrator"); users.ShouldContain(u => u.UserName == "john.nash"); - users = await UserRepository.GetListByClaimAsync(new Claim("TestClaimType", "43")); + users = await UserRepository.GetListByClaimAsync(new Claim("TestClaimType", "43")).ConfigureAwait(false); users.Count.ShouldBe(1); users.ShouldContain(u => u.UserName == "neo"); - users = await UserRepository.GetListByClaimAsync(new Claim("TestClaimType", "undefined")); + users = await UserRepository.GetListByClaimAsync(new Claim("TestClaimType", "undefined")).ConfigureAwait(false); users.Count.ShouldBe(0); } [Fact] public async Task GetListByNormalizedRoleNameAsync() { - var users = await UserRepository.GetListByNormalizedRoleNameAsync(LookupNormalizer.NormalizeName("supporter")); + var users = await UserRepository.GetListByNormalizedRoleNameAsync(LookupNormalizer.NormalizeName("supporter")).ConfigureAwait(false); users.Count.ShouldBe(2); users.ShouldContain(u => u.UserName == "john.nash"); users.ShouldContain(u => u.UserName == "neo"); @@ -89,7 +89,7 @@ namespace Volo.Abp.Identity [Fact] public async Task GetListAsync() { - var users = await UserRepository.GetListAsync("UserName DESC", 5, 0, "n"); + var users = await UserRepository.GetListAsync("UserName DESC", 5, 0, "n").ConfigureAwait(false); users.Count.ShouldBeGreaterThan(1); users.Count.ShouldBeLessThanOrEqualTo(5); @@ -107,15 +107,15 @@ namespace Volo.Abp.Identity ).ShouldBeGreaterThan(0); } - users = await UserRepository.GetListAsync(null, int.MaxValue, 0, "undefined-username"); + users = await UserRepository.GetListAsync(null, 999, 0, "undefined-username").ConfigureAwait(false); users.Count.ShouldBe(0); } [Fact] public async Task GetRolesAsync() { - var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")); - var roles = await UserRepository.GetRolesAsync(john.Id); + var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); + var roles = await UserRepository.GetRolesAsync(john.Id).ConfigureAwait(false); roles.Count.ShouldBe(2); roles.ShouldContain(r => r.Name == "moderator"); roles.ShouldContain(r => r.Name == "supporter"); @@ -124,14 +124,14 @@ namespace Volo.Abp.Identity [Fact] public async Task GetCountAsync() { - (await UserRepository.GetCountAsync("n")).ShouldBeGreaterThan(1); - (await UserRepository.GetCountAsync("undefined-username")).ShouldBe(0); + (await UserRepository.GetCountAsync("n").ConfigureAwait(false)).ShouldBeGreaterThan(1); + (await UserRepository.GetCountAsync("undefined-username").ConfigureAwait(false)).ShouldBe(0); } [Fact] public async Task Should_Eager_Load_User_Collections() { - var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")); + var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash")).ConfigureAwait(false); john.Roles.ShouldNotBeNull(); john.Roles.Any().ShouldBeTrue(); diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/LazyLoading_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/LazyLoading_Tests.cs index 1ae671dd4f..3313803436 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/LazyLoading_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/LazyLoading_Tests.cs @@ -28,11 +28,11 @@ namespace Volo.Abp.Identity { using (var uow = GetRequiredService().Begin()) { - var role = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator"), includeDetails: false); + var role = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator"), includeDetails: false).ConfigureAwait(false); role.Claims.ShouldNotBeNull(); role.Claims.Any().ShouldBeTrue(); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -41,7 +41,7 @@ namespace Volo.Abp.Identity { using (var uow = GetRequiredService().Begin()) { - var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash"), includeDetails: false); + var john = await UserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName("john.nash"), includeDetails: false).ConfigureAwait(false); john.Roles.ShouldNotBeNull(); john.Roles.Any().ShouldBeTrue(); @@ -55,7 +55,7 @@ namespace Volo.Abp.Identity john.Tokens.ShouldNotBeNull(); john.Tokens.Any().ShouldBeTrue(); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo.Abp.IdentityServer.Domain.Shared.csproj b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo.Abp.IdentityServer.Domain.Shared.csproj index bcd99cd524..71d99b826b 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo.Abp.IdentityServer.Domain.Shared.csproj +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo.Abp.IdentityServer.Domain.Shared.csproj @@ -22,7 +22,7 @@ - + diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/AbpIdentityServerDomainSharedModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/AbpIdentityServerDomainSharedModule.cs index 983ffcb071..d56968ba5d 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/AbpIdentityServerDomainSharedModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/AbpIdentityServerDomainSharedModule.cs @@ -1,14 +1,15 @@ using Volo.Abp.IdentityServer.Localization; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.IdentityServer { [DependsOn( - typeof(AbpLocalizationModule) + typeof(AbpValidationModule) )] public class AbpIdentityServerDomainSharedModule : AbpModule { diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json new file mode 100644 index 0000000000..5b30e44dad --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/cs.json @@ -0,0 +1,8 @@ +{ + "culture": "cs", + "texts": { + "Volo.IdentityServer:DuplicateIdentityResourceName": "Název Identity Resource již existuje: {Name}", + "Volo.IdentityServer:DuplicateApiResourceName": "Název Api Resource již existuje: {Name}", + "Volo.IdentityServer:DuplicateClientId": "ClientId již existuje: {ClientId}" + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/zh-Hant.json b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..859e8c29b7 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/zh-Hant.json @@ -0,0 +1,8 @@ +{ + "culture": "zh-Hant", + "texts": { + "Volo.IdentityServer:DuplicateIdentityResourceName": "Identity資源名稱已存在: {Name}", + "Volo.IdentityServer:DuplicateApiResourceName": "Api資源名稱已存在: {Name}", + "Volo.IdentityServer:DuplicateClientId": "ClientId已經存在: {ClientId}" + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo.Abp.IdentityServer.Domain.csproj b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo.Abp.IdentityServer.Domain.csproj index 798f2e360c..e7f4a6bc43 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo.Abp.IdentityServer.Domain.csproj +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo.Abp.IdentityServer.Domain.csproj @@ -20,11 +20,12 @@ + - - + + diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs index 9113051a4a..c445b7e90e 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.IdentityServer public async Task IsOriginAllowedAsync(string origin) { - var cacheItem = await Cache.GetOrAddAsync(AllowedCorsOriginsCacheItem.AllOrigins, CreateCacheItemAsync); + var cacheItem = await Cache.GetOrAddAsync(AllowedCorsOriginsCacheItem.AllOrigins, CreateCacheItemAsync).ConfigureAwait(false); var isAllowed = cacheItem.AllowedOrigins.Contains(origin, StringComparer.OrdinalIgnoreCase); @@ -49,7 +49,7 @@ namespace Volo.Abp.IdentityServer return new AllowedCorsOriginsCacheItem { - AllowedOrigins = (await clientRepository.GetAllDistinctAllowedCorsOriginsAsync()).ToArray() + AllowedOrigins = (await clientRepository.GetAllDistinctAllowedCorsOriginsAsync().ConfigureAwait(false)).ToArray() }; } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs index c89e7e74d2..0ff798e7fd 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs @@ -1,11 +1,13 @@ -using System.Security.Cryptography.X509Certificates; -using IdentityServer4.Services; +using IdentityServer4.Services; using IdentityServer4.Stores; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; using Volo.Abp.AutoMapper; +using Volo.Abp.BackgroundWorkers; using Volo.Abp.Caching; using Volo.Abp.Identity; -using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Tokens; using Volo.Abp.Modularity; using Volo.Abp.Security; using Volo.Abp.Validation; @@ -18,7 +20,8 @@ namespace Volo.Abp.IdentityServer typeof(AbpIdentityDomainModule), typeof(AbpSecurityModule), typeof(AbpCachingModule), - typeof(AbpValidationModule) + typeof(AbpValidationModule), + typeof(AbpBackgroundWorkersModule) )] public class AbpIdentityServerDomainModule : AbpModule { @@ -28,12 +31,12 @@ namespace Volo.Abp.IdentityServer Configure(options => { - options.AddProfile(validate: true); + options.AddProfile(validate: true); }); AddIdentityServer(context.Services); } - + private static void AddIdentityServer(IServiceCollection services) { var configuration = services.GetConfiguration(); @@ -58,7 +61,12 @@ namespace Volo.Abp.IdentityServer if (!services.IsAdded()) { - identityServerBuilder.AddInMemoryPersistedGrants(); + services.TryAddSingleton(); + } + + if (!services.IsAdded()) + { + services.TryAddSingleton(); } if (!services.IsAdded()) @@ -72,5 +80,19 @@ namespace Volo.Abp.IdentityServer identityServerBuilder.AddInMemoryIdentityResources(configuration.GetSection("IdentityServer:IdentityResources")); } } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var options = context.ServiceProvider.GetRequiredService>().Value; + if (options.IsCleanupEnabled) + { + context.ServiceProvider + .GetRequiredService() + .Add( + context.ServiceProvider + .GetRequiredService() + ); + } + } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItemInvalidator.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItemInvalidator.cs index 80bc425d5c..0a05e1781e 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItemInvalidator.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItemInvalidator.cs @@ -21,12 +21,12 @@ namespace Volo.Abp.IdentityServer public async Task HandleEventAsync(EntityChangedEventData eventData) { - await Cache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins); + await Cache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins).ConfigureAwait(false); } public async Task HandleEventAsync(EntityChangedEventData eventData) { - await Cache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins); + await Cache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpProfileService.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpProfileService.cs index f3bca6dba9..93a1fb5bbe 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpProfileService.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpProfileService.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity { using (_currentTenant.Change(context.Subject.FindTenantId())) { - await base.GetProfileDataAsync(context); + await base.GetProfileDataAsync(context).ConfigureAwait(false); } } @@ -37,7 +37,7 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity { using (_currentTenant.Change(context.Subject.FindTenantId())) { - await base.IsActiveAsync(context); + await base.IsActiveAsync(context).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs index f427d9edf1..86f704c27a 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs @@ -43,22 +43,22 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity [UnitOfWork] public virtual async Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { - await ReplaceEmailToUsernameOfInputIfNeeds(context); + await ReplaceEmailToUsernameOfInputIfNeeds(context).ConfigureAwait(false); - var user = await _userManager.FindByNameAsync(context.UserName); + var user = await _userManager.FindByNameAsync(context.UserName).ConfigureAwait(false); if (user != null) { - var result = await _signInManager.CheckPasswordSignInAsync(user, context.Password, true); + var result = await _signInManager.CheckPasswordSignInAsync(user, context.Password, true).ConfigureAwait(false); if (result.Succeeded) { - var sub = await _userManager.GetUserIdAsync(user); + var sub = await _userManager.GetUserIdAsync(user).ConfigureAwait(false); _logger.LogInformation("Credentials validated for username: {username}", context.UserName); - await _events.RaiseAsync(new UserLoginSuccessEvent(context.UserName, sub, context.UserName, interactive: false)); + await _events.RaiseAsync(new UserLoginSuccessEvent(context.UserName, sub, context.UserName, interactive: false)).ConfigureAwait(false); var additionalClaims = new List(); - await AddCustomClaimsAsync(additionalClaims, user, context); + await AddCustomClaimsAsync(additionalClaims, user, context).ConfigureAwait(false); context.Result = new GrantValidationResult( sub, @@ -71,23 +71,23 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity else if (result.IsLockedOut) { _logger.LogInformation("Authentication failed for username: {username}, reason: locked out", context.UserName); - await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "locked out", interactive: false)); + await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "locked out", interactive: false)).ConfigureAwait(false); } else if (result.IsNotAllowed) { _logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", context.UserName); - await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "not allowed", interactive: false)); + await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "not allowed", interactive: false)).ConfigureAwait(false); } else { _logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", context.UserName); - await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "invalid credentials", interactive: false)); + await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "invalid credentials", interactive: false)).ConfigureAwait(false); } } else { _logger.LogInformation("No user found matching username: {username}", context.UserName); - await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "invalid username", interactive: false)); + await _events.RaiseAsync(new UserLoginFailureEvent(context.UserName, "invalid username", interactive: false)).ConfigureAwait(false); } context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant); @@ -95,18 +95,18 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity protected virtual async Task ReplaceEmailToUsernameOfInputIfNeeds(ResourceOwnerPasswordValidationContext context) { - if (!ValidationHandler.IsValidEmailAddress(context.UserName)) + if (!ValidationHelper.IsValidEmailAddress(context.UserName)) { return; } - var userByUsername = await _userManager.FindByNameAsync(context.UserName); + var userByUsername = await _userManager.FindByNameAsync(context.UserName).ConfigureAwait(false); if (userByUsername != null) { return; } - var userByEmail = await _userManager.FindByEmailAsync(context.UserName); + var userByEmail = await _userManager.FindByEmailAsync(context.UserName).ConfigureAwait(false); if (userByEmail == null) { return; diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/Client.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/Client.cs index 031aa86bfc..b7a53ad66f 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/Client.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/Client.cs @@ -108,10 +108,10 @@ namespace Volo.Abp.IdentityServer.Clients } public Client(Guid id, [NotNull] string clientId) + : base(id) { Check.NotNull(clientId, nameof(clientId)); - Id = id; ClientId = clientId; //TODO: Replace magics with constants? diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs index 0e88b658cd..8ba8aea7e3 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.IdentityServer.Clients public virtual async Task FindClientByIdAsync(string clientId) { - var client = await _clientRepository.FindByCliendIdAsync(clientId); + var client = await _clientRepository.FindByCliendIdAsync(clientId).ConfigureAwait(false); return _objectMapper.Map(client); } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowCodes.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowCodes.cs new file mode 100644 index 0000000000..8814519cd4 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowCodes.cs @@ -0,0 +1,31 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Volo.Abp.IdentityServer.Devices +{ + public class DeviceFlowCodes : CreationAuditedAggregateRoot + { + public virtual string DeviceCode { get; set; } + + public virtual string UserCode { get; set; } + + public virtual string SubjectId { get; set; } + + public virtual string ClientId { get; set; } + + public virtual DateTime? Expiration { get; set; } + + public virtual string Data { get; set; } + + private DeviceFlowCodes() + { + + } + + public DeviceFlowCodes(Guid id) + : base(id) + { + + } + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs new file mode 100644 index 0000000000..4bd55ab2c6 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs @@ -0,0 +1,143 @@ +using System; +using System.Threading.Tasks; +using IdentityModel; +using IdentityServer4.Models; +using IdentityServer4.Stores; +using IdentityServer4.Stores.Serialization; +using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; + +namespace Volo.Abp.IdentityServer.Devices +{ + public class DeviceFlowStore : IDeviceFlowStore, ITransientDependency + { + protected IDeviceFlowCodesRepository DeviceFlowCodesRepository { get; } + protected IGuidGenerator GuidGenerator { get; } + protected IPersistentGrantSerializer PersistentGrantSerializer { get; } + + public DeviceFlowStore( + IDeviceFlowCodesRepository deviceFlowCodesRepository, + IGuidGenerator guidGenerator, + IPersistentGrantSerializer persistentGrantSerializer) + { + DeviceFlowCodesRepository = deviceFlowCodesRepository; + GuidGenerator = guidGenerator; + PersistentGrantSerializer = persistentGrantSerializer; + } + + public async Task StoreDeviceAuthorizationAsync(string deviceCode, string userCode, DeviceCode data) + { + Check.NotNull(deviceCode, nameof(deviceCode)); + Check.NotNull(userCode, nameof(userCode)); + Check.NotNull(data, nameof(data)); + + await DeviceFlowCodesRepository + .InsertAsync( + new DeviceFlowCodes(GuidGenerator.Create()) + { + DeviceCode = deviceCode, + UserCode = userCode, + ClientId = data.ClientId, + SubjectId = data.Subject?.FindFirst(JwtClaimTypes.Subject).Value, + CreationTime = data.CreationTime, + Expiration = data.CreationTime.AddSeconds(data.Lifetime), + Data = Serialize(data) + } + ).ConfigureAwait(false); + } + + public async Task FindByUserCodeAsync(string userCode) + { + Check.NotNull(userCode, nameof(userCode)); + + var deviceCodes = await DeviceFlowCodesRepository + .FindByUserCodeAsync(userCode) + .ConfigureAwait(false); + + if (deviceCodes == null) + { + return null; + } + + return DeserializeToDeviceCode(deviceCodes.Data); + } + + public async Task FindByDeviceCodeAsync(string deviceCode) + { + Check.NotNull(deviceCode, nameof(deviceCode)); + + var deviceCodes = await DeviceFlowCodesRepository + .FindByDeviceCodeAsync(deviceCode) + .ConfigureAwait(false); + + if (deviceCodes == null) + { + return null; + } + + return DeserializeToDeviceCode(deviceCodes.Data); + } + + public async Task UpdateByUserCodeAsync(string userCode, DeviceCode data) + { + Check.NotNull(userCode, nameof(userCode)); + Check.NotNull(data, nameof(data)); + + + var deviceCodes = await DeviceFlowCodesRepository + .FindByUserCodeAsync(userCode) + .ConfigureAwait(false); + + if (deviceCodes == null) + { + throw new InvalidOperationException($"Could not update device code by the given userCode: {userCode}"); + } + + deviceCodes.SubjectId = data.Subject?.FindFirst(JwtClaimTypes.Subject).Value; + deviceCodes.Data = Serialize(data); + + await DeviceFlowCodesRepository + .UpdateAsync(deviceCodes, autoSave: true) + .ConfigureAwait(false); + } + + public async Task RemoveByDeviceCodeAsync(string deviceCode) + { + Check.NotNull(deviceCode, nameof(deviceCode)); + + var deviceCodes = await DeviceFlowCodesRepository + .FindByDeviceCodeAsync(deviceCode) + .ConfigureAwait(false); + + if (deviceCodes == null) + { + return; + } + + await DeviceFlowCodesRepository + .DeleteAsync(deviceCodes, autoSave: true) + .ConfigureAwait(false); + } + + private string Serialize([CanBeNull] DeviceCode deviceCode) + { + if (deviceCode == null) + { + return null; + } + + return PersistentGrantSerializer.Serialize(deviceCode); + } + + protected virtual DeviceCode DeserializeToDeviceCode([CanBeNull] string data) + { + if (data == null) + { + return null; + } + + return PersistentGrantSerializer.Deserialize(data); + } + } +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/IDeviceFlowCodesRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/IDeviceFlowCodesRepository.cs new file mode 100644 index 0000000000..b6bcb69bed --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/IDeviceFlowCodesRepository.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.IdentityServer.Devices +{ + public interface IDeviceFlowCodesRepository : IBasicRepository + { + Task FindByUserCodeAsync( + string userCode, + CancellationToken cancellationToken = default + ); + + Task FindByDeviceCodeAsync( + string deviceCode, + CancellationToken cancellationToken = default + ); + + Task> GetListByExpirationAsync( + DateTime maxExpirationDate, + int maxResultCount, + CancellationToken cancellationToken = default + ); + } +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/IPersistentGrantRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/IPersistentGrantRepository.cs index 6e316806b6..65cfabd7e7 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/IPersistentGrantRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/IPersistentGrantRepository.cs @@ -18,6 +18,12 @@ namespace Volo.Abp.IdentityServer.Grants CancellationToken cancellationToken = default ); + Task> GetListByExpirationAsync( + DateTime maxExpirationDate, + int maxResultCount, + CancellationToken cancellationToken = default + ); + Task DeleteAsync( string subjectId, string clientId, diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrantStore.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrantStore.cs index 5ff3831e0e..9cf855e105 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrantStore.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Grants/PersistedGrantStore.cs @@ -24,51 +24,51 @@ namespace Volo.Abp.IdentityServer.Grants public virtual async Task StoreAsync(IdentityServer4.Models.PersistedGrant grant) { - var entity = await _persistentGrantRepository.FindByKeyAsync(grant.Key); + var entity = await _persistentGrantRepository.FindByKeyAsync(grant.Key).ConfigureAwait(false); if (entity == null) { entity = _objectMapper.Map(grant); EntityHelper.TrySetId(entity, () => _guidGenerator.Create()); - await _persistentGrantRepository.InsertAsync(entity); + await _persistentGrantRepository.InsertAsync(entity).ConfigureAwait(false); } else { _objectMapper.Map(grant, entity); - await _persistentGrantRepository.UpdateAsync(entity); + await _persistentGrantRepository.UpdateAsync(entity).ConfigureAwait(false); } } public virtual async Task GetAsync(string key) { - var persistedGrant = await _persistentGrantRepository.FindByKeyAsync(key); + var persistedGrant = await _persistentGrantRepository.FindByKeyAsync(key).ConfigureAwait(false); return _objectMapper.Map(persistedGrant); } public virtual async Task> GetAllAsync(string subjectId) { - var persistedGrants = await _persistentGrantRepository.GetListBySubjectIdAsync(subjectId); + var persistedGrants = await _persistentGrantRepository.GetListBySubjectIdAsync(subjectId).ConfigureAwait(false); return persistedGrants.Select(x => _objectMapper.Map(x)); } public virtual async Task RemoveAsync(string key) { - var persistedGrant = await _persistentGrantRepository.FindByKeyAsync(key); + var persistedGrant = await _persistentGrantRepository.FindByKeyAsync(key).ConfigureAwait(false); if (persistedGrant == null) { return; } - await _persistentGrantRepository.DeleteAsync(persistedGrant); + await _persistentGrantRepository.DeleteAsync(persistedGrant).ConfigureAwait(false); } public virtual async Task RemoveAllAsync(string subjectId, string clientId) { - await _persistentGrantRepository.DeleteAsync(subjectId, clientId); + await _persistentGrantRepository.DeleteAsync(subjectId, clientId).ConfigureAwait(false); } public virtual async Task RemoveAllAsync(string subjectId, string clientId, string type) { - await _persistentGrantRepository.DeleteAsync(subjectId, clientId, type); + await _persistentGrantRepository.DeleteAsync(subjectId, clientId, type).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceDataSeeder.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceDataSeeder.cs index 024f8bea13..8c828b970c 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceDataSeeder.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceDataSeeder.cs @@ -37,16 +37,16 @@ namespace Volo.Abp.IdentityServer.IdentityResources { foreach (var claimType in resource.UserClaims) { - await AddClaimTypeIfNotExistsAsync(claimType); + await AddClaimTypeIfNotExistsAsync(claimType).ConfigureAwait(false); } - await AddIdentityResourceIfNotExistsAsync(resource); + await AddIdentityResourceIfNotExistsAsync(resource).ConfigureAwait(false); } } protected virtual async Task AddIdentityResourceIfNotExistsAsync(IdentityServer4.Models.IdentityResource resource) { - if (await IdentityResourceRepository.CheckNameExistAsync(resource.Name)) + if (await IdentityResourceRepository.CheckNameExistAsync(resource.Name).ConfigureAwait(false)) { return; } @@ -56,12 +56,12 @@ namespace Volo.Abp.IdentityServer.IdentityResources GuidGenerator.Create(), resource ) - ); + ).ConfigureAwait(false); } protected virtual async Task AddClaimTypeIfNotExistsAsync(string claimType) { - if (await ClaimTypeRepository.AnyAsync(claimType)) + if (await ClaimTypeRepository.AnyAsync(claimType).ConfigureAwait(false)) { return; } @@ -72,7 +72,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources claimType, isStatic: true ) - ); + ).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientAutoMapperProfile.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerAutoMapperProfile.cs similarity index 94% rename from modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientAutoMapperProfile.cs rename to modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerAutoMapperProfile.cs index 81e5841d6b..ba1f44953c 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientAutoMapperProfile.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerAutoMapperProfile.cs @@ -2,14 +2,15 @@ using System.Security.Claims; using AutoMapper; using Volo.Abp.IdentityServer.ApiResources; +using Volo.Abp.IdentityServer.Clients; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; -namespace Volo.Abp.IdentityServer.Clients +namespace Volo.Abp.IdentityServer { - public class ClientAutoMapperProfile : Profile + public class IdentityServerAutoMapperProfile : Profile { - public ClientAutoMapperProfile() + public IdentityServerAutoMapperProfile() { //TODO: Reverse maps will not used probably. Remove those will not used diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerBuilderExtensions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerBuilderExtensions.cs index 2168b2067e..516d400db6 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerBuilderExtensions.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerBuilderExtensions.cs @@ -1,6 +1,7 @@ using IdentityServer4.Stores; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; namespace Volo.Abp.IdentityServer @@ -10,6 +11,7 @@ namespace Volo.Abp.IdentityServer public static IIdentityServerBuilder AddAbpStores(this IIdentityServerBuilder builder) { builder.Services.AddTransient(); + builder.Services.AddTransient(); return builder .AddClientStore() diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Jwt/JwtTokenMiddleware.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Jwt/JwtTokenMiddleware.cs index 57ca9cc4c2..58d3205dc2 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Jwt/JwtTokenMiddleware.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Jwt/JwtTokenMiddleware.cs @@ -13,14 +13,14 @@ namespace Volo.Abp.IdentityServer.Jwt { if (ctx.User.Identity?.IsAuthenticated != true) { - var result = await ctx.AuthenticateAsync(schema); + var result = await ctx.AuthenticateAsync(schema).ConfigureAwait(false); if (result.Succeeded && result.Principal != null) { ctx.User = result.Principal; } } - await next(); + await next().ConfigureAwait(false); }); } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs index 56275bb386..0b8b5016a7 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs @@ -29,26 +29,26 @@ namespace Volo.Abp.IdentityServer public virtual async Task> FindIdentityResourcesByScopeAsync(IEnumerable scopeNames) { - var resource = await _identityResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true); + var resource = await _identityResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true).ConfigureAwait(false); return _objectMapper.Map, List>(resource); } public virtual async Task> FindApiResourcesByScopeAsync(IEnumerable scopeNames) { - var resources = await _apiResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true); + var resources = await _apiResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true).ConfigureAwait(false); return resources.Select(x => _objectMapper.Map(x)); } public virtual async Task FindApiResourceAsync(string name) { - var resource = await _apiResourceRepository.FindByNameAsync(name); + var resource = await _apiResourceRepository.FindByNameAsync(name).ConfigureAwait(false); return _objectMapper.Map(resource); } public virtual async Task GetAllResourcesAsync() { - var identityResources = await _identityResourceRepository.GetListAsync(includeDetails: true); - var apiResources = await _apiResourceRepository.GetListAsync(includeDetails: true); + var identityResources = await _identityResourceRepository.GetListAsync(includeDetails: true).ConfigureAwait(false); + var apiResources = await _apiResourceRepository.GetListAsync(includeDetails: true).ConfigureAwait(false); return new Resources( _objectMapper.Map, IdentityServer4.Models.IdentityResource[]>(identityResources), diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs new file mode 100644 index 0000000000..4bec8318eb --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.BackgroundWorkers; +using Volo.Abp.Threading; + +namespace Volo.Abp.IdentityServer.Tokens +{ + public class TokenCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase + { + protected TokenCleanupOptions Options { get; } + + public TokenCleanupBackgroundWorker( + AbpTimer timer, + IServiceScopeFactory serviceScopeFactory, + IOptions options) + : base( + timer, + serviceScopeFactory) + { + Options = options.Value; + timer.Period = Options.CleanupPeriod; + } + + protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) + { + await workerContext + .ServiceProvider + .GetRequiredService() + .CleanAsync() + .ConfigureAwait(false); + } + } +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupOptions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupOptions.cs new file mode 100644 index 0000000000..816ef6af15 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupOptions.cs @@ -0,0 +1,34 @@ +using Volo.Abp.BackgroundWorkers; + +namespace Volo.Abp.IdentityServer.Tokens +{ + public class TokenCleanupOptions + { + /// + /// Default: 3,600,000 ms. + /// + public int CleanupPeriod { get; set; } = 3_600_000; + + /// + /// Default value: 100. + /// + public int CleanupBatchSize { get; set; } = 100; + + /// + /// The number of loop if there are + /// more than tokens in the database. + /// So, if is 10 and is 100, + /// then the cleanup worker will clean 1,000 items in one at max. + /// + /// Default value: 10. + /// + public int CleanupLoopCount { get; set; } = 10; + + /// + /// Default value: true. + /// If is false, + /// this property is ignored and the cleanup worker doesn't work for this application instance. + /// + public bool IsCleanupEnabled { get; set; } = true; + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupService.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupService.cs new file mode 100644 index 0000000000..ac38f792c1 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupService.cs @@ -0,0 +1,88 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.IdentityServer.Devices; +using Volo.Abp.IdentityServer.Grants; +using Volo.Abp.Timing; +using Volo.Abp.Uow; + +namespace Volo.Abp.IdentityServer.Tokens +{ + public class TokenCleanupService : ITransientDependency + { + protected IPersistentGrantRepository PersistentGrantRepository { get; } + protected IDeviceFlowCodesRepository DeviceFlowCodesRepository { get; } + protected IClock Clock { get; } + protected TokenCleanupOptions Options { get; } + + public TokenCleanupService( + IPersistentGrantRepository persistentGrantRepository, + IDeviceFlowCodesRepository deviceFlowCodesRepository, + IClock clock, + IOptions options) + { + PersistentGrantRepository = persistentGrantRepository; + DeviceFlowCodesRepository = deviceFlowCodesRepository; + Clock = clock; + Options = options.Value; + } + + public virtual async Task CleanAsync() + { + await RemoveGrantsAsync() + .ConfigureAwait(false); + + await RemoveDeviceCodesAsync() + .ConfigureAwait(false); + } + + [UnitOfWork] + protected virtual async Task RemoveGrantsAsync() + { + for (int i = 0; i < Options.CleanupLoopCount; i++) + { + var persistentGrants = await PersistentGrantRepository + .GetListByExpirationAsync(Clock.Now, Options.CleanupBatchSize) + .ConfigureAwait(false); + + //TODO: Can be optimized if the repository implements the batch deletion + foreach (var persistentGrant in persistentGrants) + { + await PersistentGrantRepository + .DeleteAsync(persistentGrant) + .ConfigureAwait(false); + } + + //No need to continue to query if it gets more than max items. + if (persistentGrants.Count < Options.CleanupBatchSize) + { + break; + } + } + } + + protected virtual async Task RemoveDeviceCodesAsync() + { + for (int i = 0; i < Options.CleanupLoopCount; i++) + { + var deviceFlowCodeses = await DeviceFlowCodesRepository + .GetListByExpirationAsync(Clock.Now, Options.CleanupBatchSize) + .ConfigureAwait(false); + + //TODO: Can be optimized if the repository implements the batch deletion + foreach (var deviceFlowCodes in deviceFlowCodeses) + { + await DeviceFlowCodesRepository + .DeleteAsync(deviceFlowCodes) + .ConfigureAwait(false); + } + + //No need to continue to query if it gets more than max items. + if (deviceFlowCodeses.Count < Options.CleanupBatchSize) + { + break; + } + } + } + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs index 5f7d6369af..ec038afac6 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.IdentityServer.ApiResources select apiResource; return await query - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListByScopesAsync( @@ -40,7 +40,7 @@ namespace Volo.Abp.IdentityServer.ApiResources where api.Scopes.Any(x => scopeNames.Contains(x.Name)) select api; - return await query.ToListAsync(GetCancellationToken(cancellationToken)); + return await query.ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, bool includeDetails = false, @@ -49,7 +49,7 @@ namespace Volo.Abp.IdentityServer.ApiResources return await DbSet .IncludeDetails(includeDetails).OrderBy(sorting ?? "name desc") .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync( @@ -58,12 +58,12 @@ namespace Volo.Abp.IdentityServer.ApiResources { return await DbSet .IncludeDetails(includeDetails) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(ar => ar.Id != expectedId && ar.Name == name, cancellationToken: cancellationToken); + return await DbSet.AnyAsync(ar => ar.Id != expectedId && ar.Name == name, cancellationToken: cancellationToken).ConfigureAwait(false); } public override async Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default) @@ -82,7 +82,7 @@ namespace Volo.Abp.IdentityServer.ApiResources DbContext.Set().Remove(scope); } - await base.DeleteAsync(id, autoSave, cancellationToken); + await base.DeleteAsync(id, autoSave, cancellationToken).ConfigureAwait(false); } public override IQueryable WithDetails() diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs index 44218470fd..4dc5134ff6 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.IdentityServer.Clients { return await DbSet .IncludeDetails(includeDetails) - .FirstOrDefaultAsync(x => x.ClientId == clientId, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(x => x.ClientId == clientId, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, bool includeDetails = false, @@ -34,7 +34,7 @@ namespace Volo.Abp.IdentityServer.Clients return await DbSet .IncludeDetails(includeDetails).OrderBy(sorting ?? nameof(Client.ClientName) + " desc") .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetAllDistinctAllowedCorsOriginsAsync(CancellationToken cancellationToken = default) @@ -42,12 +42,12 @@ namespace Volo.Abp.IdentityServer.Clients return await DbContext.ClientCorsOrigins .Select(x => x.Origin) .Distinct() - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task CheckClientIdExistAsync(string clientId, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); + return await DbSet.AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken).ConfigureAwait(false); } public override IQueryable WithDetails() diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs new file mode 100644 index 0000000000..a8d2bce3ce --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.IdentityServer.EntityFrameworkCore; + +namespace Volo.Abp.IdentityServer.Devices +{ + public class DeviceFlowCodesRepository : EfCoreRepository, + IDeviceFlowCodesRepository + { + public DeviceFlowCodesRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + + } + + public async Task FindByUserCodeAsync( + string userCode, + CancellationToken cancellationToken = default) + { + return await DbSet + .FirstOrDefaultAsync(d => d.UserCode == userCode, GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + + public async Task FindByDeviceCodeAsync( + string deviceCode, + CancellationToken cancellationToken = default) + { + return await DbSet + .FirstOrDefaultAsync(d => d.DeviceCode == deviceCode, GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + + public async Task> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount, + CancellationToken cancellationToken = default) + { + return await DbSet + .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) + .OrderBy(x => x.ClientId) + .Take(maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + } +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/AbpIdentityServerEntityFrameworkCoreModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/AbpIdentityServerEntityFrameworkCoreModule.cs index 74a4ce754f..a932cd3351 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/AbpIdentityServerEntityFrameworkCoreModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/AbpIdentityServerEntityFrameworkCoreModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.EntityFrameworkCore; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; using Volo.Abp.Modularity; @@ -34,6 +35,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs index 3c7f425dc9..52ba7c8e6c 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs @@ -3,6 +3,7 @@ using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; @@ -46,5 +47,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore DbSet ClientProperties { get; set; } DbSet PersistedGrants { get; set; } + + DbSet DeviceFlowCodes { get; set; } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContext.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContext.cs index 800aa8b8be..f63cd6bf1c 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContext.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContext.cs @@ -3,6 +3,7 @@ using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; @@ -47,6 +48,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore public DbSet PersistedGrants { get; set; } + public DbSet DeviceFlowCodes { get; set; } + public IdentityServerDbContext(DbContextOptions options) : base(options) { @@ -56,6 +59,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); + builder.ConfigureIdentityServer(); } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs index bd69f6948f..9f65e4e419 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.Modeling; +using Volo.Abp.EntityFrameworkCore.ValueComparers; +using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; @@ -202,10 +204,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore identityResource.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength); identityResource.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength); identityResource.Property(x => x.Properties) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ); + .HasConversion(new AbpJsonValueConverter>()) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); identityResource.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired(); }); @@ -229,10 +229,8 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore apiResource.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength); apiResource.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength); apiResource.Property(x => x.Properties) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ); + .HasConversion(new AbpJsonValueConverter>()) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); apiResource.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired(); apiResource.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired(); @@ -246,6 +244,7 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore apiSecret.HasKey(x => new { x.ApiResourceId, x.Type, x.Value }); apiSecret.Property(x => x.Type).HasMaxLength(SecretConsts.TypeMaxLength).IsRequired(); + apiSecret.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength); if (options.DatabaseProvider == EfCoreDatabaseProvider.MySql) { @@ -255,8 +254,6 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore { apiSecret.Property(x => x.Value).HasMaxLength(SecretConsts.ValueMaxLength).IsRequired(); } - - apiSecret.Property(x => x.Description).HasMaxLength(SecretConsts.DescriptionMaxLength); }); builder.Entity(apiClaim => @@ -290,6 +287,24 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore apiScopeClaim.Property(x => x.Type).HasMaxLength(UserClaimConsts.TypeMaxLength).IsRequired(); apiScopeClaim.Property(x => x.Name).HasMaxLength(ApiScopeConsts.NameMaxLength).IsRequired(); }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "DeviceFlowCodes", options.Schema); + + b.ConfigureByConvention(); + + b.Property(x => x.DeviceCode).HasMaxLength(200).IsRequired(); + b.Property(x => x.UserCode).HasMaxLength(200).IsRequired(); + b.Property(x => x.SubjectId).HasMaxLength(200); + b.Property(x => x.ClientId).HasMaxLength(200).IsRequired(); + b.Property(x => x.Expiration).IsRequired(); + b.Property(x => x.Data).HasMaxLength(50000).IsRequired(); + + b.HasIndex(x => new { x.UserCode }).IsUnique(); + b.HasIndex(x => x.DeviceCode).IsUnique(); + b.HasIndex(x => x.Expiration); + }); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs index 6f8b8fd4aa..cf208c7875 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs @@ -12,26 +12,42 @@ namespace Volo.Abp.IdentityServer.Grants { public class PersistentGrantRepository : EfCoreRepository, IPersistentGrantRepository { - public PersistentGrantRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + public PersistentGrantRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) { } - public Task FindByKeyAsync( + public async Task FindByKeyAsync( string key, CancellationToken cancellationToken = default) { - return DbSet - .FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken)); + return await DbSet + .FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); } - public Task> GetListBySubjectIdAsync( + public async Task> GetListBySubjectIdAsync( string subjectId, CancellationToken cancellationToken = default) { - return DbSet + return await DbSet .Where(x => x.SubjectId == subjectId) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + + public async Task> GetListByExpirationAsync( + DateTime maxExpirationDate, + int maxResultCount, + CancellationToken cancellationToken = default) + { + return await DbSet + .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) + .OrderBy(x => x.ClientId) + .Take(maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); } public async Task DeleteAsync( @@ -42,7 +58,7 @@ namespace Volo.Abp.IdentityServer.Grants await DeleteAsync( x => x.SubjectId == subjectId && x.ClientId == clientId, cancellationToken: GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); } public async Task DeleteAsync( @@ -54,7 +70,7 @@ namespace Volo.Abp.IdentityServer.Grants await DeleteAsync( x => x.SubjectId == subjectId && x.ClientId == clientId && x.Type == type, cancellationToken: GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs index 20789ecca8..d5d05c5e9a 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources where scopeNames.Contains(identityResource.Name) select identityResource; - return await query.ToListAsync(GetCancellationToken(cancellationToken)); + return await query.ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public override IQueryable WithDetails() @@ -43,7 +43,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources .IncludeDetails(includeDetails) .OrderBy(sorting ?? "name desc") .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task FindByNameAsync( @@ -54,12 +54,12 @@ namespace Volo.Abp.IdentityServer.IdentityResources return await DbSet .IncludeDetails(includeDetails) .Where(x => x.Name == name) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken); + return await DbSet.AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContext.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContext.cs index 16f99b9119..b4b5fe9b60 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContext.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContext.cs @@ -2,6 +2,7 @@ using Volo.Abp.Data; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.MongoDB; using IdentityResource = Volo.Abp.IdentityServer.IdentityResources.IdentityResource; @@ -19,6 +20,8 @@ namespace Volo.Abp.IdentityServer.MongoDB public IMongoCollection PersistedGrants => Collection(); + public IMongoCollection DeviceFlowCodes => Collection(); + protected override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder); diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContextExtensions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContextExtensions.cs index 474188a0e1..b6a20d842a 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContextExtensions.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbContextExtensions.cs @@ -1,6 +1,7 @@ using System; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; using Volo.Abp.MongoDB; @@ -39,6 +40,11 @@ namespace Volo.Abp.IdentityServer.MongoDB { b.CollectionName = options.CollectionPrefix + "PersistedGrants"; }); + + builder.Entity(b => + { + b.CollectionName = options.CollectionPrefix + "DeviceFlowCodes"; + }); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbModule.cs index 1076d19ecf..251378e087 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/AbpIdentityServerMongoDbModule.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.Modularity; using Volo.Abp.MongoDB; @@ -32,6 +33,7 @@ namespace Volo.Abp.IdentityServer.MongoDB options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/IAbpIdentityServerMongoDbContext.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/IAbpIdentityServerMongoDbContext.cs index cda4718896..3bb21a8198 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/IAbpIdentityServerMongoDbContext.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/IAbpIdentityServerMongoDbContext.cs @@ -1,6 +1,7 @@ using MongoDB.Driver; using Volo.Abp.Data; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; using Volo.Abp.MongoDB; @@ -18,5 +19,7 @@ namespace Volo.Abp.IdentityServer.MongoDB IMongoCollection IdentityResources { get; } IMongoCollection PersistedGrants { get; } + + IMongoCollection DeviceFlowCodes { get; } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs index e148bbe216..008d34f322 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs @@ -21,16 +21,16 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task FindByNameAsync(string name, bool includeDetails = true, CancellationToken cancellationToken = default) { return await GetMongoQueryable() - .Where(ar=>ar.Name == name) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .Where(ar => ar.Name == name) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListByScopesAsync(string[] scopeNames, bool includeDetails = false, CancellationToken cancellationToken = default) { return await GetMongoQueryable() - .Where(ar=>ar.Scopes.Any(x=> scopeNames.Contains(x.Name))) - .ToListAsync(GetCancellationToken(cancellationToken)); + .Where(ar => ar.Scopes.Any(x => scopeNames.Contains(x.Name))) + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, bool includeDetails = false, @@ -40,17 +40,17 @@ namespace Volo.Abp.IdentityServer.MongoDB .OrderBy(sorting ?? nameof(ApiResource.Name)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task GetTotalCount() { - return await GetCountAsync(); + return await GetCountAsync().ConfigureAwait(false); } public async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(ar => ar.Id != expectedId && ar.Name == name, cancellationToken: cancellationToken); + return await GetMongoQueryable().AnyAsync(ar => ar.Id != expectedId && ar.Name == name, cancellationToken: cancellationToken).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs index 61488edc3d..6e371717ba 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.IdentityServer.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().FirstOrDefaultAsync(x => x.ClientId == clientId, GetCancellationToken(cancellationToken)); + return await GetMongoQueryable().FirstOrDefaultAsync(x => x.ClientId == clientId, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync( @@ -40,7 +40,7 @@ namespace Volo.Abp.IdentityServer.MongoDB .OrderBy(sorting ?? nameof(Client.ClientName)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetAllDistinctAllowedCorsOriginsAsync( @@ -50,17 +50,17 @@ namespace Volo.Abp.IdentityServer.MongoDB .SelectMany(x => x.AllowedCorsOrigins) .Select(y => y.Origin) .Distinct() - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task CheckClientIdExistAsync(string clientId, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); + return await GetMongoQueryable().AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken).ConfigureAwait(false); } public virtual async Task GetTotalCount() { - return await GetCountAsync(); + return await GetCountAsync().ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs new file mode 100644 index 0000000000..86daac80a9 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.IdentityServer.Devices; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.IdentityServer.MongoDB +{ + public class MongoDeviceFlowCodesRepository : + MongoDbRepository, IDeviceFlowCodesRepository + { + public MongoDeviceFlowCodesRepository( + IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) + { + + } + + public async Task FindByUserCodeAsync( + string userCode, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable() + .FirstOrDefaultAsync(d => d.UserCode == userCode, GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + + public async Task FindByDeviceCodeAsync(string deviceCode, CancellationToken cancellationToken = default) + { + return await GetMongoQueryable() + .FirstOrDefaultAsync(d => d.DeviceCode == deviceCode, GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + + public async Task> GetListByExpirationAsync( + DateTime maxExpirationDate, + int maxResultCount, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable() + .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) + .OrderBy(x => x.ClientId) + .Take(maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs index d25faa9622..eefd4d325c 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.IdentityServer.MongoDB .OrderBy(sorting ?? nameof(IdentityResource.Name)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task FindByNameAsync( @@ -34,7 +34,7 @@ namespace Volo.Abp.IdentityServer.MongoDB { return await GetMongoQueryable() .Where(x => x.Name == name) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetListByScopesAsync(string[] scopeNames, bool includeDetails = false, @@ -42,17 +42,17 @@ namespace Volo.Abp.IdentityServer.MongoDB { return await GetMongoQueryable() .Where(ar => scopeNames.Contains(ar.Name)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task GetTotalCountAsync() { - return await GetCountAsync(); + return await GetCountAsync().ConfigureAwait(false); } public async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken); + return await GetMongoQueryable().AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken).ConfigureAwait(false); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs index 6a3248b9db..4b414482db 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs @@ -20,14 +20,26 @@ namespace Volo.Abp.IdentityServer.MongoDB { return await GetMongoQueryable() - .FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task> GetListBySubjectIdAsync(string subjectId, CancellationToken cancellationToken = default) { return await GetMongoQueryable() .Where(x => x.SubjectId == subjectId) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); + } + + public async Task> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable() + .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) + .OrderBy(x => x.ClientId) + .Take(maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)) + .ConfigureAwait(false); } public async Task DeleteAsync(string subjectId, string clientId, CancellationToken cancellationToken = default) @@ -35,7 +47,7 @@ namespace Volo.Abp.IdentityServer.MongoDB await DeleteAsync( x => x.SubjectId == subjectId && x.ClientId == clientId, cancellationToken: GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); } public async Task DeleteAsync(string subjectId, string clientId, string type, CancellationToken cancellationToken = default) @@ -43,7 +55,7 @@ namespace Volo.Abp.IdentityServer.MongoDB await DeleteAsync( x => x.SubjectId == subjectId && x.ClientId == clientId && x.Type == type, cancellationToken: GetCancellationToken(cancellationToken) - ); + ).ConfigureAwait(false); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo.Abp.IdentityServer.Domain.Tests.csproj b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo.Abp.IdentityServer.Domain.Tests.csproj index fa53edcd89..ce12bb92eb 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo.Abp.IdentityServer.Domain.Tests.csproj +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo.Abp.IdentityServer.Domain.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpIdentityServerDomainTestBase.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpIdentityServerDomainTestBase.cs index 009c6ca468..5b9c9240bf 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpIdentityServerDomainTestBase.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpIdentityServerDomainTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.IdentityServer +using Volo.Abp.Testing; + +namespace Volo.Abp.IdentityServer { public class AbpIdentityServerDomainTestBase : AbpIntegratedTest { diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/ClientStore_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/ClientStore_Tests.cs index e89f385b57..a5b1540a1b 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/ClientStore_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/ClientStore_Tests.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.IdentityServer.Clients [Fact] public async Task FindClientByIdAsync_Should_Return_Null_If_Not_Found() { - var client = await _clientStore.FindClientByIdAsync("non-existing-id"); + var client = await _clientStore.FindClientByIdAsync("non-existing-id").ConfigureAwait(false); client.ShouldBeNull(); } @@ -26,7 +26,7 @@ namespace Volo.Abp.IdentityServer.Clients public async Task FindClientByIdAsync_Should_Return_The_Client_If_Found() { //Act - var client = await _clientStore.FindClientByIdAsync("42"); + var client = await _clientStore.FindClientByIdAsync("42").ConfigureAwait(false); //Assert client.ShouldNotBeNull(); diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs index a313c2717f..9e7bdfc99a 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.IdentityServer.Clients public async Task FindApiResourceAsync_Should_Return_Null_If_Not_Found() { //Act - var resource = await _resourceStore.FindApiResourceAsync("non-existing-name"); + var resource = await _resourceStore.FindApiResourceAsync("non-existing-name").ConfigureAwait(false); //Assert resource.ShouldBeNull(); @@ -32,7 +32,7 @@ namespace Volo.Abp.IdentityServer.Clients public async Task FindApiResourceAsync_Should_Return_If_Found() { //Act - var apiResource = await _resourceStore.FindApiResourceAsync("Test-ApiResource-Name-1"); + var apiResource = await _resourceStore.FindApiResourceAsync("Test-ApiResource-Name-1").ConfigureAwait(false); //Assert apiResource.ShouldNotBe(null); @@ -48,7 +48,7 @@ namespace Volo.Abp.IdentityServer.Clients var apiResources = (await _resourceStore.FindApiResourcesByScopeAsync(new List { "Test-ApiResource-ApiScope-Name-1" - })).ToList(); + }).ConfigureAwait(false)).ToList(); //Assert apiResources.ShouldNotBe(null); @@ -63,7 +63,7 @@ namespace Volo.Abp.IdentityServer.Clients var identityResourcesByScope = await _resourceStore.FindIdentityResourcesByScopeAsync(new List { "Test-Identity-Resource-Name-1" - }); + }).ConfigureAwait(false); //Assert var resourcesByScope = identityResourcesByScope as IdentityResource[] ?? identityResourcesByScope.ToArray(); @@ -77,7 +77,7 @@ namespace Volo.Abp.IdentityServer.Clients public async Task GetAllResourcesAsync_Should_Return() { //Act - var resources = await _resourceStore.GetAllResourcesAsync(); + var resources = await _resourceStore.GetAllResourcesAsync().ConfigureAwait(false); //Assert resources.ShouldNotBe(null); diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/PersistentGrant_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/PersistentGrant_Tests.cs index 8e83f57c51..7df9936183 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/PersistentGrant_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Clients/PersistentGrant_Tests.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.IdentityServer.Clients [Fact] public async Task FindClientByIdAsync_Should_Return_Null_If_Not_Found() { - var persistentGrant = await _persistedGrantStore.GetAsync("not-existing-id"); + var persistentGrant = await _persistedGrantStore.GetAsync("not-existing-id").ConfigureAwait(false); persistentGrant.ShouldBeNull(); } @@ -29,7 +29,7 @@ namespace Volo.Abp.IdentityServer.Clients public async Task FindPersistentGrantByIdAsync_Should_Return_The_PersistentGrant_If_Found() { //Act - var client = await _persistedGrantStore.GetAsync("38"); + var client = await _persistedGrantStore.GetAsync("38").ConfigureAwait(false); //Assert client.ShouldNotBeNull(); @@ -52,10 +52,10 @@ namespace Volo.Abp.IdentityServer.Clients Data = "TestData-39", Expiration = new DateTime(2018, 1, 6, 21, 22, 23), CreationTime = new DateTime(2018, 1, 5, 19, 20, 21) - }); + }).ConfigureAwait(false); //Assert - var persistedGrant = await _persistedGrantStore.GetAsync("39"); + var persistedGrant = await _persistedGrantStore.GetAsync("39").ConfigureAwait(false); persistedGrant.Key.ShouldBe("39"); persistedGrant.ClientId.ShouldBe("TestClientId-39"); persistedGrant.Type.ShouldBe("TestType-39"); @@ -92,10 +92,10 @@ namespace Volo.Abp.IdentityServer.Clients Data = "TestData-PersistedGrantKey1", Expiration = new DateTime(2018, 1, 6, 21, 22, 23), CreationTime = new DateTime(2018, 1, 5, 19, 20, 21) - }); + }).ConfigureAwait(false); //Assert - var persistedGrant = await _persistedGrantStore.GetAsync("PersistedGrantKey1"); + var persistedGrant = await _persistedGrantStore.GetAsync("PersistedGrantKey1").ConfigureAwait(false); persistedGrant.Key.ShouldBe("PersistedGrantKey1"); persistedGrant.ClientId.ShouldBe("TestClientId-PersistedGrantKey1"); persistedGrant.Type.ShouldBe("TestType-PersistedGrantKey1"); @@ -122,7 +122,7 @@ namespace Volo.Abp.IdentityServer.Clients public async Task GetAllAsync_Should_Get_All_PersistedGrants_For_A_Given_SubjectId() { //Act - var persistentGrants = await _persistedGrantStore.GetAllAsync("TestSubject"); + var persistentGrants = await _persistedGrantStore.GetAllAsync("TestSubject").ConfigureAwait(false); //Assert var persistedGrants = persistentGrants as PersistedGrant[] ?? persistentGrants.ToArray(); @@ -142,13 +142,13 @@ namespace Volo.Abp.IdentityServer.Clients Type = "Type", ClientId = "ClientId", Data = "" - }); + }).ConfigureAwait(false); //Act - await _persistedGrantStore.RemoveAsync("#1P3R"); + await _persistedGrantStore.RemoveAsync("#1P3R").ConfigureAwait(false); //Assert - var persistedGrant = await _persistedGrantStore.GetAsync("#1P3R"); + var persistedGrant = await _persistedGrantStore.GetAsync("#1P3R").ConfigureAwait(false); persistedGrant.ShouldBe(null); } @@ -156,16 +156,16 @@ namespace Volo.Abp.IdentityServer.Clients public async Task RemoveAllAsync_Should_RemoveAll_PeristedGrants_For_A_Given_Subject_And_ClientId() { //Arrange - var persistedGrantsWithTestSubjectX = await _persistedGrantStore.GetAllAsync("TestSubject-X"); + var persistedGrantsWithTestSubjectX = await _persistedGrantStore.GetAllAsync("TestSubject-X").ConfigureAwait(false); var persistedGrantsWithTestSubjectXBeforeLength = persistedGrantsWithTestSubjectX.ToArray().Length; //Act - await _persistedGrantStore.RemoveAllAsync("TestSubject-X", "TestClientId-X"); + await _persistedGrantStore.RemoveAllAsync("TestSubject-X", "TestClientId-X").ConfigureAwait(false); //Assert persistedGrantsWithTestSubjectXBeforeLength.ShouldBe(2); - var persistedGrants = (await _persistedGrantStore.GetAllAsync("TestClientId-37")).ToArray(); + var persistedGrants = (await _persistedGrantStore.GetAllAsync("TestClientId-37").ConfigureAwait(false)).ToArray(); persistedGrants.ShouldNotBe(null); persistedGrants.Length.ShouldBe(0); } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/CorsPolicyService_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/CorsPolicyService_Tests.cs index af701cfc69..cdbea763c6 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/CorsPolicyService_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/CorsPolicyService_Tests.cs @@ -23,27 +23,27 @@ namespace Volo.Abp.IdentityServer [Fact] public async Task IsOriginAllowedAsync() { - (await _corsPolicyService.IsOriginAllowedAsync("https://client1-origin.com")).ShouldBeTrue(); - (await _corsPolicyService.IsOriginAllowedAsync("https://unknown-origin.com")).ShouldBeFalse(); + (await _corsPolicyService.IsOriginAllowedAsync("https://client1-origin.com").ConfigureAwait(false)).ShouldBeTrue(); + (await _corsPolicyService.IsOriginAllowedAsync("https://unknown-origin.com").ConfigureAwait(false)).ShouldBeFalse(); } [Fact] public async Task IsOriginAllowedAsync_Should_Invalidate_Cache_On_Update() { //It does not exists before - (await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com")).ShouldBeFalse(); + (await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com").ConfigureAwait(false)).ShouldBeFalse(); using (var uow = _unitOfWorkManager.Begin()) { - var client1 = await _clientRepository.FindByCliendIdAsync("ClientId1"); + var client1 = await _clientRepository.FindByCliendIdAsync("ClientId1").ConfigureAwait(false); client1.AddCorsOrigin("https://new-origin.com"); - await _clientRepository.UpdateAsync(client1); + await _clientRepository.UpdateAsync(client1).ConfigureAwait(false); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } //It does exists now - (await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com")).ShouldBeTrue(); + (await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com").ConfigureAwait(false)).ShouldBeTrue(); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Devices/DeviceFlowStore_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Devices/DeviceFlowStore_Tests.cs new file mode 100644 index 0000000000..7d4c630de7 --- /dev/null +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Devices/DeviceFlowStore_Tests.cs @@ -0,0 +1,95 @@ +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using IdentityModel; +using IdentityServer4.Models; +using IdentityServer4.Stores; +using Shouldly; +using Xunit; + +namespace Volo.Abp.IdentityServer.Devices +{ + public class DeviceFlowStore_Tests : AbpIdentityServerTestBase + { + private readonly IDeviceFlowStore _deviceFlowStore; + + public DeviceFlowStore_Tests() + { + _deviceFlowStore = GetRequiredService(); + } + + [Fact] + public async Task StoreDeviceAuthorizationAsync() + { + await _deviceFlowStore.StoreDeviceAuthorizationAsync( + "DeviceCode-Test1", + "UserCode-Test1", + new DeviceCode + { + ClientId = "ClientId1", + AuthorizedScopes = new string[] { "s1", "s2" }, + IsAuthorized = true, + Lifetime = 42, + RequestedScopes = new string[] { "rs1" }, + Subject = new ClaimsPrincipal( + new[] + { + new ClaimsIdentity(new[] + { + new Claim(JwtClaimTypes.Subject, "sid1") + }) + } + ) + } + ); + + void Check(DeviceCode deviceCode) + { + deviceCode.ClientId.ShouldBe("ClientId1"); + deviceCode.AuthorizedScopes.ShouldNotBeNull(); + deviceCode.AuthorizedScopes.Count().ShouldBe(2); + deviceCode.AuthorizedScopes.ShouldContain("s1"); + deviceCode.AuthorizedScopes.ShouldContain("s2"); + deviceCode.IsAuthorized.ShouldBeTrue(); + deviceCode.Lifetime.ShouldBe(42); + deviceCode.RequestedScopes.ShouldNotBeNull(); + deviceCode.RequestedScopes.Count().ShouldBe(1); + deviceCode.RequestedScopes.ShouldContain("rs1"); + deviceCode.Subject.ShouldNotBeNull(); + deviceCode.Subject.Claims.ShouldContain(x => x.Type == JwtClaimTypes.Subject && x.Value == "sid1"); + } + + Check(await _deviceFlowStore.FindByUserCodeAsync("UserCode-Test1")); + Check(await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode-Test1")); + } + + [Fact] + public async Task RemoveByDeviceCodeAsync() + { + (await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode1")).ShouldNotBeNull(); + + await _deviceFlowStore.RemoveByDeviceCodeAsync("DeviceCode1"); + + (await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode1")).ShouldBeNull(); + } + + [Fact] + public async Task UpdateByDeviceCodeAsync() + { + var deviceCode = await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode1"); + deviceCode.ShouldNotBeNull(); + deviceCode.Lifetime.ShouldBe(42); + + await _deviceFlowStore.UpdateByUserCodeAsync( + "DeviceFlowCodesUserCode1", + new DeviceCode + { + Lifetime = 43 + } + ); + + deviceCode = await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode1"); + deviceCode.Lifetime.ShouldBe(43); + } + } +} diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Tokens/TokenCleanupService_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Tokens/TokenCleanupService_Tests.cs new file mode 100644 index 0000000000..8de564cc23 --- /dev/null +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Tokens/TokenCleanupService_Tests.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.IdentityServer.Devices; +using Volo.Abp.IdentityServer.Grants; +using Xunit; + +namespace Volo.Abp.IdentityServer.Tokens +{ + public class TokenCleanupService_Tests : AbpIdentityServerTestBase + { + private readonly IPersistentGrantRepository _persistentGrantRepository; + private readonly IDeviceFlowCodesRepository _deviceFlowCodesRepository; + private readonly TokenCleanupService _tokenCleanupService; + + public TokenCleanupService_Tests() + { + _persistentGrantRepository = GetRequiredService(); + _deviceFlowCodesRepository = GetRequiredService(); + _tokenCleanupService = GetRequiredService(); + } + + [Fact] + public async Task Should_Clear_Expired_Tokens() + { + var persistentGrantCount = await _persistentGrantRepository.GetCountAsync(); + var deviceFlowCodesCount = await _deviceFlowCodesRepository.GetCountAsync(); + + await _tokenCleanupService.CleanAsync(); + + (await _persistentGrantRepository.GetCountAsync()) + .ShouldBe(persistentGrantCount - 1); + + (await _deviceFlowCodesRepository.GetCountAsync()) + .ShouldBe(deviceFlowCodesCount - 1); + } + } +} diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests.csproj b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests.csproj index 915709e8b7..4876a42c56 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests.csproj +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests.csproj @@ -18,7 +18,7 @@ - + diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityApplicationTestBase.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityApplicationTestBase.cs index b102a72329..f66709e5d1 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityApplicationTestBase.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityApplicationTestBase.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.IdentityServer +using Volo.Abp.Testing; + +namespace Volo.Abp.IdentityServer { public class AbpIdentityServerTestBase : AbpIntegratedTest { diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs index 2eef9ffc57..d7e0716151 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs @@ -1,4 +1,5 @@ -using IdentityServer4.Models; +using System.Threading.Tasks; +using IdentityServer4.Models; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.IdentityServer.ApiResources; @@ -12,7 +13,7 @@ using PersistedGrant = Volo.Abp.IdentityServer.Grants.PersistedGrant; namespace Volo.Abp.IdentityServer { - //TODO: There are two data builders (ses AbpIdentityServerTestDataBuilder in Volo.Abp.IdentityServer.TestBase). It should be somehow unified! + //TODO: There are two data builders (see AbpIdentityServerTestDataBuilder in Volo.Abp.IdentityServer.TestBase). It should be somehow unified! public class AbpIdentityServerTestDataBuilder : ITransientDependency { @@ -36,15 +37,15 @@ namespace Volo.Abp.IdentityServer _identityResourceRepository = identityResourceRepository; } - public void Build() + public async Task BuildAsync() { - AddClients(); - AddPersistentGrants(); - AddApiResources(); - AddIdentityResources(); + await AddClients().ConfigureAwait(false); + await AddPersistentGrants().ConfigureAwait(false); + await AddApiResources().ConfigureAwait(false); + await AddIdentityResources().ConfigureAwait(false); } - private void AddClients() + private async Task AddClients() { var client42 = new Client(_guidGenerator.Create(), "42") { @@ -55,49 +56,49 @@ namespace Volo.Abp.IdentityServer client42.AddScope("api1"); - _clientRepository.Insert(client42); + await _clientRepository.InsertAsync(client42).ConfigureAwait(false); } - private void AddPersistentGrants() + private async Task AddPersistentGrants() { - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "38", ClientId = "TestClientId-38", Type = "TestType-38", SubjectId = "TestSubject", Data = "TestData-38" - }); + }).ConfigureAwait(false); - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "37", ClientId = "TestClientId-37", Type = "TestType-37", SubjectId = "TestSubject", Data = "TestData-37" - }); + }).ConfigureAwait(false); - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "36", ClientId = "TestClientId-X", Type = "TestType-36", SubjectId = "TestSubject-X", Data = "TestData-36" - }); + }).ConfigureAwait(false); - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "35", ClientId = "TestClientId-X", Type = "TestType-35", SubjectId = "TestSubject-X", Data = "TestData-35" - }); + }).ConfigureAwait(false); } - private void AddApiResources() + private async Task AddApiResources() { var apiResource = new ApiResource(_guidGenerator.Create(), "Test-ApiResource-Name-1") { @@ -110,10 +111,10 @@ namespace Volo.Abp.IdentityServer apiResource.AddScope("Test-ApiResource-ApiScope-Name-1", "Test-ApiResource-ApiScope-DisplayName-1"); apiResource.AddUserClaim("Test-ApiResource-Claim-Type-1"); - _apiResourceRepository.Insert(apiResource); + await _apiResourceRepository.InsertAsync(apiResource).ConfigureAwait(false); } - private void AddIdentityResources() + private async Task AddIdentityResources() { var identityResource = new IdentityResource(_guidGenerator.Create(), "Test-Identity-Resource-Name-1") { @@ -125,7 +126,7 @@ namespace Volo.Abp.IdentityServer identityResource.AddUserClaim("Test-Identity-Resource-1-IdentityClaim-Type-1"); - _identityResourceRepository.Insert(identityResource); + await _identityResourceRepository.InsertAsync(identityResource).ConfigureAwait(false); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestEntityFrameworkCoreModule.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestEntityFrameworkCoreModule.cs index 627ae45e38..450bd922f8 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestEntityFrameworkCoreModule.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestEntityFrameworkCoreModule.cs @@ -7,6 +7,7 @@ using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.IdentityServer.EntityFrameworkCore; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.IdentityServer { @@ -55,9 +56,9 @@ namespace Volo.Abp.IdentityServer { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo.Abp.IdentityServer.MongoDB.Tests.csproj b/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo.Abp.IdentityServer.MongoDB.Tests.csproj index 2aba61db0d..6459a4c307 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo.Abp.IdentityServer.MongoDB.Tests.csproj +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo.Abp.IdentityServer.MongoDB.Tests.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo.Abp.IdentityServer.TestBase.csproj b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo.Abp.IdentityServer.TestBase.csproj index 60e98e6d29..c02b7d5c13 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo.Abp.IdentityServer.TestBase.csproj +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo.Abp.IdentityServer.TestBase.csproj @@ -19,7 +19,7 @@ - + diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBase.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBase.cs index a78caec8d0..ca3eebd260 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBase.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBase.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.IdentityServer { diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBaseModule.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBaseModule.cs index b80cfedc20..29c748361a 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBaseModule.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestBaseModule.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Autofac; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.IdentityServer { @@ -25,9 +26,9 @@ namespace Volo.Abp.IdentityServer { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs index f86d060d5b..ee6c8c59b6 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.Identity; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; +using Volo.Abp.IdentityServer.Devices; using Volo.Abp.IdentityServer.Grants; using Volo.Abp.IdentityServer.IdentityResources; +using Volo.Abp.Timing; namespace Volo.Abp.IdentityServer { @@ -18,7 +21,9 @@ namespace Volo.Abp.IdentityServer private readonly IIdentityResourceRepository _identityResourceRepository; private readonly IIdentityClaimTypeRepository _identityClaimTypeRepository; private readonly IPersistentGrantRepository _persistentGrantRepository; + private readonly IDeviceFlowCodesRepository _deviceFlowCodesRepository; private readonly AbpIdentityServerTestData _testData; + private readonly IClock _clock; public AbpIdentityServerTestDataBuilder( IGuidGenerator guidGenerator, @@ -27,7 +32,9 @@ namespace Volo.Abp.IdentityServer IIdentityResourceRepository identityResourceRepository, IIdentityClaimTypeRepository identityClaimTypeRepository, AbpIdentityServerTestData testData, - IPersistentGrantRepository persistentGrantRepository) + IPersistentGrantRepository persistentGrantRepository, + IDeviceFlowCodesRepository deviceFlowCodesRepository, + IClock clock) { _testData = testData; _guidGenerator = guidGenerator; @@ -36,48 +43,90 @@ namespace Volo.Abp.IdentityServer _identityResourceRepository = identityResourceRepository; _identityClaimTypeRepository = identityClaimTypeRepository; _persistentGrantRepository = persistentGrantRepository; + _clock = clock; + _deviceFlowCodesRepository = deviceFlowCodesRepository; } - public void Build() + public async Task BuildAsync() { - AddPersistedGrants(); - AddIdentityResources(); - AddApiResources(); - AddClients(); - AddClaimTypes(); + await AddDeviceFlowCodes().ConfigureAwait(false); + await AddPersistedGrants().ConfigureAwait(false); + await AddIdentityResources().ConfigureAwait(false); + await AddApiResources().ConfigureAwait(false); + await AddClients().ConfigureAwait(false); + await AddClaimTypes().ConfigureAwait(false); } - private void AddPersistedGrants() + private async Task AddDeviceFlowCodes() { - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _deviceFlowCodesRepository.InsertAsync( + new DeviceFlowCodes(_guidGenerator.Create()) + { + ClientId = "c1", + DeviceCode = "DeviceCode1", + Expiration = _clock.Now.AddDays(1), + Data = "{\"Lifetime\":\"42\"}", + UserCode = "DeviceFlowCodesUserCode1", + SubjectId = "DeviceFlowCodesSubjectId1" + } + ); + + await _deviceFlowCodesRepository.InsertAsync( + new DeviceFlowCodes(_guidGenerator.Create()) + { + ClientId = "c1", + DeviceCode = "DeviceCode2", + Expiration = _clock.Now.AddDays(-1), + Data = "", + UserCode = "DeviceFlowCodesUserCode2", + SubjectId = "DeviceFlowCodesSubjectId2" + } + ); + + } + + private async Task AddPersistedGrants() + { + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "PersistedGrantKey1", SubjectId = "PersistedGrantSubjectId1", ClientId = "PersistedGrantClientId1", Type = "PersistedGrantType1", Data = "" - }); + }).ConfigureAwait(false); - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "PersistedGrantKey2", SubjectId = "PersistedGrantSubjectId2", ClientId = "c1", Type = "c1type", Data = "" - }); + }).ConfigureAwait(false); - _persistentGrantRepository.Insert(new PersistedGrant(_guidGenerator.Create()) + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) { Key = "PersistedGrantKey3", SubjectId = "PersistedGrantSubjectId3", ClientId = "c1", Type = "c1type", - Data = "" - }); + Data = "", + Expiration = _clock.Now.AddDays(1), + }).ConfigureAwait(false); + + await _persistentGrantRepository.InsertAsync(new PersistedGrant(_guidGenerator.Create()) + { + Key = "PersistedGrantKey_Expired1", + SubjectId = "PersistedGrantSubjectId_Expired1", + ClientId = "c1", + Type = "c1type", + Data = "", + Expiration = _clock.Now.AddDays(-1) + }).ConfigureAwait(false); } - private void AddIdentityResources() + private async Task AddIdentityResources() { var identityResource = new IdentityResource(_testData.IdentityResource1Id, "NewIdentityResource1") { @@ -87,12 +136,12 @@ namespace Volo.Abp.IdentityServer identityResource.AddUserClaim(nameof(ApiResourceClaim.Type)); - _identityResourceRepository.Insert(identityResource); - _identityResourceRepository.Insert(new IdentityResource(_guidGenerator.Create(), "NewIdentityResource2")); - _identityResourceRepository.Insert(new IdentityResource(_guidGenerator.Create(), "NewIdentityResource3")); + await _identityResourceRepository.InsertAsync(identityResource).ConfigureAwait(false); + await _identityResourceRepository.InsertAsync(new IdentityResource(_guidGenerator.Create(), "NewIdentityResource2")).ConfigureAwait(false); + await _identityResourceRepository.InsertAsync(new IdentityResource(_guidGenerator.Create(), "NewIdentityResource3")).ConfigureAwait(false); } - private void AddApiResources() + private async Task AddApiResources() { var apiResource = new ApiResource(_testData.ApiResource1Id, "NewApiResource1"); apiResource.Description = nameof(apiResource.Description); @@ -102,12 +151,12 @@ namespace Volo.Abp.IdentityServer apiResource.AddUserClaim(nameof(ApiResourceClaim.Type)); apiResource.AddSecret(nameof(ApiSecret.Value)); - _apiResourceRepository.Insert(apiResource); - _apiResourceRepository.Insert(new ApiResource(_guidGenerator.Create(), "NewApiResource2")); - _apiResourceRepository.Insert(new ApiResource(_guidGenerator.Create(), "NewApiResource3")); + await _apiResourceRepository.InsertAsync(apiResource).ConfigureAwait(false); + await _apiResourceRepository.InsertAsync(new ApiResource(_guidGenerator.Create(), "NewApiResource2")).ConfigureAwait(false); + await _apiResourceRepository.InsertAsync(new ApiResource(_guidGenerator.Create(), "NewApiResource3")).ConfigureAwait(false); } - private void AddClients() + private async Task AddClients() { var client = new Client(_testData.Client1Id, "ClientId1") { @@ -129,17 +178,17 @@ namespace Volo.Abp.IdentityServer client.AddScope(nameof(ClientScope.Scope)); client.AddSecret(nameof(ClientSecret.Value)); - _clientRepository.Insert(client); + await _clientRepository.InsertAsync(client).ConfigureAwait(false); - _clientRepository.Insert(new Client(_guidGenerator.Create(), "ClientId2")); - _clientRepository.Insert(new Client(_guidGenerator.Create(), "ClientId3")); + await _clientRepository.InsertAsync(new Client(_guidGenerator.Create(), "ClientId2")).ConfigureAwait(false); + await _clientRepository.InsertAsync(new Client(_guidGenerator.Create(), "ClientId3")).ConfigureAwait(false); } - private void AddClaimTypes() + private async Task AddClaimTypes() { var ageClaim = new IdentityClaimType(Guid.NewGuid(), "Age", false, false, null, null, null, IdentityClaimValueType.Int); - _identityClaimTypeRepository.Insert(ageClaim); + await _identityClaimTypeRepository.InsertAsync(ageClaim).ConfigureAwait(false); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ApiResourceRepository_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ApiResourceRepository_Tests.cs index db8eacae5c..43b4e9d8f2 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ApiResourceRepository_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ApiResourceRepository_Tests.cs @@ -20,13 +20,13 @@ namespace Volo.Abp.IdentityServer [Fact] public async Task FindByNormalizedNameAsync() { - (await apiResourceRepository.FindByNameAsync("NewApiResource2")).ShouldNotBeNull(); + (await apiResourceRepository.FindByNameAsync("NewApiResource2").ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] public async Task GetListByScopesAsync() { - (await apiResourceRepository.GetListByScopesAsync(new []{ "NewApiResource2", "NewApiResource3"})).Count.ShouldBe(2); + (await apiResourceRepository.GetListByScopesAsync(new[] { "NewApiResource2", "NewApiResource3" }).ConfigureAwait(false)).Count.ShouldBe(2); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ClientRepository_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ClientRepository_Tests.cs index 86f69610f5..300c1620ff 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ClientRepository_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/ClientRepository_Tests.cs @@ -21,13 +21,13 @@ namespace Volo.Abp.IdentityServer [Fact] public async Task FindByCliendIdAsync() { - (await clientRepository.FindByCliendIdAsync("ClientId2")).ShouldNotBeNull(); + (await clientRepository.FindByCliendIdAsync("ClientId2").ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] public async Task GetAllDistinctAllowedCorsOriginsAsync() { - var origins = await clientRepository.GetAllDistinctAllowedCorsOriginsAsync(); + var origins = await clientRepository.GetAllDistinctAllowedCorsOriginsAsync().ConfigureAwait(false); origins.Any().ShouldBeTrue(); } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/IdentityResourceRepository_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/IdentityResourceRepository_Tests.cs index 32fd716d3d..2d98fff2a3 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/IdentityResourceRepository_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/IdentityResourceRepository_Tests.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.IdentityServer [Fact] public async Task GetListByScopesAsync() { - (await identityResourceRepository.GetListByScopesAsync(new []{"", "NewIdentityResource2" })).Count.ShouldBe(1); + (await identityResourceRepository.GetListByScopesAsync(new[] { "", "NewIdentityResource2" }).ConfigureAwait(false)).Count.ShouldBe(1); } } } diff --git a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/PersistentGrantRepository_Tests.cs b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/PersistentGrantRepository_Tests.cs index 20f6674515..0786af42bc 100644 --- a/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/PersistentGrantRepository_Tests.cs +++ b/modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/PersistentGrantRepository_Tests.cs @@ -22,13 +22,13 @@ namespace Volo.Abp.IdentityServer [Fact] public async Task FindByKeyAsync() { - (await _persistentGrantRepository.FindByKeyAsync("PersistedGrantKey1")).ShouldNotBeNull(); + (await _persistentGrantRepository.FindByKeyAsync("PersistedGrantKey1").ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] public async Task GetListBySubjectIdAsync() { - var persistedGrants = await _persistentGrantRepository.GetListBySubjectIdAsync("PersistedGrantSubjectId1"); + var persistedGrants = await _persistentGrantRepository.GetListBySubjectIdAsync("PersistedGrantSubjectId1").ConfigureAwait(false); persistedGrants.ShouldNotBeEmpty(); persistedGrants.ShouldContain(x => x.Key == "PersistedGrantKey1"); } @@ -36,9 +36,9 @@ namespace Volo.Abp.IdentityServer [Fact] public async Task DeleteBySubjectIdAndClientId() { - await _persistentGrantRepository.DeleteAsync("PersistedGrantSubjectId1", "PersistedGrantClientId1"); + await _persistentGrantRepository.DeleteAsync("PersistedGrantSubjectId1", "PersistedGrantClientId1").ConfigureAwait(false); - var persistedGrants = await _persistentGrantRepository.GetListAsync(); + var persistedGrants = await _persistentGrantRepository.GetListAsync().ConfigureAwait(false); persistedGrants.ShouldNotBeEmpty(); persistedGrants.ShouldNotContain(x => x.Key == "PersistedGrantKey1" && x.SubjectId == "PersistedGrantSubjectId1" && @@ -49,9 +49,9 @@ namespace Volo.Abp.IdentityServer public async Task DeleteBySubjectIdAndClientIdAndType() { await _persistentGrantRepository.DeleteAsync("PersistedGrantSubjectId1", "PersistedGrantClientId1", - "PersistedGrantClientId1"); + "PersistedGrantClientId1").ConfigureAwait(false); - var persistedGrants = await _persistentGrantRepository.GetListAsync(); + var persistedGrants = await _persistentGrantRepository.GetListAsync().ConfigureAwait(false); persistedGrants.ShouldNotBeEmpty(); persistedGrants.ShouldNotContain(x => x.Key == "PersistedGrantKey1" && x.SubjectId == "PersistedGrantSubjectId1" && diff --git a/modules/permission-management/Volo.Abp.PermissionManagement.sln b/modules/permission-management/Volo.Abp.PermissionManagement.sln index 5812918a3c..16071f9e10 100644 --- a/modules/permission-management/Volo.Abp.PermissionManagement.sln +++ b/modules/permission-management/Volo.Abp.PermissionManagement.sln @@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManageme EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManagement.Web", "src\Volo.Abp.PermissionManagement.Web\Volo.Abp.PermissionManagement.Web.csproj", "{97A386F8-DAE0-4BEA-ADE5-1D57C3336515}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManagement.Tests", "test\Volo.Abp.PermissionManagement.Tests\Volo.Abp.PermissionManagement.Tests.csproj", "{48297098-79D0-413B-939C-6C432142C42D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManagement.Domain.Tests", "test\Volo.Abp.PermissionManagement.Tests\Volo.Abp.PermissionManagement.Domain.Tests.csproj", "{48297098-79D0-413B-939C-6C432142C42D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManagement.TestBase", "test\Volo.Abp.PermissionManagement.TestBase\Volo.Abp.PermissionManagement.TestBase.csproj", "{49259427-CAEB-4FAE-81E4-848F789487EA}" EndProject @@ -33,7 +33,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManageme EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManagement.HttpApi.Client", "src\Volo.Abp.PermissionManagement.HttpApi.Client\Volo.Abp.PermissionManagement.HttpApi.Client.csproj", "{1CD80519-9431-48DB-B0EA-291A73FF9F49}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.PermissionManagement.Application.Tests", "test\Volo.Abp.PermissionManagement.Application.Tests\Volo.Abp.PermissionManagement.Application.Tests.csproj", "{A0F72F5F-3713-4E06-ADB7-15ADFDCB79B1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.PermissionManagement.Application.Tests", "test\Volo.Abp.PermissionManagement.Application.Tests\Volo.Abp.PermissionManagement.Application.Tests.csproj", "{A0F72F5F-3713-4E06-ADB7-15ADFDCB79B1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index 63065fd688..b9f504b4f1 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.PermissionManagement public virtual async Task GetAsync(string providerName, string providerKey) { - await CheckProviderPolicy(providerName); + await CheckProviderPolicy(providerName).ConfigureAwait(false); var result = new GetPermissionListResultDto { @@ -74,7 +74,7 @@ namespace Volo.Abp.PermissionManagement GrantedProviders = new List() }; - var grantInfo = await _permissionManager.GetAsync(permission.Name, providerName, providerKey); + var grantInfo = await _permissionManager.GetAsync(permission.Name, providerName, providerKey).ConfigureAwait(false); grantInfoDto.IsGranted = grantInfo.IsGranted; @@ -101,11 +101,11 @@ namespace Volo.Abp.PermissionManagement public virtual async Task UpdateAsync(string providerName, string providerKey, UpdatePermissionsDto input) { - await CheckProviderPolicy(providerName); + await CheckProviderPolicy(providerName).ConfigureAwait(false); foreach (var permissionDto in input.Permissions) { - await _permissionManager.SetAsync(permissionDto.Name, providerName, providerKey, permissionDto.IsGranted); + await _permissionManager.SetAsync(permissionDto.Name, providerName, providerKey, permissionDto.IsGranted).ConfigureAwait(false); } } @@ -117,7 +117,7 @@ namespace Volo.Abp.PermissionManagement throw new AbpException($"No policy defined to get/set permissions for the provider '{policyName}'. Use {nameof(PermissionManagementOptions)} to map the policy."); } - await AuthorizationService.CheckAsync(policyName); + await AuthorizationService.CheckAsync(policyName).ConfigureAwait(false); } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo.Abp.PermissionManagement.Domain.Shared.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo.Abp.PermissionManagement.Domain.Shared.csproj index fd4d602045..ff0ba6fbee 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo.Abp.PermissionManagement.Domain.Shared.csproj +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo.Abp.PermissionManagement.Domain.Shared.csproj @@ -19,7 +19,7 @@ - + diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainSharedModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainSharedModule.cs index 210ff6affc..b1d2c59a73 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainSharedModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainSharedModule.cs @@ -1,13 +1,14 @@ using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.Localization; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.PermissionManagement { [DependsOn( - typeof(AbpLocalizationModule) + typeof(AbpValidationModule) )] public class AbpPermissionManagementDomainSharedModule : AbpModule { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json new file mode 100644 index 0000000000..ea109a2dd0 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json @@ -0,0 +1,10 @@ +{ + "culture": "zh-Hant", + "texts": { + "Permissions": "權限", + "OnlyProviderPermissons": "只有這個提供者", + "All": "全部", + "SelectAllInAllTabs": "授予所有權限", + "SelectAllInThisTab": "全選" + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs index 886d546073..8c0beffd1a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -7,8 +8,17 @@ namespace Volo.Abp.PermissionManagement { public interface IPermissionGrantRepository : IBasicRepository { - Task FindAsync(string name, string providerName, string providerKey); + Task FindAsync( + string name, + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); - Task> GetListAsync(string providerName, string providerKey); + Task> GetListAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs index 888f06235e..26310a12fe 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs @@ -13,5 +13,7 @@ namespace Volo.Abp.PermissionManagement Task> GetAllAsync([NotNull] string providerName, [NotNull] string providerKey); Task SetAsync(string permissionName, string providerName, string providerKey, bool isGranted); + + Task UpdateProviderKeyAsync(PermissionGrant permissionGrant, string providerKey); } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeeder.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeeder.cs index 80062f528d..451b9fadbf 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeeder.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeeder.cs @@ -40,7 +40,7 @@ namespace Volo.Abp.PermissionManagement providerKey, tenantId ) - ); + ).ConfigureAwait(false); } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrant.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrant.cs index 7ec99fbe3a..4f951a92cc 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrant.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrant.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.PermissionManagement public virtual string ProviderName { get; protected set; } [CanBeNull] - public virtual string ProviderKey { get; protected set; } + public virtual string ProviderKey { get; protected internal set; } protected PermissionGrant() { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs index 9e73e59b79..46badf093a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs @@ -29,7 +29,7 @@ namespace Volo.Abp.PermissionManagement using (CurrentTenant.Change(eventData.Entity.TenantId)) { - await Cache.RemoveAsync(cacheKey); + await Cache.RemoveAsync(cacheKey).ConfigureAwait(false); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementProvider.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementProvider.cs index 0b83f37fd1..9cca1277d5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementProvider.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementProvider.cs @@ -46,7 +46,7 @@ namespace Volo.Abp.PermissionManagement protected virtual async Task GrantAsync(string name, string providerKey) { - var permissionGrant = await PermissionGrantRepository.FindAsync(name, Name, providerKey); + var permissionGrant = await PermissionGrantRepository.FindAsync(name, Name, providerKey).ConfigureAwait(false); if (permissionGrant != null) { return; @@ -60,18 +60,18 @@ namespace Volo.Abp.PermissionManagement providerKey, CurrentTenant.Id ) - ); + ).ConfigureAwait(false); } protected virtual async Task RevokeAsync(string name, string providerKey) { - var permissionGrant = await PermissionGrantRepository.FindAsync(name, Name, providerKey); + var permissionGrant = await PermissionGrantRepository.FindAsync(name, Name, providerKey).ConfigureAwait(false); if (permissionGrant == null) { return; } - await PermissionGrantRepository.DeleteAsync(permissionGrant); + await PermissionGrantRepository.DeleteAsync(permissionGrant).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs index f8825c6e81..4f7d177802 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs @@ -52,7 +52,7 @@ namespace Volo.Abp.PermissionManagement public async Task GetAsync(string permissionName, string providerName, string providerKey) { - return await GetInternalAsync(PermissionDefinitionManager.Get(permissionName), providerName, providerKey); + return await GetInternalAsync(PermissionDefinitionManager.Get(permissionName), providerName, providerKey).ConfigureAwait(false); } public async Task> GetAllAsync(string providerName, string providerKey) @@ -61,7 +61,7 @@ namespace Volo.Abp.PermissionManagement foreach (var permissionDefinition in PermissionDefinitionManager.GetPermissions()) { - results.Add(await GetInternalAsync(permissionDefinition, providerName, providerKey)); + results.Add(await GetInternalAsync(permissionDefinition, providerName, providerKey).ConfigureAwait(false)); } return results; @@ -83,7 +83,7 @@ namespace Volo.Abp.PermissionManagement throw new ApplicationException($"The permission named '{permission.Name}' has multitenancy side '{permission.MultiTenancySide}' which is not compatible with the current multitenancy side '{CurrentTenant.GetMultiTenancySide()}'"); } - var currentGrantInfo = await GetInternalAsync(permission, providerName, providerKey); + var currentGrantInfo = await GetInternalAsync(permission, providerName, providerKey).ConfigureAwait(false); if (currentGrantInfo.IsGranted == isGranted) { return; @@ -96,7 +96,13 @@ namespace Volo.Abp.PermissionManagement throw new AbpException("Unknown permission management provider: " + providerName); } - await provider.SetAsync(permissionName, providerKey, isGranted); + await provider.SetAsync(permissionName, providerKey, isGranted).ConfigureAwait(false); + } + + public async Task UpdateProviderKeyAsync(PermissionGrant permissionGrant, string providerKey) + { + permissionGrant.ProviderKey = providerKey; + return await PermissionGrantRepository.UpdateAsync(permissionGrant).ConfigureAwait(false); } protected virtual async Task GetInternalAsync(PermissionDefinition permission, string providerName, string providerKey) @@ -115,7 +121,7 @@ namespace Volo.Abp.PermissionManagement foreach (var provider in ManagementProviders) { - var providerResult = await provider.CheckAsync(permission.Name, providerName, providerKey); + var providerResult = await provider.CheckAsync(permission.Name, providerName, providerKey).ConfigureAwait(false); if (providerResult.IsGranted) { result.IsGranted = true; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs index c312a094e7..0d594007e8 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs @@ -1,4 +1,6 @@ using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; @@ -7,42 +9,55 @@ namespace Volo.Abp.PermissionManagement { public class PermissionStore : IPermissionStore, ITransientDependency { + public ILogger Logger { get; set; } + protected IPermissionGrantRepository PermissionGrantRepository { get; } protected IDistributedCache Cache { get; } - + public PermissionStore( IPermissionGrantRepository permissionGrantRepository, IDistributedCache cache) { PermissionGrantRepository = permissionGrantRepository; Cache = cache; + Logger = NullLogger.Instance; } public async Task IsGrantedAsync(string name, string providerName, string providerKey) { - return (await GetCacheItemAsync(name, providerName, providerKey)).IsGranted; + return (await GetCacheItemAsync(name, providerName, providerKey).ConfigureAwait(false)).IsGranted; } protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey) { var cacheKey = CalculateCacheKey(name, providerName, providerKey); - var cacheItem = await Cache.GetAsync(cacheKey); + + Logger.LogDebug($"PermissionStore.GetCacheItemAsync: {cacheKey}"); + + var cacheItem = await Cache.GetAsync(cacheKey).ConfigureAwait(false); if (cacheItem != null) { + Logger.LogDebug($"Found in the cache: {cacheKey}"); return cacheItem; } + Logger.LogDebug($"Not found in the cache, getting from the repository: {cacheKey}"); + cacheItem = new PermissionGrantCacheItem( name, - await PermissionGrantRepository.FindAsync(name, providerName, providerKey) != null + (await PermissionGrantRepository.FindAsync(name, providerName, providerKey)) != null ); + Logger.LogDebug($"Setting the cache item: {cacheKey}"); + await Cache.SetAsync( cacheKey, cacheItem - ); + ).ConfigureAwait(false); + + Logger.LogDebug($"Finished setting the cache item: {cacheKey}"); return cacheItem; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo.Abp.PermissionManagement.EntityFrameworkCore.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo.Abp.PermissionManagement.EntityFrameworkCore.csproj index c13b3da80b..037bda9589 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo.Abp.PermissionManagement.EntityFrameworkCore.csproj +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo.Abp.PermissionManagement.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.PermissionManagement.EntityFrameworkCore Volo.Abp.PermissionManagement.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs index 413a960c7c..8663e8026a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -8,7 +9,8 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.PermissionManagement.EntityFrameworkCore { - public class EfCorePermissionGrantRepository : EfCoreRepository, IPermissionGrantRepository + public class EfCorePermissionGrantRepository : EfCoreRepository, + IPermissionGrantRepository { public EfCorePermissionGrantRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) @@ -16,23 +18,31 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore } - public async Task FindAsync(string name, string providerName, string providerKey) + public async Task FindAsync( + string name, + string providerName, + string providerKey, + CancellationToken cancellationToken = default) { return await DbSet .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && - s.ProviderKey == providerKey - ); + s.ProviderKey == providerKey, + GetCancellationToken(cancellationToken) + ).ConfigureAwait(false); } - public async Task> GetListAsync(string providerName, string providerKey) + public async Task> GetListAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default) { return await DbSet .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey - ).ToListAsync(); + ).ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs index 70614c890d..bc2f5ef5d9 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; @@ -16,23 +17,31 @@ namespace Volo.Abp.PermissionManagement.MongoDB } - public async Task FindAsync(string name, string providerName, string providerKey) + public async Task FindAsync( + string name, + string providerName, + string providerKey, + CancellationToken cancellationToken = default) { return await GetMongoQueryable() .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && - s.ProviderKey == providerKey - ); + s.ProviderKey == providerKey, + GetCancellationToken(cancellationToken) + ).ConfigureAwait(false); } - public async Task> GetListAsync(string providerName, string providerKey) + public async Task> GetListAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default) { return await GetMongoQueryable() .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey - ).ToListAsync(); + ).ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs index cf1c3f13b1..c7f4e08480 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs @@ -1,10 +1,7 @@ -using Localization.Resources.AbpUi; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AutoMapper; -using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.HttpApi; using Volo.Abp.PermissionManagement.Localization; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs index 70ec393455..fe01aa6618 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs @@ -42,7 +42,7 @@ namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement { ValidateModel(); - var result = await _permissionAppService.GetAsync(ProviderName, ProviderKey); + var result = await _permissionAppService.GetAsync(ProviderName, ProviderKey).ConfigureAwait(false); EntityDisplayName = result.EntityDisplayName; @@ -84,7 +84,7 @@ namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement { Permissions = updatePermissionDtos } - ); + ).ConfigureAwait(false); return NoContent(); } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo.Abp.PermissionManagement.Application.Tests.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo.Abp.PermissionManagement.Application.Tests.csproj index c17b20f355..81e3861ed9 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo.Abp.PermissionManagement.Application.Tests.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo.Abp.PermissionManagement.Application.Tests.csproj @@ -5,12 +5,12 @@ - + - + diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs index 8b36b02877..d610eede6e 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.PermissionManagement.Application.Tests.Volo.Abp.PermissionMan public async Task GetAsync() { var permissionListResultDto = await _permissionAppService.GetAsync(UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()); + PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false); permissionListResultDto.ShouldNotBeNull(); permissionListResultDto.EntityDisplayName.ShouldBe(PermissionTestDataBuilder.User1Id.ToString()); @@ -43,7 +43,7 @@ namespace Volo.Abp.PermissionManagement.Application.Tests.Volo.Abp.PermissionMan public async Task UpdateAsync() { (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", - "Test")).ShouldBeNull(); + "Test").ConfigureAwait(false)).ShouldBeNull(); await _permissionAppService.UpdateAsync("Test", "Test", new UpdatePermissionsDto() @@ -56,25 +56,25 @@ namespace Volo.Abp.PermissionManagement.Application.Tests.Volo.Abp.PermissionMan Name = "MyPermission1" } } - }); + }).ConfigureAwait(false); (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", - "Test")).ShouldNotBeNull(); + "Test").ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] public async Task Update_Revoke_Test() { - _permissionGrantRepository.Insert( + await _permissionGrantRepository.InsertAsync( new PermissionGrant( - Guid.NewGuid(), + Guid.NewGuid(), "MyPermission1", "Test", "Test" ) - ); + ).ConfigureAwait(false); (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", - "Test")).ShouldNotBeNull(); + "Test").ConfigureAwait(false)).ShouldNotBeNull(); await _permissionAppService.UpdateAsync("Test", "Test", new UpdatePermissionsDto() @@ -87,10 +87,10 @@ namespace Volo.Abp.PermissionManagement.Application.Tests.Volo.Abp.PermissionMan Name = "MyPermission1" } } - }); + }).ConfigureAwait(false); (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", - "Test")).ShouldBeNull(); + "Test").ConfigureAwait(false)).ShouldBeNull(); } } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests.csproj index f1510b8f17..c3e5d1d750 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests.csproj @@ -18,7 +18,7 @@ - + \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo.Abp.PermissionManagement.MongoDB.Tests.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo.Abp.PermissionManagement.MongoDB.Tests.csproj index 140772eadc..1f66b07cf5 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo.Abp.PermissionManagement.MongoDB.Tests.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo.Abp.PermissionManagement.MongoDB.Tests.csproj @@ -17,8 +17,8 @@ - - + + \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo.Abp.PermissionManagement.TestBase.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo.Abp.PermissionManagement.TestBase.csproj index 49dfaf8af7..ba8c20e337 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo.Abp.PermissionManagement.TestBase.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo.Abp.PermissionManagement.TestBase.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs index ec343d9615..20f4c94b62 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Autofac; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement { @@ -29,9 +30,9 @@ namespace Volo.Abp.PermissionManagement { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(() => scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs index e27be7e426..217b81361b 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs @@ -19,16 +19,16 @@ namespace Volo.Abp.PermissionManagement [Fact] public async Task FindAsync() { - (await PermissionGrantRepository.FindAsync("MyPermission1", UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString())).ShouldNotBeNull(); + (await PermissionGrantRepository.FindAsync("MyPermission1", UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false)).ShouldNotBeNull(); - (await PermissionGrantRepository.FindAsync("Undefined-Permission", UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString())).ShouldBeNull(); - (await PermissionGrantRepository.FindAsync("MyPermission1", "Undefined-Provider", "Unknown-Id")).ShouldBeNull(); + (await PermissionGrantRepository.FindAsync("Undefined-Permission", UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false)).ShouldBeNull(); + (await PermissionGrantRepository.FindAsync("MyPermission1", "Undefined-Provider", "Unknown-Id").ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task GetListAsync() { - var permissionGrants = await PermissionGrantRepository.GetListAsync(UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString()); + var permissionGrants = await PermissionGrantRepository.GetListAsync(UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false); permissionGrants.ShouldContain(p => p.Name == "MyPermission1"); } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionManagementTestBase.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionManagementTestBase.cs index c90537d159..d64369978b 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionManagementTestBase.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionManagementTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.PermissionManagement { diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs index 9d9e2ab10f..d6e89741c4 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; @@ -19,25 +20,25 @@ namespace Volo.Abp.PermissionManagement _permissionGrantRepository = permissionGrantRepository; } - public void Build() + public async Task BuildAsync() { - _permissionGrantRepository.Insert( + await _permissionGrantRepository.InsertAsync( new PermissionGrant( _guidGenerator.Create(), "MyPermission1", UserPermissionValueProvider.ProviderName, User1Id.ToString() ) - ); + ).ConfigureAwait(false); - _permissionGrantRepository.Insert( + await _permissionGrantRepository.InsertAsync( new PermissionGrant( _guidGenerator.Create(), "MyPermission3", UserPermissionValueProvider.ProviderName, User1Id.ToString() ) - ); + ).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo.Abp.PermissionManagement.Tests.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj similarity index 98% rename from modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo.Abp.PermissionManagement.Tests.csproj rename to modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj index 889a464c81..c9a10af869 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo.Abp.PermissionManagement.Tests.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj @@ -18,7 +18,7 @@ - + \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs index 1fb52c13a1..b2125dbf02 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs @@ -19,13 +19,13 @@ namespace Volo.Abp.PermissionManagement { await Assert.ThrowsAsync(async () => await _permissionChecker.IsGrantedAsync("UndefinedPermissionName") - ); +.ConfigureAwait(false)).ConfigureAwait(false); } [Fact] public async Task Should_Return_False_As_Default_For_Any_Permission() { - (await _permissionChecker.IsGrantedAsync("MyPermission1")).ShouldBeFalse(); + (await _permissionChecker.IsGrantedAsync("MyPermission1").ConfigureAwait(false)).ShouldBeFalse(); } } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_User_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_User_Tests.cs index b49ff94f90..2a6f59af82 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_User_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionChecker_User_Tests.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.PermissionManagement (await _permissionChecker.IsGrantedAsync( CreatePrincipal(PermissionTestDataBuilder.User1Id), "MyPermission1" - )).ShouldBeTrue(); + ).ConfigureAwait(false)).ShouldBeTrue(); } [Fact] @@ -32,7 +32,7 @@ namespace Volo.Abp.PermissionManagement (await _permissionChecker.IsGrantedAsync( CreatePrincipal(PermissionTestDataBuilder.User2Id), "MyPermission1" - )).ShouldBeFalse(); + ).ConfigureAwait(false)).ShouldBeFalse(); } [Fact] @@ -41,7 +41,7 @@ namespace Volo.Abp.PermissionManagement (await _permissionChecker.IsGrantedAsync( CreatePrincipal(null), "MyPermission1" - )).ShouldBeFalse(); + ).ConfigureAwait(false)).ShouldBeFalse(); } [Fact] @@ -50,7 +50,7 @@ namespace Volo.Abp.PermissionManagement (await _permissionChecker.IsGrantedAsync( CreatePrincipal(PermissionTestDataBuilder.User1Id, Guid.NewGuid()), "MyPermission3" - )).ShouldBeFalse(); + ).ConfigureAwait(false)).ShouldBeFalse(); } private static ClaimsPrincipal CreatePrincipal(Guid? userId, Guid? tenantId = null) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionDataSeeder_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionDataSeeder_Tests.cs index 6868421a8a..32ee6ff1cf 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionDataSeeder_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionDataSeeder_Tests.cs @@ -21,17 +21,17 @@ namespace Volo.Abp.PermissionManagement [Fact] public async Task SeedAsync() { - (await _grantpermissionGrantRepository.FindAsync("MyPermission1", "Test", "Test")).ShouldBeNull(); - (await _grantpermissionGrantRepository.FindAsync("MyPermission2", "Test", "Test")).ShouldBeNull(); + (await _grantpermissionGrantRepository.FindAsync("MyPermission1", "Test", "Test").ConfigureAwait(false)).ShouldBeNull(); + (await _grantpermissionGrantRepository.FindAsync("MyPermission2", "Test", "Test").ConfigureAwait(false)).ShouldBeNull(); await _permissionDataSeeder.SeedAsync("Test", "Test", new List() { "MyPermission1", "MyPermission2" - }); + }).ConfigureAwait(false); - (await _grantpermissionGrantRepository.FindAsync("MyPermission1", "Test", "Test")).ShouldNotBeNull(); - (await _grantpermissionGrantRepository.FindAsync("MyPermission2", "Test", "Test")).ShouldNotBeNull(); + (await _grantpermissionGrantRepository.FindAsync("MyPermission1", "Test", "Test").ConfigureAwait(false)).ShouldNotBeNull(); + (await _grantpermissionGrantRepository.FindAsync("MyPermission2", "Test", "Test").ConfigureAwait(false)).ShouldNotBeNull(); } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator_Tests.cs index 9d4248bb5a..7148fe9191 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator_Tests.cs @@ -28,17 +28,17 @@ namespace Volo.Abp.PermissionManagement { (await _cache.GetAsync(PermissionGrantCacheItem.CalculateCacheKey("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()))).ShouldBeNull(); + PermissionTestDataBuilder.User1Id.ToString())).ConfigureAwait(false)).ShouldBeNull(); await _permissionStore.IsGrantedAsync("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()); + PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false); (await _cache.GetAsync(PermissionGrantCacheItem.CalculateCacheKey("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()))).ShouldNotBeNull(); + PermissionTestDataBuilder.User1Id.ToString())).ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] @@ -47,17 +47,17 @@ namespace Volo.Abp.PermissionManagement // IsGrantedAsync will cache PermissionGrant await _permissionStore.IsGrantedAsync("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()); + PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false); var permissionGrant = await _permissionGrantRepository.FindAsync("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()); + PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false); permissionGrant.ShouldNotBeNull(); - await _permissionGrantRepository.DeleteAsync(permissionGrant); + await _permissionGrantRepository.DeleteAsync(permissionGrant).ConfigureAwait(false); (await _cache.GetAsync(PermissionGrantCacheItem.CalculateCacheKey("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString()))).ShouldBeNull(); + PermissionTestDataBuilder.User1Id.ToString())).ConfigureAwait(false)).ShouldBeNull(); } } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManagementProvider_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManagementProvider_Tests.cs index d1e249c29a..1cbab007e3 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManagementProvider_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManagementProvider_Tests.cs @@ -22,18 +22,18 @@ namespace Volo.Abp.PermissionManagement [Fact] public async Task CheckAsync() { - _permissionGrantRepository.Insert( + await _permissionGrantRepository.InsertAsync( new PermissionGrant( Guid.NewGuid(), "MyPermission1", "Test", "Test" ) - ); + ).ConfigureAwait(false); var permissionValueProviderGrantInfo = await _permissionManagementProvider.CheckAsync("MyPermission1", "Test", - "Test"); + "Test").ConfigureAwait(false); permissionValueProviderGrantInfo.IsGranted.ShouldBeTrue(); permissionValueProviderGrantInfo.ProviderKey.ShouldBe("Test"); @@ -44,7 +44,7 @@ namespace Volo.Abp.PermissionManagement { var permissionValueProviderGrantInfo = await _permissionManagementProvider.CheckAsync("MyPermission1", "TestNotExist", - "Test"); + "Test").ConfigureAwait(false); permissionValueProviderGrantInfo.IsGranted.ShouldBeFalse(); permissionValueProviderGrantInfo.ProviderKey.ShouldBeNull(); @@ -54,25 +54,25 @@ namespace Volo.Abp.PermissionManagement [Fact] public async Task SetAsync() { - _permissionGrantRepository.Insert( + await _permissionGrantRepository.InsertAsync( new PermissionGrant( Guid.NewGuid(), "MyPermission1", "Test", "Test" ) - ); + ).ConfigureAwait(false); (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", - "Test")).ShouldNotBeNull(); + "Test").ConfigureAwait(false)).ShouldNotBeNull(); await _permissionManagementProvider.SetAsync("MyPermission1", "Test", - false); + false).ConfigureAwait(false); (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", - "Test")).ShouldBeNull(); + "Test").ConfigureAwait(false)).ShouldBeNull(); } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs index b5fe647c89..66f0de1755 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs @@ -28,11 +28,11 @@ namespace Volo.Abp.PermissionManagement "MyPermission1", "Test", "Test") - ); + ).ConfigureAwait(false); var grantedProviders = await _permissionManager.GetAsync("MyPermission1", "Test", - "Test"); + "Test").ConfigureAwait(false); grantedProviders.ShouldNotBeNull(); grantedProviders.IsGranted.ShouldBeTrue(); @@ -46,7 +46,7 @@ namespace Volo.Abp.PermissionManagement await Assert.ThrowsAsync(async () => await _permissionManager.GetAsync( "MyPermission1NotExist", "Test", - "Test")); + "Test").ConfigureAwait(false)).ConfigureAwait(false); } [Fact] @@ -57,18 +57,18 @@ namespace Volo.Abp.PermissionManagement "MyPermission1", "Test", "Test") - ); + ).ConfigureAwait(false); await _permissionGrantRepository.InsertAsync(new PermissionGrant( Guid.NewGuid(), "MyPermission2", "Test", "Test") - ); + ).ConfigureAwait(false); var permissionWithGrantedProviders = await _permissionManager.GetAllAsync( "Test", - "Test"); + "Test").ConfigureAwait(false); permissionWithGrantedProviders.ShouldNotBeNull(); permissionWithGrantedProviders.ShouldContain(x => @@ -82,16 +82,16 @@ namespace Volo.Abp.PermissionManagement { (await _permissionGrantRepository.FindAsync("MyPermission2", "Test", - "Test")).ShouldBeNull(); + "Test").ConfigureAwait(false)).ShouldBeNull(); await _permissionManager.SetAsync( "MyPermission2", "Test", - "Test", true); + "Test", true).ConfigureAwait(false); (await _permissionGrantRepository.FindAsync("MyPermission2", "Test", - "Test")).ShouldNotBeNull(); + "Test").ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] @@ -101,8 +101,23 @@ namespace Volo.Abp.PermissionManagement "MyPermission1NotExist", "Test", "Test", - true)); + true).ConfigureAwait(false)).ConfigureAwait(false); } + [Fact] + public async Task UpdateProviderKey() + { + await _permissionGrantRepository.InsertAsync(new PermissionGrant( + Guid.NewGuid(), + "MyPermission1", + "Test", + "Test") + ).ConfigureAwait(false); + var permissionGrant = await _permissionGrantRepository.FindAsync("MyPermission1", "Test", "Test").ConfigureAwait(false); + permissionGrant.ProviderKey.ShouldBe("Test"); + + await _permissionManager.UpdateProviderKeyAsync(permissionGrant, "NewProviderKey").ConfigureAwait(false); + (await _permissionGrantRepository.FindAsync("MyPermission1", "Test", "NewProviderKey").ConfigureAwait(false)).ShouldNotBeNull(); + } } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs index 965899ede9..f82b541e27 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs @@ -22,12 +22,12 @@ namespace Volo.Abp.PermissionManagement { (await _permissionStore.IsGrantedAsync("MyPermission1", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString())).ShouldBeTrue(); + PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false)).ShouldBeTrue(); (await _permissionStore.IsGrantedAsync("MyPermission1NotExist", UserPermissionValueProvider.ProviderName, - PermissionTestDataBuilder.User1Id.ToString())).ShouldBeFalse(); + PermissionTestDataBuilder.User1Id.ToString()).ConfigureAwait(false)).ShouldBeFalse(); } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json index a0357eda0c..0cdb16d2d4 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/cs.json @@ -1,6 +1,7 @@ { "culture": "cs", "texts": { - "Settings": "Nastavení" + "Settings": "Nastavení", + "SuccessfullySaved": "Úspěšně uloženo" } } \ No newline at end of file diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json new file mode 100644 index 0000000000..f8f55c38cb --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "Settings": "設置", + "SuccessfullySaved": "保存成功" + } +} \ No newline at end of file diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs index a590775167..3511df204d 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs @@ -1,8 +1,10 @@ using System; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.SettingManagement { [Serializable] + [IgnoreMultiTenancy] public class SettingCacheItem { public string Value { get; set; } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs index 35d358a67d..419d0febcd 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.SettingManagement eventData.Entity.ProviderKey ); - await Cache.RemoveAsync(cacheKey); + await Cache.RemoveAsync(cacheKey).ConfigureAwait(false); } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs index 2859b2e7f4..b7410490f5 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs @@ -17,17 +17,17 @@ namespace Volo.Abp.SettingManagement public async Task GetOrNullAsync(SettingDefinition setting, string providerKey) { - return await SettingManagementStore.GetOrNullAsync(setting.Name, Name, NormalizeProviderKey(providerKey)); + return await SettingManagementStore.GetOrNullAsync(setting.Name, Name, NormalizeProviderKey(providerKey)).ConfigureAwait(false); } public virtual async Task SetAsync(SettingDefinition setting, string value, string providerKey) { - await SettingManagementStore.SetAsync(setting.Name, value, Name, NormalizeProviderKey(providerKey)); + await SettingManagementStore.SetAsync(setting.Name, value, Name, NormalizeProviderKey(providerKey)).ConfigureAwait(false); } public virtual async Task ClearAsync(SettingDefinition setting, string providerKey) { - await SettingManagementStore.DeleteAsync(setting.Name, Name, NormalizeProviderKey(providerKey)); + await SettingManagementStore.DeleteAsync(setting.Name, Name, NormalizeProviderKey(providerKey)).ConfigureAwait(false); } protected virtual string NormalizeProviderKey(string providerKey) diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs index 8c9cfc8684..622ea4a705 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs @@ -26,58 +26,58 @@ namespace Volo.Abp.SettingManagement public async Task GetOrNullAsync(string name, string providerName, string providerKey) { - var cacheItem = await GetCacheItemAsync(name, providerName, providerKey); + var cacheItem = await GetCacheItemAsync(name, providerName, providerKey).ConfigureAwait(false); return cacheItem.Value; } public async Task SetAsync(string name, string value, string providerName, string providerKey) { - var setting = await SettingRepository.FindAsync(name, providerName, providerKey); + var setting = await SettingRepository.FindAsync(name, providerName, providerKey).ConfigureAwait(false); if (setting == null) { setting = new Setting(GuidGenerator.Create(), name, value, providerName, providerKey); - await SettingRepository.InsertAsync(setting); + await SettingRepository.InsertAsync(setting).ConfigureAwait(false); } else { setting.Value = value; - await SettingRepository.UpdateAsync(setting); + await SettingRepository.UpdateAsync(setting).ConfigureAwait(false); } } public async Task> GetListAsync(string providerName, string providerKey) { - var settings = await SettingRepository.GetListAsync(providerName, providerKey); + var settings = await SettingRepository.GetListAsync(providerName, providerKey).ConfigureAwait(false); return settings.Select(s => new SettingValue(s.Name, s.Value)).ToList(); } public async Task DeleteAsync(string name, string providerName, string providerKey) { - var setting = await SettingRepository.FindAsync(name, providerName, providerKey); + var setting = await SettingRepository.FindAsync(name, providerName, providerKey).ConfigureAwait(false); if (setting != null) { - await SettingRepository.DeleteAsync(setting); + await SettingRepository.DeleteAsync(setting).ConfigureAwait(false); } } protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey) { var cacheKey = CalculateCacheKey(name, providerName, providerKey); - var cacheItem = await Cache.GetAsync(cacheKey); + var cacheItem = await Cache.GetAsync(cacheKey).ConfigureAwait(false); if (cacheItem != null) { return cacheItem; } - var setting = await SettingRepository.FindAsync(name, providerName, providerKey); + var setting = await SettingRepository.FindAsync(name, providerName, providerKey).ConfigureAwait(false); cacheItem = new SettingCacheItem(setting?.Value); await Cache.SetAsync( cacheKey, cacheItem - ); + ).ConfigureAwait(false); return cacheItem; } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs index cfb4cccbe3..e5cdcb4466 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs @@ -79,7 +79,7 @@ namespace Volo.Abp.SettingManagement var providerValue = await provider.GetOrNullAsync( setting, provider.Name == providerName ? providerKey : null - ); + ).ConfigureAwait(false); if (providerValue != null) { value = providerValue; @@ -91,7 +91,7 @@ namespace Volo.Abp.SettingManagement value = await providerList[0].GetOrNullAsync( setting, providerKey - ); + ).ConfigureAwait(false); } if (setting.IsEncrypted) @@ -132,7 +132,7 @@ namespace Volo.Abp.SettingManagement if (providers.Count > 1 && !forceToSet && setting.IsInherited && value != null) { - var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null); + var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null).ConfigureAwait(false); if (fallbackValue == value) { //Clear the value if it's same as it's fallback value @@ -148,14 +148,14 @@ namespace Volo.Abp.SettingManagement { foreach (var provider in providers) { - await provider.ClearAsync(setting, providerKey); + await provider.ClearAsync(setting, providerKey).ConfigureAwait(false); } } else { foreach (var provider in providers) { - await provider.SetAsync(setting, value, providerKey); + await provider.SetAsync(setting, value, providerKey).ConfigureAwait(false); } } } @@ -182,7 +182,7 @@ namespace Volo.Abp.SettingManagement value = await provider.GetOrNullAsync( setting, provider.Name == providerName ? providerKey : null - ); + ).ConfigureAwait(false); if (value != null) { diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo.Abp.SettingManagement.EntityFrameworkCore.csproj b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo.Abp.SettingManagement.EntityFrameworkCore.csproj index f5e1761cc5..c76680e887 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo.Abp.SettingManagement.EntityFrameworkCore.csproj +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo.Abp.SettingManagement.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.SettingManagement.EntityFrameworkCore Volo.Abp.SettingManagement.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs index 86b31036d1..bd848ce076 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore return await DbSet .FirstOrDefaultAsync( s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey - ); + ).ConfigureAwait(false); } public async Task> GetListAsync(string providerName, string providerKey) @@ -28,7 +28,7 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore return await DbSet .Where( s => s.ProviderName == providerName && s.ProviderKey == providerKey - ).ToListAsync(); + ).ToListAsync().ConfigureAwait(false); } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs index 56516dcbd0..e08c099eaa 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs @@ -18,12 +18,12 @@ namespace Volo.Abp.SettingManagement.MongoDB public async Task FindAsync(string name, string providerName, string providerKey) { - return await GetMongoQueryable().FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); + return await GetMongoQueryable().FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ConfigureAwait(false); } public async Task> GetListAsync(string providerName, string providerKey) { - return await GetMongoQueryable().Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); + return await GetMongoQueryable().Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync().ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs index 8aee74c56c..1dc8030bd8 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.SettingManagement.Web.Navigation var settingPageCreationContext = new SettingPageCreationContext(context.ServiceProvider); if ( !settingManagementPageOptions.Contributors.Any() || - !(await CheckAnyOfPagePermissionsGranted(settingManagementPageOptions, settingPageCreationContext)) + !(await CheckAnyOfPagePermissionsGranted(settingManagementPageOptions, settingPageCreationContext).ConfigureAwait(false)) ) { return; @@ -49,7 +49,7 @@ namespace Volo.Abp.SettingManagement.Web.Navigation { foreach (var contributor in settingManagementPageOptions.Contributors) { - if (await contributor.CheckPermissionsAsync(settingPageCreationContext)) + if (await contributor.CheckPermissionsAsync(settingPageCreationContext).ConfigureAwait(false)) { return true; } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml index 88645ad20e..7a4a36ed6a 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml @@ -19,14 +19,17 @@
    - + @foreach (var group in Model.SettingPageCreationContext.Groups) { - +

    @group.DisplayName


    - @await Component.InvokeAsync(group.ComponentType) + @await Component.InvokeAsync(group.ComponentType, new + { + parameter = group.Parameter + })
    }
    diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml.cs index 1fdba05707..401d845039 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.SettingManagement.Web.Pages.SettingManagement foreach (var contributor in _options.Contributors) { - await contributor.ConfigureAsync(SettingPageCreationContext); + await contributor.ConfigureAsync(SettingPageCreationContext).ConfigureAwait(false); } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/SettingPageGroup.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/SettingPageGroup.cs index 5acd284267..f6fae8726d 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/SettingPageGroup.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/SettingPageGroup.cs @@ -26,11 +26,14 @@ namespace Volo.Abp.SettingManagement.Web.Pages.SettingManagement } private Type _componentType; - public SettingPageGroup([NotNull] string id, [NotNull] string displayName, [NotNull] Type componentType) + public object Parameter { get; set; } + + public SettingPageGroup([NotNull] string id, [NotNull] string displayName, [NotNull] Type componentType, object parameter = null) { Id = id; DisplayName = displayName; ComponentType = componentType; + Parameter = parameter; } } } \ No newline at end of file diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests.csproj b/modules/setting-management/test/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests.csproj index a6ddba5616..1a04328983 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests.csproj +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests/Volo.Abp.SettingManagement.EntityFrameworkCore.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo.Abp.SettingManagement.MongoDB.Tests.csproj b/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo.Abp.SettingManagement.MongoDB.Tests.csproj index 8a1c723db4..791758698d 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo.Abp.SettingManagement.MongoDB.Tests.csproj +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.MongoDB.Tests/Volo.Abp.SettingManagement.MongoDB.Tests.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo.Abp.SettingManagement.TestBase.csproj b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo.Abp.SettingManagement.TestBase.csproj index bfa3355d60..75f44e1ca3 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo.Abp.SettingManagement.TestBase.csproj +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo.Abp.SettingManagement.TestBase.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/AbpSettingManagementTestBaseModule.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/AbpSettingManagementTestBaseModule.cs index 7d90dcd747..058bd8ff49 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/AbpSettingManagementTestBaseModule.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/AbpSettingManagementTestBaseModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.Autofac; using Volo.Abp.Modularity; using Volo.Abp.Settings; +using Volo.Abp.Threading; namespace Volo.Abp.SettingManagement { @@ -20,9 +21,9 @@ namespace Volo.Abp.SettingManagement { using (var scope = context.ServiceProvider.CreateScope()) { - scope.ServiceProvider + AsyncHelper.RunSync(()=> scope.ServiceProvider .GetRequiredService() - .Build(); + .BuildAsync()); } } } diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingManagementTestBase.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingManagementTestBase.cs index c6deeba0fc..002c1b95da 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingManagementTestBase.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingManagementTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.SettingManagement { diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs index 5dad99a0ca..6d8be6fe8a 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs @@ -26,25 +26,25 @@ namespace Volo.Abp.SettingManagement "MySetting1", GlobalSettingValueProvider.ProviderName, null - )).Value.ShouldBe("42"); + ).ConfigureAwait(false)).Value.ShouldBe("42"); (await SettingRepository.FindAsync( "MySetting2", UserSettingValueProvider.ProviderName, TestData.User1Id.ToString() - )).Value.ShouldBe("user1-store-value"); + ).ConfigureAwait(false)).Value.ShouldBe("user1-store-value"); (await SettingRepository.FindAsync( "Undefined-Setting", GlobalSettingValueProvider.ProviderName, null - )).ShouldBeNull(); + ).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task GetListAsync() { - var settings = await SettingRepository.GetListAsync(GlobalSettingValueProvider.ProviderName, null); + var settings = await SettingRepository.GetListAsync(GlobalSettingValueProvider.ProviderName, null).ConfigureAwait(false); settings.Any().ShouldBeTrue(); settings.ShouldContain(s => s.Name == "MySetting1" && s.Value == "42"); settings.ShouldContain(s => s.Name == "MySetting2" && s.Value == "default-store-value"); diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingTestDataBuilder.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingTestDataBuilder.cs index 6843d6257e..d89111bd82 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingTestDataBuilder.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingTestDataBuilder.cs @@ -1,4 +1,5 @@ -using Volo.Abp.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.Settings; @@ -20,27 +21,27 @@ namespace Volo.Abp.SettingManagement _testData = testData; } - public void Build() + public async Task BuildAsync() { - _settingRepository.Insert( + await _settingRepository.InsertAsync( new Setting( _testData.SettingId, "MySetting1", "42", GlobalSettingValueProvider.ProviderName ) - ); + ).ConfigureAwait(false); - _settingRepository.Insert( + await _settingRepository.InsertAsync( new Setting( _guidGenerator.Create(), "MySetting2", "default-store-value", GlobalSettingValueProvider.ProviderName ) - ); + ).ConfigureAwait(false); - _settingRepository.Insert( + await _settingRepository.InsertAsync( new Setting( _guidGenerator.Create(), "MySetting2", @@ -48,9 +49,9 @@ namespace Volo.Abp.SettingManagement UserSettingValueProvider.ProviderName, _testData.User1Id.ToString() ) - ); + ).ConfigureAwait(false); - _settingRepository.Insert( + await _settingRepository.InsertAsync( new Setting( _guidGenerator.Create(), "MySetting2", @@ -58,18 +59,18 @@ namespace Volo.Abp.SettingManagement UserSettingValueProvider.ProviderName, _testData.User2Id.ToString() ) - ); + ).ConfigureAwait(false); - _settingRepository.Insert( + await _settingRepository.InsertAsync( new Setting( _guidGenerator.Create(), "MySettingWithoutInherit", "default-store-value", GlobalSettingValueProvider.ProviderName ) - ); + ).ConfigureAwait(false); - _settingRepository.Insert( + await _settingRepository.InsertAsync( new Setting( _guidGenerator.Create(), "MySettingWithoutInherit", @@ -77,7 +78,7 @@ namespace Volo.Abp.SettingManagement UserSettingValueProvider.ProviderName, _testData.User1Id.ToString() ) - ); + ).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo.Abp.SettingManagement.Tests.csproj b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo.Abp.SettingManagement.Tests.csproj index f358429196..7f99e1ae2c 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo.Abp.SettingManagement.Tests.csproj +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo.Abp.SettingManagement.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/DefaultValueSettingManagementProvider_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/DefaultValueSettingManagementProvider_Tests.cs index 20263a73c9..216ebf6283 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/DefaultValueSettingManagementProvider_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/DefaultValueSettingManagementProvider_Tests.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.SettingManagement var defaultValueSettingManagementProvider = new DefaultValueSettingManagementProvider(); (await defaultValueSettingManagementProvider - .GetOrNullAsync(mySetting3, DefaultValueSettingValueProvider.ProviderName)).ShouldBe("123"); + .GetOrNullAsync(mySetting3, DefaultValueSettingValueProvider.ProviderName).ConfigureAwait(false)).ShouldBe("123"); } [Fact] @@ -30,7 +30,7 @@ namespace Volo.Abp.SettingManagement var mySetting3 = _settingDefinitionManager.Get("MySetting3"); await Assert.ThrowsAsync(async () => await new DefaultValueSettingManagementProvider().SetAsync(mySetting3, "123", - DefaultValueSettingValueProvider.ProviderName)); + DefaultValueSettingValueProvider.ProviderName).ConfigureAwait(false)).ConfigureAwait(false); } [Fact] @@ -40,7 +40,7 @@ namespace Volo.Abp.SettingManagement await Assert.ThrowsAsync(async () => await new DefaultValueSettingManagementProvider().ClearAsync(mySetting3, - DefaultValueSettingValueProvider.ProviderName)); + DefaultValueSettingValueProvider.ProviderName).ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItemInvalidator_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItemInvalidator_Tests.cs index 2a458a1739..cf2c610b79 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItemInvalidator_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItemInvalidator_Tests.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System; using System.Threading.Tasks; -using Castle.DynamicProxy.Generators; using Shouldly; using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; using Xunit; @@ -16,6 +14,7 @@ namespace Volo.Abp.SettingManagement private readonly ISettingManagementStore _settingManagementStore; private readonly ISettingRepository _settingRepository; private readonly SettingTestData _testData; + private readonly ICurrentTenant _currentTenant; public SettingCacheItemInvalidator_Tests() { @@ -23,15 +22,16 @@ namespace Volo.Abp.SettingManagement _cache = GetRequiredService>(); _settingRepository = GetRequiredService(); _testData = GetRequiredService(); + _currentTenant = GetRequiredService(); } [Fact] public async Task GetOrNullAsync_Should_Cached() { // Act - (await _cache.GetAsync(SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()))).ShouldBeNull(); - await _settingManagementStore.GetOrNullAsync("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()); - (await _cache.GetAsync(SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()))).ShouldNotBeNull(); + (await _cache.GetAsync(SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString())).ConfigureAwait(false)).ShouldBeNull(); + await _settingManagementStore.GetOrNullAsync("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()).ConfigureAwait(false); + (await _cache.GetAsync(SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString())).ConfigureAwait(false)).ShouldNotBeNull(); } [Fact] @@ -39,15 +39,45 @@ namespace Volo.Abp.SettingManagement { // Arrange // GetOrNullAsync will cache language. - await _settingManagementStore.GetOrNullAsync("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()); + await _settingManagementStore.GetOrNullAsync("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()).ConfigureAwait(false); // Act - var lang = await _settingRepository.FindAsync("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()); - await _settingRepository.DeleteAsync(lang); + var lang = await _settingRepository.FindAsync("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()).ConfigureAwait(false); + await _settingRepository.DeleteAsync(lang).ConfigureAwait(false); // Assert (await _cache.GetAsync( - SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString()))).ShouldBeNull(); + SettingCacheItem.CalculateCacheKey("MySetting2", UserSettingValueProvider.ProviderName, _testData.User1Id.ToString())).ConfigureAwait(false)).ShouldBeNull(); + } + + [Fact] + public async Task Cache_Should_Invalidator_WhenSettingChanged_Between_Tenant_And_Host() + { + var tenantId = Guid.NewGuid(); + + using (_currentTenant.Change(tenantId)) + { + // GetOrNullAsync will cache language. + await _settingManagementStore + .GetOrNullAsync("MySetting2", GlobalSettingValueProvider.ProviderName, null) + .ConfigureAwait(false); + } + + using (_currentTenant.Change(null)) + { + // SetAsync will make cache invalid. + await _settingManagementStore + .SetAsync("MySetting2", "MySetting2Value", GlobalSettingValueProvider.ProviderName, null) + .ConfigureAwait(false); + } + + using (_currentTenant.Change(tenantId)) + { + // Assert + (await _cache.GetAsync( + SettingCacheItem.CalculateCacheKey("MySetting2", GlobalSettingValueProvider.ProviderName, null)) + .ConfigureAwait(false)).ShouldBeNull(); + } } } } diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs index 753ba15054..99ca9e70da 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.SettingManagement public async Task GetOrNull_NotExist_Should_Be_Null() { var value = await _settingManagementStore.GetOrNullAsync("notExistName", "notExistProviderName", - "notExistProviderKey"); + "notExistProviderKey").ConfigureAwait(false); value.ShouldBeNull(); } @@ -33,7 +33,7 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task GetOrNullAsync() { - var value = await _settingManagementStore.GetOrNullAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null); + var value = await _settingManagementStore.GetOrNullAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null).ConfigureAwait(false); value.ShouldNotBeNull(); value.ShouldBe("42"); @@ -42,22 +42,22 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task SetAsync() { - var setting = await _settingRepository.FindAsync(_testData.SettingId); + var setting = await _settingRepository.FindAsync(_testData.SettingId).ConfigureAwait(false); setting.Value.ShouldBe("42"); - await _settingManagementStore.SetAsync("MySetting1", "43", GlobalSettingValueProvider.ProviderName, null); + await _settingManagementStore.SetAsync("MySetting1", "43", GlobalSettingValueProvider.ProviderName, null).ConfigureAwait(false); - (await _settingRepository.FindAsync(_testData.SettingId)).Value.ShouldBe("43"); + (await _settingRepository.FindAsync(_testData.SettingId).ConfigureAwait(false)).Value.ShouldBe("43"); } [Fact] public async Task DeleteAsync() { - (await _settingRepository.FindAsync(_testData.SettingId)).ShouldNotBeNull(); + (await _settingRepository.FindAsync(_testData.SettingId).ConfigureAwait(false)).ShouldNotBeNull(); - await _settingManagementStore.DeleteAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null); + await _settingManagementStore.DeleteAsync("MySetting1", GlobalSettingValueProvider.ProviderName, null).ConfigureAwait(false); - (await _settingRepository.FindAsync(_testData.SettingId)).ShouldBeNull(); + (await _settingRepository.FindAsync(_testData.SettingId).ConfigureAwait(false)).ShouldBeNull(); } } diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs index 1dafc31570..b9efa5640f 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_Basic_Tests.cs @@ -21,26 +21,26 @@ namespace Volo.Abp.SettingManagement { await Assert.ThrowsAsync( async () => await _settingProvider.GetOrNullAsync("UndefinedSetting") - ); +.ConfigureAwait(false)).ConfigureAwait(false); } [Fact] public async Task Should_Get_Default_Value_If_Not_Set_In_Store() { - var value = await _settingProvider.GetOrNullAsync("SettingNotSetInStore"); + var value = await _settingProvider.GetOrNullAsync("SettingNotSetInStore").ConfigureAwait(false); value.ShouldBe("default-value"); } [Fact] public async Task Should_Get_Base_Store_Value() { - (await _settingProvider.GetOrNullAsync("MySetting1")).ShouldBe("42"); + (await _settingProvider.GetOrNullAsync("MySetting1").ConfigureAwait(false)).ShouldBe("42"); } [Fact] public async Task Should_Get_All_Base_Store_Values() { - var settingValues = await _settingProvider.GetAllAsync(); + var settingValues = await _settingProvider.GetAllAsync().ConfigureAwait(false); settingValues.ShouldContain(sv => sv.Name == "MySetting1" && sv.Value == "42"); settingValues.ShouldContain(sv => sv.Name == "MySetting2" && sv.Value == "default-store-value"); settingValues.ShouldContain(sv => sv.Name == "SettingNotSetInStore" && sv.Value == "default-value"); @@ -49,10 +49,10 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task Should_Set_Global_Value() { - await _settingManager.SetGlobalAsync("MySetting1", "43"); + await _settingManager.SetGlobalAsync("MySetting1", "43").ConfigureAwait(false); - (await _settingManager.GetOrNullGlobalAsync("MySetting1")).ShouldBe("43"); - (await _settingProvider.GetOrNullAsync("MySetting1")).ShouldBe("43"); + (await _settingManager.GetOrNullGlobalAsync("MySetting1").ConfigureAwait(false)).ShouldBe("43"); + (await _settingProvider.GetOrNullAsync("MySetting1").ConfigureAwait(false)).ShouldBe("43"); } } } diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_User_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_User_Tests.cs index 4b42572f0a..d49ca823f1 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_User_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManager_User_Tests.cs @@ -35,67 +35,67 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task Should_Get_From_Store_For_Given_User() { - (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id)).ShouldBe("user1-store-value"); - (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User2Id)).ShouldBe("user2-store-value"); + (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id).ConfigureAwait(false)).ShouldBe("user1-store-value"); + (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User2Id).ConfigureAwait(false)).ShouldBe("user2-store-value"); } [Fact] public async Task Should_Fallback_To_Default_Store_Value_When_No_Value_For_Given_User() { - (await _settingManager.GetOrNullForUserAsync("MySetting2", Guid.NewGuid())).ShouldBe("default-store-value"); + (await _settingManager.GetOrNullForUserAsync("MySetting2", Guid.NewGuid()).ConfigureAwait(false)).ShouldBe("default-store-value"); } [Fact] public async Task Should_Not_Fallback_To_Default_Store_Value_When_No_Value_For_Given_User_But_Specified_Fallback_As_False() { - (await _settingManager.GetOrNullForUserAsync("MySetting2", Guid.NewGuid(), fallback: false)).ShouldBeNull(); + (await _settingManager.GetOrNullForUserAsync("MySetting2", Guid.NewGuid(), fallback: false).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task Should_Get_From_Store_For_Current_User() { _currentUserId = _testData.User1Id; - (await _settingProvider.GetOrNullAsync("MySetting2")).ShouldBe("user1-store-value"); + (await _settingProvider.GetOrNullAsync("MySetting2").ConfigureAwait(false)).ShouldBe("user1-store-value"); _currentUserId = _testData.User2Id; - (await _settingProvider.GetOrNullAsync("MySetting2")).ShouldBe("user2-store-value"); + (await _settingProvider.GetOrNullAsync("MySetting2").ConfigureAwait(false)).ShouldBe("user2-store-value"); } [Fact] public async Task Should_Fallback_To_Default_Store_Value_When_No_Value_For_Current_User() { _currentUserId = Guid.NewGuid(); - (await _settingProvider.GetOrNullAsync("MySetting2")).ShouldBe("default-store-value"); + (await _settingProvider.GetOrNullAsync("MySetting2").ConfigureAwait(false)).ShouldBe("default-store-value"); } [Fact] public async Task Should_Get_From_Store_For_Current_User_With_GetOrNullForCurrentUserAsync() { _currentUserId = _testData.User1Id; - (await _settingManager.GetOrNullForCurrentUserAsync("MySetting2")).ShouldBe("user1-store-value"); + (await _settingManager.GetOrNullForCurrentUserAsync("MySetting2").ConfigureAwait(false)).ShouldBe("user1-store-value"); _currentUserId = _testData.User2Id; - (await _settingManager.GetOrNullForCurrentUserAsync("MySetting2")).ShouldBe("user2-store-value"); + (await _settingManager.GetOrNullForCurrentUserAsync("MySetting2").ConfigureAwait(false)).ShouldBe("user2-store-value"); } [Fact] public async Task Should_Fallback_To_Default_Store_Value_When_No_Value_For_Current_User_With_GetOrNullForCurrentUserAsync() { _currentUserId = Guid.NewGuid(); - (await _settingProvider.GetOrNullAsync("MySetting2")).ShouldBe("default-store-value"); + (await _settingProvider.GetOrNullAsync("MySetting2").ConfigureAwait(false)).ShouldBe("default-store-value"); } [Fact] public async Task Should_Not_Fallback_To_Default_Store_Value_When_No_Value_For_Current_User_But_Specified_Fallback_As_False() { _currentUserId = Guid.NewGuid(); - (await _settingManager.GetOrNullForCurrentUserAsync("MySetting2", fallback: false)).ShouldBeNull(); + (await _settingManager.GetOrNullForCurrentUserAsync("MySetting2", fallback: false).ConfigureAwait(false)).ShouldBeNull(); } [Fact] public async Task Should_Get_All_From_Store_For_Given_User() { - var settingValues = await _settingManager.GetAllForUserAsync(_testData.User1Id); + var settingValues = await _settingManager.GetAllForUserAsync(_testData.User1Id).ConfigureAwait(false); settingValues.ShouldContain(sv => sv.Name == "MySetting1" && sv.Value == "42"); settingValues.ShouldContain(sv => sv.Name == "MySetting2" && sv.Value == "user1-store-value"); settingValues.ShouldContain(sv => sv.Name == "SettingNotSetInStore" && sv.Value == "default-value"); @@ -104,7 +104,7 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task Should_Get_All_From_Store_For_Given_User_Without_Fallback() { - var settingValues = await _settingManager.GetAllForUserAsync(_testData.User1Id, fallback: false); + var settingValues = await _settingManager.GetAllForUserAsync(_testData.User1Id, fallback: false).ConfigureAwait(false); settingValues.ShouldContain(sv => sv.Name == "MySetting2" && sv.Value == "user1-store-value"); settingValues.ShouldContain(sv => sv.Name == "MySettingWithoutInherit" && sv.Value == "user1-store-value"); settingValues.ShouldNotContain(sv => sv.Name == "MySetting1"); @@ -113,7 +113,7 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task Should_Delete_Setting_Record_When_Set_To_Null() { - await _settingManager.SetForUserAsync(_testData.User1Id, "MySetting2", null); + await _settingManager.SetForUserAsync(_testData.User1Id, "MySetting2", null).ConfigureAwait(false); GetSettingsFromDbContext( UserSettingValueProvider.ProviderName, @@ -125,12 +125,12 @@ namespace Volo.Abp.SettingManagement [Fact] public async Task Should_Change_User_Setting() { - (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id)) + (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id).ConfigureAwait(false)) .ShouldBe("user1-store-value"); - await _settingManager.SetForUserAsync(_testData.User1Id, "MySetting2", "user1-new-store-value"); + await _settingManager.SetForUserAsync(_testData.User1Id, "MySetting2", "user1-new-store-value").ConfigureAwait(false); - (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id)) + (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id).ConfigureAwait(false)) .ShouldBe("user1-new-store-value"); GetSettingsFromDbContext( @@ -147,7 +147,7 @@ namespace Volo.Abp.SettingManagement _testData.User1Id, "MySetting2", "default-store-value" - ); + ).ConfigureAwait(false); GetSettingsFromDbContext( UserSettingValueProvider.ProviderName, @@ -155,7 +155,7 @@ namespace Volo.Abp.SettingManagement "MySetting2" ).Count.ShouldBe(0); - (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id)) + (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id).ConfigureAwait(false)) .ShouldBe("default-store-value"); } @@ -167,7 +167,7 @@ namespace Volo.Abp.SettingManagement "MySetting2", "default-store-value", forceToSet: true - ); + ).ConfigureAwait(false); GetSettingsFromDbContext( UserSettingValueProvider.ProviderName, @@ -175,16 +175,16 @@ namespace Volo.Abp.SettingManagement "MySetting2" ).Single().Value.ShouldBe("default-store-value"); - (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id)) + (await _settingManager.GetOrNullForUserAsync("MySetting2", _testData.User1Id).ConfigureAwait(false)) .ShouldBe("default-store-value"); } [Fact] public async Task Should_Get_For_Given_User_For_Non_Inherited_Setting() { - (await _settingManager.GetOrNullForUserAsync("MySettingWithoutInherit", _testData.User1Id)).ShouldBe("user1-store-value"); - (await _settingManager.GetOrNullForUserAsync("MySettingWithoutInherit", _testData.User2Id)).ShouldBeNull(); //Does not inherit! - (await _settingManager.GetOrNullGlobalAsync("MySettingWithoutInherit")).ShouldBe("default-store-value"); + (await _settingManager.GetOrNullForUserAsync("MySettingWithoutInherit", _testData.User1Id).ConfigureAwait(false)).ShouldBe("user1-store-value"); + (await _settingManager.GetOrNullForUserAsync("MySettingWithoutInherit", _testData.User2Id).ConfigureAwait(false)).ShouldBeNull(); //Does not inherit! + (await _settingManager.GetOrNullGlobalAsync("MySettingWithoutInherit").ConfigureAwait(false)).ShouldBe("default-store-value"); } } } \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Application/Volo/Abp/TenantManagement/TenantAppService.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Application/Volo/Abp/TenantManagement/TenantAppService.cs index b8a0d827ed..084c6c1920 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Application/Volo/Abp/TenantManagement/TenantAppService.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Application/Volo/Abp/TenantManagement/TenantAppService.cs @@ -27,14 +27,13 @@ namespace Volo.Abp.TenantManagement public virtual async Task GetAsync(Guid id) { return ObjectMapper.Map( - await TenantRepository.GetAsync(id) - ); + await TenantRepository.GetAsync(id).ConfigureAwait(false)); } public virtual async Task> GetListAsync(GetTenantsInput input) { - var count = await TenantRepository.GetCountAsync(input.Filter); - var list = await TenantRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter); + var count = await TenantRepository.GetCountAsync(input.Filter).ConfigureAwait(false); + var list = await TenantRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter).ConfigureAwait(false); return new PagedResultDto( count, @@ -45,15 +44,15 @@ namespace Volo.Abp.TenantManagement [Authorize(TenantManagementPermissions.Tenants.Create)] public virtual async Task CreateAsync(TenantCreateDto input) { - var tenant = await TenantManager.CreateAsync(input.Name); - await TenantRepository.InsertAsync(tenant); + var tenant = await TenantManager.CreateAsync(input.Name).ConfigureAwait(false); + await TenantRepository.InsertAsync(tenant).ConfigureAwait(false); using (CurrentTenant.Change(tenant.Id, tenant.Name)) { //TODO: Handle database creation? //TODO: Set admin email & password..? - await DataSeeder.SeedAsync(tenant.Id); + await DataSeeder.SeedAsync(tenant.Id).ConfigureAwait(false); } return ObjectMapper.Map(tenant); @@ -62,45 +61,45 @@ namespace Volo.Abp.TenantManagement [Authorize(TenantManagementPermissions.Tenants.Update)] public virtual async Task UpdateAsync(Guid id, TenantUpdateDto input) { - var tenant = await TenantRepository.GetAsync(id); - await TenantManager.ChangeNameAsync(tenant, input.Name); - await TenantRepository.UpdateAsync(tenant); + var tenant = await TenantRepository.GetAsync(id).ConfigureAwait(false); + await TenantManager.ChangeNameAsync(tenant, input.Name).ConfigureAwait(false); + await TenantRepository.UpdateAsync(tenant).ConfigureAwait(false); return ObjectMapper.Map(tenant); } [Authorize(TenantManagementPermissions.Tenants.Delete)] public virtual async Task DeleteAsync(Guid id) { - var tenant = await TenantRepository.FindAsync(id); + var tenant = await TenantRepository.FindAsync(id).ConfigureAwait(false); if (tenant == null) { return; } - await TenantRepository.DeleteAsync(tenant); + await TenantRepository.DeleteAsync(tenant).ConfigureAwait(false); } [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] public virtual async Task GetDefaultConnectionStringAsync(Guid id) { - var tenant = await TenantRepository.GetAsync(id); + var tenant = await TenantRepository.GetAsync(id).ConfigureAwait(false); return tenant?.FindDefaultConnectionString(); } [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] public virtual async Task UpdateDefaultConnectionStringAsync(Guid id, string defaultConnectionString) { - var tenant = await TenantRepository.GetAsync(id); + var tenant = await TenantRepository.GetAsync(id).ConfigureAwait(false); tenant.SetDefaultConnectionString(defaultConnectionString); - await TenantRepository.UpdateAsync(tenant); + await TenantRepository.UpdateAsync(tenant).ConfigureAwait(false); } [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] public virtual async Task DeleteDefaultConnectionStringAsync(Guid id) { - var tenant = await TenantRepository.GetAsync(id); + var tenant = await TenantRepository.GetAsync(id).ConfigureAwait(false); tenant.RemoveDefaultConnectionString(); - await TenantRepository.UpdateAsync(tenant); + await TenantRepository.UpdateAsync(tenant).ConfigureAwait(false); } } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo.Abp.TenantManagement.Domain.Shared.csproj b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo.Abp.TenantManagement.Domain.Shared.csproj index dec1cabd46..5cdaa28369 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo.Abp.TenantManagement.Domain.Shared.csproj +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo.Abp.TenantManagement.Domain.Shared.csproj @@ -19,7 +19,7 @@ - + diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs index 2058ae5425..158a78b0cb 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs @@ -1,11 +1,13 @@ using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; using Volo.Abp.TenantManagement.Localization; +using Volo.Abp.Validation; +using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.TenantManagement { + [DependsOn(typeof(AbpValidationModule))] public class AbpTenantManagementDomainSharedModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..858d7d6f9b --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json @@ -0,0 +1,20 @@ +{ + "culture": "zh-Hant", + "texts": { + "Menu:TenantManagement": "租戶管理", + "Tenants": "租戶", + "NewTenant": "新租戶", + "TenantName": "租戶名稱", + "DisplayName:TenantName": "租戶名稱", + "TenantDeletionConfirmationMessage": "租戶 '{0}' 將被刪除. 您確定嗎?", + "ConnectionStrings": "資料庫連線字串", + "DisplayName:DefaultConnectionString": "預設資料庫連線字串", + "DisplayName:UseSharedDatabase": "使用共用資料庫", + "Permission:TenantManagement": "租戶管理", + "Permission:Create": "新增", + "Permission:Edit": "編輯", + "Permission:Delete": "刪除", + "Permission:ManageConnectionStrings": "管理資料庫連線字串", + "Permission:ManageFeatures": "管理功能" + } +} \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs index d8725bf6cf..1feca866a2 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs @@ -18,6 +18,11 @@ namespace Volo.Abp.TenantManagement bool includeDetails = true ); + Tenant FindById( + Guid id, + bool includeDetails = true + ); + Task> GetListAsync( string sorting = null, int maxResultCount = int.MaxValue, diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs index 79d7cf891e..fbc422c31a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.TenantManagement { Check.NotNull(name, nameof(name)); - await ValidateNameAsync(name); + await ValidateNameAsync(name).ConfigureAwait(false); return new Tenant(GuidGenerator.Create(), name); } @@ -28,13 +28,13 @@ namespace Volo.Abp.TenantManagement Check.NotNull(tenant, nameof(tenant)); Check.NotNull(name, nameof(name)); - await ValidateNameAsync(name, tenant.Id); + await ValidateNameAsync(name, tenant.Id).ConfigureAwait(false); tenant.SetName(name); } protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null) { - var tenant = await _tenantRepository.FindByNameAsync(name); + var tenant = await _tenantRepository.FindByNameAsync(name).ConfigureAwait(false); if (tenant != null && tenant.Id != expectedId) { throw new UserFriendlyException("Duplicate tenancy name: " + name); //TODO: A domain exception would be better..? diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs index cc0788d634..234f23959a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.TenantManagement { using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! { - var tenant = await _tenantRepository.FindByNameAsync(name); + var tenant = await _tenantRepository.FindByNameAsync(name).ConfigureAwait(false); if (tenant == null) { return null; @@ -42,7 +42,7 @@ namespace Volo.Abp.TenantManagement { using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! { - var tenant = await _tenantRepository.FindAsync(id); + var tenant = await _tenantRepository.FindAsync(id).ConfigureAwait(false); if (tenant == null) { return null; @@ -70,7 +70,7 @@ namespace Volo.Abp.TenantManagement { using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! { - var tenant = _tenantRepository.Find(id); + var tenant = _tenantRepository.FindById(id); if (tenant == null) { return null; diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo.Abp.TenantManagement.EntityFrameworkCore.csproj b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo.Abp.TenantManagement.EntityFrameworkCore.csproj index 259f5e7a73..b103325b1a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo.Abp.TenantManagement.EntityFrameworkCore.csproj +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo.Abp.TenantManagement.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.TenantManagement.EntityFrameworkCore Volo.Abp.TenantManagement.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs index c1188d2859..a6deb69f4c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore { return await DbSet .IncludeDetails(includeDetails) - .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public Tenant FindByName(string name, bool includeDetails = true) @@ -35,6 +35,13 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore .FirstOrDefault(t => t.Name == name); } + public Tenant FindById(Guid id, bool includeDetails = true) + { + return DbSet + .IncludeDetails(includeDetails) + .FirstOrDefault(t => t.Id == id); + } + public virtual async Task> GetListAsync( string sorting = null, int maxResultCount = int.MaxValue, @@ -52,7 +59,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore ) .OrderBy(sorting ?? nameof(Tenant.Name)) .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task GetCountAsync(string filter = null, CancellationToken cancellationToken = default) diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs index 389f55d5db..21e5ab9b1d 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.TenantManagement.MongoDB CancellationToken cancellationToken = default) { return await GetMongoQueryable() - .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public Tenant FindByName(string name, bool includeDetails = true) @@ -34,6 +34,12 @@ namespace Volo.Abp.TenantManagement.MongoDB .FirstOrDefault(t => t.Name == name); } + public Tenant FindById(Guid id, bool includeDetails = true) + { + return GetMongoQueryable() + .FirstOrDefault(t => t.Id == id); + } + public virtual async Task> GetListAsync( string sorting = null, int maxResultCount = int.MaxValue, @@ -51,7 +57,7 @@ namespace Volo.Abp.TenantManagement.MongoDB .OrderBy(sorting ?? nameof(Tenant.Name)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public async Task GetCountAsync(string filter = null, CancellationToken cancellationToken = default) diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs index a3f066594e..0094b7d5ad 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs @@ -1,13 +1,9 @@ -using Localization.Resources.AbpUi; -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AutoMapper; using Volo.Abp.FeatureManagement; -using Volo.Abp.FeatureManagement.Localization; -using Volo.Abp.Localization; -using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; using Volo.Abp.TenantManagement.Localization; using Volo.Abp.TenantManagement.Web.Navigation; diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs index b7ef9f277e..2ca66c1485 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.TenantManagement.Web.Navigation var tenantManagementMenuItem = new ApplicationMenuItem(TenantManagementMenuNames.GroupName, l["Menu:TenantManagement"], icon: "fa fa-users"); administrationMenu.AddItem(tenantManagementMenuItem); - if (await authorizationService.IsGrantedAsync(TenantManagementPermissions.Tenants.Default)) + if (await authorizationService.IsGrantedAsync(TenantManagementPermissions.Tenants.Default).ConfigureAwait(false)) { tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "/TenantManagement/Tenants")); } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/ConnectionStringsModal.cshtml.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/ConnectionStringsModal.cshtml.cs index 481cc6b7ca..7814d7c018 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/ConnectionStringsModal.cshtml.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/ConnectionStringsModal.cshtml.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants public async Task OnGetAsync(Guid id) { - var defaultConnectionString = await _tenantAppService.GetDefaultConnectionStringAsync(id); + var defaultConnectionString = await _tenantAppService.GetDefaultConnectionStringAsync(id).ConfigureAwait(false); Tenant = new TenantInfoModel { Id = id, @@ -35,11 +35,11 @@ namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants if (Tenant.UseSharedDatabase || Tenant.DefaultConnectionString.IsNullOrWhiteSpace()) { - await _tenantAppService.DeleteDefaultConnectionStringAsync(Tenant.Id); + await _tenantAppService.DeleteDefaultConnectionStringAsync(Tenant.Id).ConfigureAwait(false); } else { - await _tenantAppService.UpdateDefaultConnectionStringAsync(Tenant.Id, Tenant.DefaultConnectionString); + await _tenantAppService.UpdateDefaultConnectionStringAsync(Tenant.Id, Tenant.DefaultConnectionString).ConfigureAwait(false); } return NoContent(); diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/CreateModal.cshtml.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/CreateModal.cshtml.cs index a602b12a65..1ac1e7b97d 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/CreateModal.cshtml.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/CreateModal.cshtml.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants ValidateModel(); var input = ObjectMapper.Map(Tenant); - await _tenantAppService.CreateAsync(input); + await _tenantAppService.CreateAsync(input).ConfigureAwait(false); return NoContent(); } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/EditModal.cshtml.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/EditModal.cshtml.cs index 58516e8ff7..f3bdb8f95f 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/EditModal.cshtml.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/EditModal.cshtml.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants { Tenant = ObjectMapper.Map( await _tenantAppService.GetAsync(id) - ); +.ConfigureAwait(false)); } public async Task OnPostAsync() @@ -30,7 +30,7 @@ namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants ValidateModel(); var input = ObjectMapper.Map(Tenant); - await _tenantAppService.UpdateAsync(Tenant.Id, input); + await _tenantAppService.UpdateAsync(Tenant.Id, input).ConfigureAwait(false); return NoContent(); } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js index 3ae75e6ad6..0dc1861790 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js @@ -19,6 +19,7 @@ order: [[1, "asc"]], processing: true, paging: true, + scrollX: true, serverSide: true, ajax: abp.libs.datatables.createAjax(_tenantAppService.getList), columnDefs: [ diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj index b177b0e3aa..65498d6f38 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo.Abp.TenantManagement.Application.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs index 3e44e7c8ea..99318e52e4 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs @@ -20,14 +20,14 @@ namespace Volo.Abp.TenantManagement public async Task GetAsync() { var tenantInDb = UsingDbContext(dbContext => dbContext.Tenants.First()); - var tenant = await _tenantAppService.GetAsync(tenantInDb.Id); + var tenant = await _tenantAppService.GetAsync(tenantInDb.Id).ConfigureAwait(false); tenant.Name.ShouldBe(tenantInDb.Name); } [Fact] public async Task GetListAsync() { - var result = await _tenantAppService.GetListAsync(new GetTenantsInput()); + var result = await _tenantAppService.GetListAsync(new GetTenantsInput()).ConfigureAwait(false); result.TotalCount.ShouldBeGreaterThan(0); result.Items.ShouldContain(t => t.Name == "acme"); result.Items.ShouldContain(t => t.Name == "volosoft"); @@ -36,7 +36,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task GetListAsync_Filtered() { - var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Filter = "volo" }); + var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Filter = "volo" }).ConfigureAwait(false); result.TotalCount.ShouldBeGreaterThan(0); result.Items.ShouldNotContain(t => t.Name == "acme"); result.Items.ShouldContain(t => t.Name == "volosoft"); @@ -45,7 +45,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task GetListAsync_Sorted_Descending_By_Name() { - var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Sorting = "Name DESC" }); + var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Sorting = "Name DESC" }).ConfigureAwait(false); result.TotalCount.ShouldBeGreaterThan(0); var tenants = result.Items.ToList(); @@ -59,7 +59,7 @@ namespace Volo.Abp.TenantManagement public async Task CreateAsync() { var tenancyName = Guid.NewGuid().ToString("N").ToLowerInvariant(); - var tenant = await _tenantAppService.CreateAsync(new TenantCreateDto { Name = tenancyName }); + var tenant = await _tenantAppService.CreateAsync(new TenantCreateDto { Name = tenancyName }).ConfigureAwait(false); tenant.Name.ShouldBe(tenancyName); tenant.Id.ShouldNotBe(default(Guid)); } @@ -69,8 +69,8 @@ namespace Volo.Abp.TenantManagement { await Assert.ThrowsAsync(async () => { - await _tenantAppService.CreateAsync(new TenantCreateDto { Name = "acme" }); - }); + await _tenantAppService.CreateAsync(new TenantCreateDto { Name = "acme" }).ConfigureAwait(false); + }).ConfigureAwait(false); } [Fact] @@ -78,7 +78,7 @@ namespace Volo.Abp.TenantManagement { var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); - var result = await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "acme-renamed" }); + var result = await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "acme-renamed" }).ConfigureAwait(false); result.Id.ShouldBe(acme.Id); result.Name.ShouldBe("acme-renamed"); @@ -93,8 +93,8 @@ namespace Volo.Abp.TenantManagement await Assert.ThrowsAsync(async () => { - await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "volosoft" }); - }); + await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "volosoft" }).ConfigureAwait(false); + }).ConfigureAwait(false); } [Fact] @@ -102,7 +102,7 @@ namespace Volo.Abp.TenantManagement { var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); - await _tenantAppService.DeleteAsync(acme.Id); + await _tenantAppService.DeleteAsync(acme.Id).ConfigureAwait(false); UsingDbContext(dbContext => { diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo.Abp.TenantManagement.Domain.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo.Abp.TenantManagement.Domain.Tests.csproj index 448dca7f18..8dd16201cb 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo.Abp.TenantManagement.Domain.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo.Abp.TenantManagement.Domain.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs index 8605047bbb..0e5eba4136 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs @@ -19,23 +19,23 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task CreateAsync() { - var tenant = await _tenantManager.CreateAsync("Test"); + var tenant = await _tenantManager.CreateAsync("Test").ConfigureAwait(false); tenant.Name.ShouldBe("Test"); } [Fact] public async Task Create_Tenant_Name_Can_Not_Duplicate() { - await Assert.ThrowsAsync(async () => await _tenantManager.CreateAsync("volosoft")); + await Assert.ThrowsAsync(async () => await _tenantManager.CreateAsync("volosoft").ConfigureAwait(false)).ConfigureAwait(false); } [Fact] public async Task ChangeNameAsync() { - var tenant = await _tenantRepository.FindByNameAsync("volosoft"); + var tenant = await _tenantRepository.FindByNameAsync("volosoft").ConfigureAwait(false); tenant.ShouldNotBeNull(); - await _tenantManager.ChangeNameAsync(tenant, "newVolosoft"); + await _tenantManager.ChangeNameAsync(tenant, "newVolosoft").ConfigureAwait(false); tenant.Name.ShouldBe("newVolosoft"); } @@ -43,10 +43,10 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task ChangeName_Tenant_Name_Can_Not_Duplicate() { - var tenant = await _tenantRepository.FindByNameAsync("acme"); + var tenant = await _tenantRepository.FindByNameAsync("acme").ConfigureAwait(false); tenant.ShouldNotBeNull(); - await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); + await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft").ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs index f199124bca..eb6f44068f 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantStore_Tests.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task FindAsyncByName() { - var acme = await _tenantStore.FindAsync("acme"); + var acme = await _tenantStore.FindAsync("acme").ConfigureAwait(false); acme.ShouldNotBeNull(); acme.Name.ShouldBe("acme"); } @@ -27,10 +27,10 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task FindAsyncById() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync("acme").ConfigureAwait(false); acme.ShouldNotBeNull(); - (await _tenantStore.FindAsync(acme.Id)).ShouldNotBeNull(); + (await _tenantStore.FindAsync(acme.Id).ConfigureAwait(false)).ShouldNotBeNull(); } } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs index 5107d1a06d..6256007e57 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/Tenant_Tests.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task FindDefaultConnectionString() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync("acme").ConfigureAwait(false); acme.ShouldNotBeNull(); acme.FindDefaultConnectionString().ShouldBe("DefaultConnString-Value"); @@ -25,7 +25,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task FindConnectionString() { - var acme = await _tenantRepository.FindByNameAsync("acme"); + var acme = await _tenantRepository.FindByNameAsync("acme").ConfigureAwait(false); acme.ShouldNotBeNull(); acme.FindConnectionString(Data.ConnectionStrings.DefaultConnectionStringName).ShouldBe("DefaultConnString-Value"); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj index 8b1f523d22..528fd9e4e9 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests/Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj index 527aaeaf0c..8cd0fbdae2 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.MongoDB.Tests/Volo.Abp.TenantManagement.MongoDB.Tests.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj index cea0e714b8..89b9c1aae2 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo.Abp.TenantManagement.TestBase.csproj @@ -18,8 +18,8 @@ - - + + diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/AbpTenantManagementTestDataBuilder.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/AbpTenantManagementTestDataBuilder.cs index 45acc070d8..7127d902f5 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/AbpTenantManagementTestDataBuilder.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/AbpTenantManagementTestDataBuilder.cs @@ -25,13 +25,13 @@ namespace Volo.Abp.TenantManagement private async Task AddTenantsAsync() { - var acme = await _tenantManager.CreateAsync("acme"); + var acme = await _tenantManager.CreateAsync("acme").ConfigureAwait(false); acme.ConnectionStrings.Add(new TenantConnectionString(acme.Id, ConnectionStrings.DefaultConnectionStringName, "DefaultConnString-Value")); acme.ConnectionStrings.Add(new TenantConnectionString(acme.Id, "MyConnString", "MyConnString-Value")); - await _tenantRepository.InsertAsync(acme); + await _tenantRepository.InsertAsync(acme).ConfigureAwait(false); - var volosoft = await _tenantManager.CreateAsync("volosoft"); - await _tenantRepository.InsertAsync(volosoft); + var volosoft = await _tenantManager.CreateAsync("volosoft").ConfigureAwait(false); + await _tenantRepository.InsertAsync(volosoft).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs index 4ece524e0f..f055e8e9b5 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/LazyLoad_Tests.cs @@ -22,11 +22,11 @@ namespace Volo.Abp.TenantManagement { using (var uow = GetRequiredService().Begin()) { - var role = await TenantRepository.FindByNameAsync("acme", includeDetails: false); + var role = await TenantRepository.FindByNameAsync("acme", includeDetails: false).ConfigureAwait(false); role.ConnectionStrings.ShouldNotBeNull(); role.ConnectionStrings.Any().ShouldBeTrue(); - await uow.CompleteAsync(); + await uow.CompleteAsync().ConfigureAwait(false); } } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantManagementTestBase.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantManagementTestBase.cs index eee575ba5f..a5e041c5f3 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantManagementTestBase.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantManagementTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.TenantManagement { diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs index 06c75317fa..92ebf57353 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.TestBase/Volo/Abp/TenantManagement/TenantRepository_Tests.cs @@ -20,13 +20,13 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task FindByNameAsync() { - var tenant = await TenantRepository.FindByNameAsync("acme"); + var tenant = await TenantRepository.FindByNameAsync("acme").ConfigureAwait(false); tenant.ShouldNotBeNull(); - tenant = await TenantRepository.FindByNameAsync("undefined-tenant"); + tenant = await TenantRepository.FindByNameAsync("undefined-tenant").ConfigureAwait(false); tenant.ShouldBeNull(); - tenant = await TenantRepository.FindByNameAsync("acme", includeDetails: true); + tenant = await TenantRepository.FindByNameAsync("acme", includeDetails: true).ConfigureAwait(false); tenant.ShouldNotBeNull(); tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2); } @@ -34,15 +34,15 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task FindAsync() { - var tenantId = (await TenantRepository.FindByNameAsync("acme")).Id; + var tenantId = (await TenantRepository.FindByNameAsync("acme").ConfigureAwait(false)).Id; - var tenant = await TenantRepository.FindAsync(tenantId); + var tenant = await TenantRepository.FindAsync(tenantId).ConfigureAwait(false); tenant.ShouldNotBeNull(); - tenant = await TenantRepository.FindAsync(Guid.NewGuid()); + tenant = await TenantRepository.FindAsync(Guid.NewGuid()).ConfigureAwait(false); tenant.ShouldBeNull(); - tenant = await TenantRepository.FindAsync(tenantId, includeDetails: true); + tenant = await TenantRepository.FindAsync(tenantId, includeDetails: true).ConfigureAwait(false); tenant.ShouldNotBeNull(); tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2); } @@ -50,7 +50,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task GetListAsync() { - var tenants = await TenantRepository.GetListAsync(); + var tenants = await TenantRepository.GetListAsync().ConfigureAwait(false); tenants.ShouldContain(t => t.Name == "acme"); tenants.ShouldContain(t => t.Name == "volosoft"); } @@ -58,7 +58,7 @@ namespace Volo.Abp.TenantManagement [Fact] public async Task Should_Eager_Load_Tenant_Collections() { - var role = await TenantRepository.FindByNameAsync("acme"); + var role = await TenantRepository.FindByNameAsync("acme").ConfigureAwait(false); role.ConnectionStrings.ShouldNotBeNull(); role.ConnectionStrings.Any().ShouldBeTrue(); } diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs index 09979f00e1..a45bcec7ce 100644 --- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs +++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs @@ -32,7 +32,7 @@ namespace Volo.Abp.Users public async Task FindByIdAsync(Guid id, CancellationToken cancellationToken = default) { - var localUser = await _userRepository.FindAsync(id, cancellationToken: cancellationToken); + var localUser = await _userRepository.FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); if (ExternalUserLookupServiceProvider == null) { @@ -48,13 +48,13 @@ namespace Volo.Abp.Users try { - externalUser = await ExternalUserLookupServiceProvider.FindByIdAsync(id, cancellationToken); + externalUser = await ExternalUserLookupServiceProvider.FindByIdAsync(id, cancellationToken).ConfigureAwait(false); if (externalUser == null) { if (localUser != null) { //TODO: Instead of deleting, should be make it inactive or something like that? - await WithNewUowAsync(() => _userRepository.DeleteAsync(localUser, cancellationToken: cancellationToken)); + await WithNewUowAsync(() => _userRepository.DeleteAsync(localUser, cancellationToken: cancellationToken)).ConfigureAwait(false); } return null; @@ -68,25 +68,25 @@ namespace Volo.Abp.Users if (localUser == null) { - await WithNewUowAsync(() => _userRepository.InsertAsync(CreateUser(externalUser), cancellationToken: cancellationToken)); - return await _userRepository.FindAsync(id, cancellationToken: cancellationToken); + await WithNewUowAsync(() => _userRepository.InsertAsync(CreateUser(externalUser), cancellationToken: cancellationToken)).ConfigureAwait(false); + return await _userRepository.FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); } if (localUser is IUpdateUserData && ((IUpdateUserData)localUser).Update(externalUser)) { - await WithNewUowAsync(() => _userRepository.UpdateAsync(localUser, cancellationToken: cancellationToken)); + await WithNewUowAsync(() => _userRepository.UpdateAsync(localUser, cancellationToken: cancellationToken)).ConfigureAwait(false); } else { return localUser; } - return await _userRepository.FindAsync(id, cancellationToken: cancellationToken); + return await _userRepository.FindAsync(id, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default) { - var localUser = await _userRepository.FindByUserNameAsync(userName, cancellationToken); + var localUser = await _userRepository.FindByUserNameAsync(userName, cancellationToken).ConfigureAwait(false); if (ExternalUserLookupServiceProvider == null) { @@ -102,13 +102,13 @@ namespace Volo.Abp.Users try { - externalUser = await ExternalUserLookupServiceProvider.FindByUserNameAsync(userName, cancellationToken); + externalUser = await ExternalUserLookupServiceProvider.FindByUserNameAsync(userName, cancellationToken).ConfigureAwait(false); if (externalUser == null) { if (localUser != null) { //TODO: Instead of deleting, should be make it passive or something like that? - await WithNewUowAsync(() => _userRepository.DeleteAsync(localUser, cancellationToken: cancellationToken)); + await WithNewUowAsync(() => _userRepository.DeleteAsync(localUser, cancellationToken: cancellationToken)).ConfigureAwait(false); } return null; @@ -122,20 +122,20 @@ namespace Volo.Abp.Users if (localUser == null) { - await WithNewUowAsync(() => _userRepository.InsertAsync(CreateUser(externalUser), cancellationToken: cancellationToken)); - return await _userRepository.FindAsync(externalUser.Id, cancellationToken: cancellationToken); + await WithNewUowAsync(() => _userRepository.InsertAsync(CreateUser(externalUser), cancellationToken: cancellationToken)).ConfigureAwait(false); + return await _userRepository.FindAsync(externalUser.Id, cancellationToken: cancellationToken).ConfigureAwait(false); } if (localUser is IUpdateUserData && ((IUpdateUserData)localUser).Update(externalUser)) { - await WithNewUowAsync(() => _userRepository.UpdateAsync(localUser, cancellationToken: cancellationToken)); + await WithNewUowAsync(() => _userRepository.UpdateAsync(localUser, cancellationToken: cancellationToken)).ConfigureAwait(false); } else { return localUser; } - return await _userRepository.FindAsync(externalUser.Id, cancellationToken: cancellationToken); + return await _userRepository.FindAsync(externalUser.Id, cancellationToken: cancellationToken).ConfigureAwait(false); } protected abstract TUser CreateUser(IUserData externalUser); @@ -144,8 +144,8 @@ namespace Volo.Abp.Users { using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) { - await func(); - await uow.SaveChangesAsync(); + await func().ConfigureAwait(false); + await uow.SaveChangesAsync().ConfigureAwait(false); } } } diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupServiceExtensions.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupServiceExtensions.cs index 88781ea026..a605db88bc 100644 --- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupServiceExtensions.cs +++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupServiceExtensions.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Users public static async Task GetByIdAsync(this IUserLookupService userLookupService, Guid id, CancellationToken cancellationToken = default) where TUser : class, IUser { - var user = await userLookupService.FindByIdAsync(id, cancellationToken); + var user = await userLookupService.FindByIdAsync(id, cancellationToken).ConfigureAwait(false); if (user == null) { throw new EntityNotFoundException(typeof(TUser), id); @@ -22,7 +22,7 @@ namespace Volo.Abp.Users public static async Task GetByUserNameAsync(this IUserLookupService userLookupService, string userName, CancellationToken cancellationToken = default) where TUser : class, IUser { - var user = await userLookupService.FindByUserNameAsync(userName, cancellationToken); + var user = await userLookupService.FindByUserNameAsync(userName, cancellationToken).ConfigureAwait(false); if (user == null) { throw new EntityNotFoundException(typeof(TUser), userName); diff --git a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo.Abp.Users.EntityFrameworkCore.csproj b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo.Abp.Users.EntityFrameworkCore.csproj index d70b92e1a4..b6916f3aaa 100644 --- a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo.Abp.Users.EntityFrameworkCore.csproj +++ b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo.Abp.Users.EntityFrameworkCore.csproj @@ -3,7 +3,7 @@ - netstandard2.1 + netstandard2.0 Volo.Abp.Users.EntityFrameworkCore Volo.Abp.Users.EntityFrameworkCore $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; diff --git a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs index 1b95984e4b..e8c95b5659 100644 --- a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs +++ b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Users.EntityFrameworkCore { b.Property(u => u.TenantId).HasColumnName(nameof(IUser.TenantId)); b.Property(u => u.UserName).IsRequired().HasMaxLength(AbpUserConsts.MaxUserNameLength).HasColumnName(nameof(IUser.UserName)); - b.Property(u => u.Email).HasMaxLength(AbpUserConsts.MaxEmailLength).HasColumnName(nameof(IUser.Email)); + b.Property(u => u.Email).IsRequired().HasMaxLength(AbpUserConsts.MaxEmailLength).HasColumnName(nameof(IUser.Email)); b.Property(u => u.Name).HasMaxLength(AbpUserConsts.MaxNameLength).HasColumnName(nameof(IUser.Name)); b.Property(u => u.Surname).HasMaxLength(AbpUserConsts.MaxSurnameLength).HasColumnName(nameof(IUser.Surname)); b.Property(u => u.EmailConfirmed).HasDefaultValue(false).HasColumnName(nameof(IUser.EmailConfirmed)); diff --git a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs index 5d0958101c..6dbc5b7d0c 100644 --- a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs +++ b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs @@ -21,12 +21,12 @@ namespace Volo.Abp.Users.EntityFrameworkCore public async Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default) { - return await this.FirstOrDefaultAsync(u => u.UserName == userName, GetCancellationToken(cancellationToken)); + return await this.FirstOrDefaultAsync(u => u.UserName == userName, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync(IEnumerable ids, CancellationToken cancellationToken = default) { - return await DbSet.Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)); + return await DbSet.Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs b/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs index 3c5bb66b25..a176db97b4 100644 --- a/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs +++ b/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs @@ -22,12 +22,12 @@ namespace Volo.Abp.Users.MongoDB public virtual async Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().FirstOrDefaultAsync(u => u.UserName == userName, GetCancellationToken(cancellationToken)); + return await GetMongoQueryable().FirstOrDefaultAsync(u => u.UserName == userName, GetCancellationToken(cancellationToken)).ConfigureAwait(false); } public virtual async Task> GetListAsync(IEnumerable ids, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().Where(u => ids.Contains(u.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); + return await GetMongoQueryable().Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj index 2ba192fe5f..5a5fdebd93 100644 --- a/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj +++ b/modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj @@ -19,7 +19,7 @@ - + diff --git a/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj b/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj index 4aeb17b9c5..ececb4eddd 100644 --- a/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj +++ b/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj @@ -21,7 +21,7 @@ - + diff --git a/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestBase.cs b/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestBase.cs index 2d90e59d4a..e36f485a70 100644 --- a/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestBase.cs +++ b/modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestBase.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.Testing; namespace Volo.Abp.Users { diff --git a/npm/lerna.json b/npm/lerna.json index f941062e34..c482601db0 100644 --- a/npm/lerna.json +++ b/npm/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.1.1", + "version": "2.0.1", "packages": [ "packs/*" ], diff --git a/npm/ng-packs/CHANGELOG.md b/npm/ng-packs/CHANGELOG.md new file mode 100644 index 0000000000..64777880da --- /dev/null +++ b/npm/ng-packs/CHANGELOG.md @@ -0,0 +1,290 @@ +# [2.0.0](https://github.com/abpframework/abp/compare/1.1.2...2.0.0) (2020-01-13) + + +### Bug Fixes + +* **core:** fix flattedRoutes manipulation ([2b2e0be](https://github.com/abpframework/abp/commit/2b2e0be51d9fb37188348f390b56df286de7a6bc)) +* **core:** fix nullable control in the config state ([756e858](https://github.com/abpframework/abp/commit/756e8588f3dd2d1035dbc22db3773653e28b1542)) +* **core:** update flattedRoutes when patchRoute action dispatched ([15a8279](https://github.com/abpframework/abp/commit/15a82794ac5173bd080d3aec46efb43bfc0614ae)) +* **permission-management:** fix twice executing problem of visible setter([ae16916](https://github.com/abpframework/abp/commit/ae16916ae2b03dfc25d9c4c5ceeb559dee34bde2)) +* **theme-shared:** fix remember me functionality [(#2610)](https://github.com/abpframework/abp/pull/2610) ([189a77f](https://github.com/abpframework/abp/commit/189a77f4c421398b841e67280f6f19c4ef56649d)), closes [(#2602)](https://github.com/abpframework/abp/issues/2602) + + +### Code Refactoring + +* remove deprecated functions, outputs, inputs etc. ([f1d0eba](https://github.com/abpframework/abp/commit/f1d0ebae856406213023af11632ed72849928b3e)), closes [#2476](https://github.com/abpframework/abp/issues/2476) + + +### Features + +* add state actions to related state services ([#2431](https://github.com/abpframework/abp/pull/2431)), closes ([#2430](https://github.com/abpframework/abp/pull/2430)) +* make some components replaceable ([#2522](https://github.com/abpframework/abp/pull/2522)), closes ([#2404](https://github.com/abpframework/abp/issues/2404)) +* **account:** add autocomplete attiributes for chromium based browsers ([343c847](https://github.com/abpframework/abp/commit/343c847fb70d634218de1b156b3a15557e27acda)) +* **account:** add the enableLocalLogin condition to auth-wrapper ([#2537](https://github.com/abpframework/abp/pull/2573)) ([0fb7ba4](https://github.com/abpframework/abp/commit/0fb7ba4614ebb64a00f19a9bef277a0fb9bee764)) +* **core:** add init directive ([5ae1071](https://github.com/abpframework/abp/commit/5ae10717d73b1d76711dcd68201ed6b0609c4112)) +* **core:** add ExtractFromGeneric type to ABP namespace ([1fe3b35](https://github.com/abpframework/abp/commit/1fe3b35076c5daddf9edc2a8396b62288cf105da)) +* **core:** add init directive to emit an output when the element initialized ([31c224c](https://github.com/abpframework/abp/commit/31c224c9f9c015e94877d1eba382d1cd415704c7)) +* **core:** fill the parentName property in flattedRoutes for child rotues ([17dd0a2](https://github.com/abpframework/abp/commit/17dd0a25a7dc2fa6268ce68f4f2f5d78f78a1f23)) +* **core:** create AddRoute action to add new elements to top navigation ([#2425](https://github.com/abpframework/abp/pull/2425)), closes ([#2186](https://github.com/abpframework/abp/pull/2186)) +* **theme-shared:** trigger unload confirmation in the modal component when form is dirty ([f59a294](https://github.com/abpframework/abp/commit/f59a2945b223a19750afd46da7e33deff2583328)) +* **theme-shared:** create new toast and confirmation components ([#2606](https://github.com/abpframework/abp/pull/2606)), closes ([#2537](https://github.com/abpframework/abp/issues/2537)) +* **theme-shared:** create table, pagination, loading components ([#2605](https://github.com/abpframework/abp/pull/2605)), related ([#2537](https://github.com/abpframework/abp/issues/2537)) + + +### BREAKING CHANGES + +* Deprecated functions, outputs, inputs addressed in issue #2476 are removed. + + +# [1.1.0](https://github.com/abpframework/abp/compare/1.0.2...1.1.0) (2019-12-06) + + +### Bug Fixes + +* **account:** add header parameter to fetchTokenUsingPasswordFlow method ([3c92489](https://github.com/abpframework/abp/commit/3c924899ca6e5b797bd6536420f75efb61981787)) +* **account:** add tenant header to token request ([dce9777](https://github.com/abpframework/abp/commit/dce97779e5c5a343a1a4bb1b2599bb9a0b192d9a)) +* **core:** fix add view clear before creating view ([95563de](https://github.com/abpframework/abp/commit/95563de2a414f2b96a52e63e85cf7d256dcccbaa)) +* **core:** fix change default insert position in the lazy-load.service ([13a10c2](https://github.com/abpframework/abp/commit/13a10c2cc5dd35ae120492f95de18b182be85eb1)) +* **core:** fix abpfor directive filtering bug ([4f4075f](https://github.com/abpframework/abp/commit/4f4075fb2b6f9ec371fbfa85ed61ac1a5af725ef)) +* **core:** fix sort pipe key error ([2f53454](https://github.com/abpframework/abp/commit/2f534545bac1d45d8f5e5fd99fee982765db6a4d)) +* **core:** fix sort pipe null data problem ([4764750](https://github.com/abpframework/abp/commit/4764750a8c4c38c670d05858e88407b91c5dbe60)) +* **core:** fix visibility directive bug ([c1a1bfe](https://github.com/abpframework/abp/commit/c1a1bfe7ee16e3c2e9f71779c4928340c0278a9a)) +* **identity:** fix validation display error ([335c74d](https://github.com/abpframework/abp/commit/335c74d80097de5a97913e97230f423768f751ea)) +* **module-template:** organize home page [#2265](https://github.com/abpframework/abp/issues/2265) ([1b54da2](https://github.com/abpframework/abp/commit/1b54da232ff86891b54219a58e2ee616a46fbe5f)) +* **module-template:** update environments ([b5a13a2](https://github.com/abpframework/abp/commit/b5a13a26580210ab035b344ce30366f1595ae9d3)) +* **template:** fix lazyLoadService parameters in app.component ([6f024a9](https://github.com/abpframework/abp/commit/6f024a94df6b882385f8653a17071d4b0eb638c3)) +* **tenant-management:** add modalBusy controls ([e75bf30](https://github.com/abpframework/abp/commit/e75bf30aada713697f34feb0c6a49ca25bc3e709)), closes [#2042](https://github.com/abpframework/abp/issues/2042) +* **tenant-management:** add type error control ([f21917a](https://github.com/abpframework/abp/commit/f21917ab2bb5f5dce51dde1a5e9fbbef36bc9f90)) +* **theme-basic:** fix layout animations ([66fcb0e](https://github.com/abpframework/abp/commit/66fcb0e0a5bdb6f6ec25171cb0a7e06cb333c9cd)) +* **theme-shared:** fix breadcrumb type error ([d7c9a60](https://github.com/abpframework/abp/commit/d7c9a6044c32b7b20232a76c5e98b9d874c79cd7)) +* **theme-shared:** fix confirmation yes text localization ([f55862a](https://github.com/abpframework/abp/commit/f55862adca463b9fbd6e3af36738874ed210742e)) +* **theme-shared:** fix creating custom error component problem ([2c891d8](https://github.com/abpframework/abp/commit/2c891d84e904f619cc4ac6de834e0dbc666837ee)) +* **theme-shared:** fix modal animation and backdrop height ([383c4f6](https://github.com/abpframework/abp/commit/383c4f6a29d2412e9225283b0c2f8d0e8db50936)) +* **theme-shared:** fix wrong folder name ([1f8c447](https://github.com/abpframework/abp/commit/1f8c4477cf79d1d891d159580728ce8ea76d6934)) +* add finalize operator to set false the modalBusy ([208a5e3](https://github.com/abpframework/abp/commit/208a5e3ab52a828e8a4e37156dd2f927c48b152e)), closes [#2093](https://github.com/abpframework/abp/issues/2093) +* add finalize operator to set false the modalBusy ([3ec86f1](https://github.com/abpframework/abp/commit/3ec86f150e5ef1f9728137eff0aa8210248cb015)), closes [#2093](https://github.com/abpframework/abp/issues/2093) +* fix mistyped config file and selector name ([73fbe7d](https://github.com/abpframework/abp/commit/73fbe7ddf1326f5faa812bae0e79c0726d740d5d)) +* move table-sort.directive to theme-shared ([ae31b57](https://github.com/abpframework/abp/commit/ae31b57aa91a45d0b828ae64a7151f7d0b483661)), closes [#2067](https://github.com/abpframework/abp/issues/2067) +* remove console warn ([d2dc069](https://github.com/abpframework/abp/commit/d2dc06982b62f4f7c54848130cdf87df6dab521e)) +* update NgxValidate blueprints ([22b1c56](https://github.com/abpframework/abp/commit/22b1c569dd1241a9b74be3c7caf128ce101c4f39)) + + +### Code Refactoring + +* **theme-shared:** rename error.component ([d17d6b1](https://github.com/abpframework/abp/commit/d17d6b1c16dca21c682b116d2d3847f10e4856bd)) + + +### Features + +* **theme-shared:** add date parser formatter for ng-datepicker ([4769843](https://github.com/abpframework/abp/commit/4769843e305badd5da64efccfb90d1552c576b6f)) +* **account:** implement dynamic password rules ([0bde323](https://github.com/abpframework/abp/commit/0bde3233186177662f03e7a2a55236e8d2b2fa69)) +* **account:** implement dynamic password validation to register page ([60ed67d](https://github.com/abpframework/abp/commit/60ed67d004acb78041efa9e2a2d20cd83611e803)), closes [#2039](https://github.com/abpframework/abp/issues/2039) +* **account:** implement manage-profile html design ([746c7ce](https://github.com/abpframework/abp/commit/746c7ceda9674f6093a4e833c756eda3ae8c8bdd)) +* **account:** implement new login and register html design ([f44773c](https://github.com/abpframework/abp/commit/f44773cca74c22f742f82b64b04d390bec9094c7)) +* **core:** add condition check to getGrantedPolicy ([76b7559](https://github.com/abpframework/abp/commit/76b755957598b4a21e1f270538c6137ae1c537ae)) +* **core:** add stop-propagation directive test ([d4b5bd9](https://github.com/abpframework/abp/commit/d4b5bd93deadd06d45593ab1f0015f55abedf603)) +* **core:** add template ref to permission directive ([eedab03](https://github.com/abpframework/abp/commit/eedab03ad1634097bebf21542071933768b9e5e5)) +* **core:** add toLocalISOString function to Date prototype ([9be9401](https://github.com/abpframework/abp/commit/9be940181e2d68bd9bb7af44487b81996f4431ac)) +* **core:** add undefined and empty string params control to rest service ([6b78dbf](https://github.com/abpframework/abp/commit/6b78dbff863e92f6c41358fceb25210763571388)) +* **core:** support to find requiredPolicy from child route ([a3d751f](https://github.com/abpframework/abp/commit/a3d751f482d4ca4ab9b8a23896b789479376e820)) +* **feature-management:** add empty data message ([6e759b8](https://github.com/abpframework/abp/commit/6e759b8829649a4a80a5c82700af9f9baea3763d)) +* **identity:** add badges to role list ([a191661](https://github.com/abpframework/abp/commit/a1916615354155a91410da65ff726e762a158887)) +* **identity:** implement dynamic password validation to users page ([7d026e5](https://github.com/abpframework/abp/commit/7d026e5e9176511864947ebc8d8c452384e72ee9)), closes [#2039](https://github.com/abpframework/abp/issues/2039) +* **permissin-guard:** add a handling permission condition ([c5fc902](https://github.com/abpframework/abp/commit/c5fc902fb3aa45422d7efb5728d12b0e31b0ff8c)) +* **permission-management:** add hideBadges input ([b9d2e5f](https://github.com/abpframework/abp/commit/b9d2e5f6565e95b7b6e73c457d9a6f857277379e)) +* **setting-management:** add a pointer class ([80e362a](https://github.com/abpframework/abp/commit/80e362a06d05da9f9ac214e95a46510c713ad5b3)) +* **settings-management:** add requiredPolicy to settings page ([04bcc4f](https://github.com/abpframework/abp/commit/04bcc4f4a92a213f737e9104b417fd986d803e69)) +* **template:** add insert position parameter in load method of lazyLoadScript ([77e6515](https://github.com/abpframework/abp/commit/77e6515aadd7a9d5fa049237f0d09f6e227aafdf)) +* **theme-basic:** add icon to default link template ([0e765bd](https://github.com/abpframework/abp/commit/0e765bd1d73342bb2e7dda17a3e4db00a958b45e)) +* **theme-basic:** add two icons ([22051fe](https://github.com/abpframework/abp/commit/22051fe7eb416d1d768bac480031518bde621553)) +* **theme-basic:** copy new styles ([6c2df8d](https://github.com/abpframework/abp/commit/6c2df8dfdf1c77a414a7049461ed5006e164c3b3)) +* **theme-basic:** implement collapse animation to the user info nav element ([87bad9b](https://github.com/abpframework/abp/commit/87bad9b567e3d10b2ae576c4ab514b3591faeb42)) +* **theme-basic:** implement collapseWithMargin animation to the application layout main navigation ([6fa1922](https://github.com/abpframework/abp/commit/6fa19229bbd54a79cf98c06b9cbfe3222c0cd91c)) +* **theme-shared:** add collapseLinearWithMargin animation ([91f10ee](https://github.com/abpframework/abp/commit/91f10eec66e8930f144d91bb236776296b624fcc)) +* **theme-shared:** add custom component features to error.component ([257cc8f](https://github.com/abpframework/abp/commit/257cc8f4597cef6d0fd530e7a15015a088585ade)), closes [#2097](https://github.com/abpframework/abp/issues/2097) +* **theme-shared:** add destroy subject to custom error component ([707c37c](https://github.com/abpframework/abp/commit/707c37c04d602d743289724198a4ffbffde8fc29)), closes [#2097](https://github.com/abpframework/abp/issues/2097) +* **theme-shared:** add expand classes and implement to layout ([d6c049d](https://github.com/abpframework/abp/commit/d6c049d3bfe5945e9d81e3077124a6f993c9bba6)) +* **theme-shared:** add hideCloseIcon property to http error config token ([8365934](https://github.com/abpframework/abp/commit/8365934032c144927ae9ac636dbf1a89db94113c)) +* **theme-shared:** add http error config token ([5809d1b](https://github.com/abpframework/abp/commit/5809d1ba01438d3d5bc26c7a67a871c5459d2069)) +* **theme-shared:** add id input to button.component ([c7c1efe](https://github.com/abpframework/abp/commit/c7c1efe378cd345a40f6af894c58c648fc7618e8)) +* **theme-shared:** add overflow-hidden class ([e0902a1](https://github.com/abpframework/abp/commit/e0902a1a20227e4e8e695303357b29b42b9fd8c8)) +* **theme-shared:** add table scroll styles ([fe2d731](https://github.com/abpframework/abp/commit/fe2d73102dd00c73dff4cf21559209fa6297a414)) +* add abp-collapsed-height and remove abp-collapsed class ([c0fef92](https://github.com/abpframework/abp/commit/c0fef926621a81962c2670dc1337d8a0c3d1a93f)) +* add collapseWithMargin animation ([6f94e73](https://github.com/abpframework/abp/commit/6f94e736e3bcaf70b78fbfcf17e0426c63c80f49)) +* add jest.config files ([c116a2d](https://github.com/abpframework/abp/commit/c116a2d21396fc696adfd0a393e0420f62333504)) +* implement new home page ([01c8bf9](https://github.com/abpframework/abp/commit/01c8bf9f592e834516204a09ae26e661fde46553)) +* update ui design ([7ebb7a0](https://github.com/abpframework/abp/commit/7ebb7a0097e8cc1f84c41078a802c596135e3dcf)), closes [#2024](https://github.com/abpframework/abp/issues/2024) + + +### BREAKING CHANGES + +* **theme-shared:** renamed error.component to http-error-wrapper.component + + + +## [1.0.2](https://github.com/abpframework/abp/compare/1.0.0...1.0.2) (2019-10-22) + + +### Bug Fixes + +* fix manage profile animations ([d41e2e4](https://github.com/abpframework/abp/commit/d41e2e483f4a201ba90709a5a898fe3b8535682e)) + + + +# [1.0.0](https://github.com/abpframework/abp/compare/0.22.0...1.0.0) (2019-10-21) + + +### Bug Fixes + +* fix width of table columns ([e182861](https://github.com/abpframework/abp/commit/e1828614702d646feab3e4d73696d894d63bbc55)) + + +### Features + +* **setting-management:** create state ([8f358bb](https://github.com/abpframework/abp/commit/8f358bbe0179feaacb80bb9dde79682b69b7eb2f)) +* **theme-shared:** add new inputs to button component ([d6efc85](https://github.com/abpframework/abp/commit/d6efc85b8ed88bd7b99025662b5220567d9551cc)) +* upgrade font awesome ([e4957fe](https://github.com/abpframework/abp/commit/e4957fe45548b7910996aab2dc6b0f9f425e7c04)) + + + +# [0.22.0](https://github.com/abpframework/abp/compare/0.21.0...0.22.0) (2019-10-14) + + +### Bug Fixes + +* **core:** change pipe inputs ([4fa105b](https://github.com/abpframework/abp/commit/4fa105bb77b123ec2861b8f9033bb6f986b960e4)) +* **core:** fix localizationInitialize function state selector error ([08d013e](https://github.com/abpframework/abp/commit/08d013ebc419366a272fc2d8d4e5a4c55ed22107)) +* **core:** fix state selecting errors ([8967bb4](https://github.com/abpframework/abp/commit/8967bb431001d2cad8abf0200103a9809d6ab815)) +* **tenant-management-config:** fix exports ([cecdbfc](https://github.com/abpframework/abp/commit/cecdbfc44ae9186db99cf38ae24d01b15ae4af46)) +* **theme-shared:** change color-white css class ([1abe70f](https://github.com/abpframework/abp/commit/1abe70f7f1edef8fb198047ce980ba1cfa360b36)) +* **theme-shared:** fix modal styles and animations ([093e62e](https://github.com/abpframework/abp/commit/093e62eb64c5446d13fd78ec68dd4e9d4ebfe684)) +* **theme-shared:** remove unnecessary brackets ([d330342](https://github.com/abpframework/abp/commit/d3303420e0485ccfbff02840101b9f686c7cb328)) +* **theme-shared:** fix timing bug ([8ddf13e](https://github.com/abpframework/abp/commit/8ddf13ef6546957d7c0679a4df93c26c5076c1b9)) +* fix some bugs ([efb6c45](https://github.com/abpframework/abp/commit/efb6c456f6453f715d65876722ad636bb024d12e)) + + +### Code Refactoring + +* **core:** convert localization pipe to pure ([bbfc2dc](https://github.com/abpframework/abp/commit/bbfc2dc688ea91662dd54adcdb621c26686dea15)) + + +### Features + +* **module-template:** add settings component ([d7713ee](https://github.com/abpframework/abp/commit/d7713ee30836cf667ae96fd8bd8a584f377cab82)) +* **core:** add default option to localization ([a92b48d](https://github.com/abpframework/abp/commit/a92b48d6b3f635f0f80fc1d6cc81b30f039b4e40)) +* **core:** add sort method to sort.pipe ([6b7f2ae](https://github.com/abpframework/abp/commit/6b7f2ae2ca47001c7f8bd977ea9827c9b273a6ea)) +* **core:** add table-sort.directive ([35420bc](https://github.com/abpframework/abp/commit/35420bc4d48d5b2109f5f2c943613cd550fb8255)) +* **core:** lazy load service supports url array ([220d411](https://github.com/abpframework/abp/commit/220d41149d4824c3341ee5e946a898f159e45a63)) +* **module-template:** add identity, tenant management, setting-management modules ([5c1bcbb](https://github.com/abpframework/abp/commit/5c1bcbb256c0b1b8bb948d256ee5e4c8162d12c3)), closes [#1652](https://github.com/abpframework/abp/issues/1652) +* **templates:** add setting management module ([5c29d1f](https://github.com/abpframework/abp/commit/5c29d1f69f9f94f5ecd473a40b0a049ecc51c4eb)), closes [#1652](https://github.com/abpframework/abp/issues/1652) +* create dev-app ([2c2cd7c](https://github.com/abpframework/abp/commit/2c2cd7c1aa0aee2c63a68dbdad9810a730810810)) +* create libraries in the module-template [#1652](https://github.com/abpframework/abp/issues/1652) ([7856b22](https://github.com/abpframework/abp/commit/7856b223533aaedbb9b068ab8116daffa985b70c)) +* create module template main app [#1652](https://github.com/abpframework/abp/issues/1652) ([a99496f](https://github.com/abpframework/abp/commit/a99496f2efd229b9250334f7eb9c0371b276fa33)) +* seperate 3th party css files from initial bundle ([ac71b2f](https://github.com/abpframework/abp/commit/ac71b2fc6f7ae6e6b7d4e632104af330ab8de484)) + + +# [0.21.0](https://github.com/abpframework/abp/compare/0.20.1...0.21.0) (2019-09-23) + + + +## [0.20.1](https://github.com/abpframework/abp/compare/0.20.0...0.20.1) (2019-09-23) + + +### Bug Fixes + +* **account:** comment to remember me logic ([00b9d01](https://github.com/abpframework/abp/commit/00b9d015cb63c25df85705802a53434fabb1d26c)) +* **account:** rename appName ([d5035c4](https://github.com/abpframework/abp/commit/d5035c4400cb1f99d32b79b42d05ffa0d60f26fd)) +* **core:** add ng zone to route navigating ([19a1abb](https://github.com/abpframework/abp/commit/19a1abba0cc1d42bdaeb8b654737379223ee61bf)) +* **core:** auth guard redirect ([7c14c73](https://github.com/abpframework/abp/commit/7c14c73a392c591b382be34128d9674616284b6f)) +* **core:** build error ([0f1424a](https://github.com/abpframework/abp/commit/0f1424a0749debcbd95ccc351fcea17dcb294bdd)) +* **core:** change getGrantedPolicy ([148c16b](https://github.com/abpframework/abp/commit/148c16b80b2da07447e089626a75add60ac210ca)) +* **core:** localization pipe sync value problem ([efa0a4e](https://github.com/abpframework/abp/commit/efa0a4e1bd5184afc9bebd670aaa8447ca841ce5)) +* **feature-management:** npm version ([d4bd43b](https://github.com/abpframework/abp/commit/d4bd43b0f9a9387daeed26853d358f87248ae8f8)) +* **feature-management:** remove deleteDestPath from ng-package.json ([e35b801](https://github.com/abpframework/abp/commit/e35b8010ed38a5c72794dc3decffb9d252540bbb)) +* **identity:** change actions column minimum width ([8086c1c](https://github.com/abpframework/abp/commit/8086c1c97cd18335c71eb3ae9bf217f8c32fca01)) +* **identity:** change template ([3bef365](https://github.com/abpframework/abp/commit/3bef3650f8cbfcfc47894abdf490f12a6dc1fbb5)) +* **permission-management:** fix type error ([779e161](https://github.com/abpframework/abp/commit/779e161aa8b9a379295525458fc60b97d2b33629)) +* **setting-management:** fix permisson problem ([143a34e](https://github.com/abpframework/abp/commit/143a34e2440dc222158a8d5de8b831c13c2625af)) +* **tenant:** add validation to connection string #resolves 1641 ([96386ef](https://github.com/abpframework/abp/commit/96386ef0e6d8c8f7f99b2c9758d6500e36ad409a)) +* **tenant-management:** change actions column minimum width ([cb7df88](https://github.com/abpframework/abp/commit/cb7df881e14b563d4721f35b710c2852381438ef)) +* add feature-management to angular.json ([03ae5b5](https://github.com/abpframework/abp/commit/03ae5b5ee48da4b7f42384283decf36bd1a22d2d)) +* **tenant-management:** change checkbox html element ([97af208](https://github.com/abpframework/abp/commit/97af208f9a9f9d359d73f516ca58759b50254cce)) +* **tenant-management:** fix default connection string modal validation issue [#1641](https://github.com/abpframework/abp/issues/1641) ([adf32c1](https://github.com/abpframework/abp/commit/adf32c1cb265c2d2e06d158cf4c0453f041c0f75)) +* **theme-basic:** remove unused router ([015e94d](https://github.com/abpframework/abp/commit/015e94daf663ce81b8229a3c019d4f980f76fed9)) +* **theme-shared:** change abpButton class from fa-spin to fa-pulse ([ef79664](https://github.com/abpframework/abp/commit/ef796645d96bc6968565497995049314ce2039e8)) +* **theme-shared:** change button text colors to white ([9638ef1](https://github.com/abpframework/abp/commit/9638ef107baa7258b2b35e5eafbded4bcbd61b18)) +* **theme-shared:** change fade animation name ([683337f](https://github.com/abpframework/abp/commit/683337f6b45442fd8d2edb19fd978aa1bd47170f)) +* **theme-shared:** loader bar turning back problem ([38f5f32](https://github.com/abpframework/abp/commit/38f5f320147dcaf781a905b0d67d8634cd89173d)) +* **theme-shared:** move chart.js importing in the appendScript function ([1b30f90](https://github.com/abpframework/abp/commit/1b30f90f79b4ac0187baebee1ced73aa1d8dd601)) +* **theme-shared:** remove unnecessary css style ([70ec0b3](https://github.com/abpframework/abp/commit/70ec0b3a63c001f94e7eb5de4b1be6fefb625869)) + + +### Reverts + +* Revert "fix docs projects combobox link bug" ([0965eb4](https://github.com/abpframework/abp/commit/0965eb43bde4fce27037761cf2150126142a8c86)) + + + +# [0.19.0](https://github.com/abpframework/abp/compare/0.18.1...0.19.0) (2019-08-16) + + +### Bug Fixes + +* **account:** tenant-box selection ([26c6901](https://github.com/abpframework/abp/commit/26c69017d9655d82a9d50b08f2acdc9da0d3895a)) +* **angular-tutorial:** add some modules in shared.module ([5154e80](https://github.com/abpframework/abp/commit/5154e80add02833627eb44b69f31ac94b49afce6)) +* **core:** check if localization key exists ([c80ba38](https://github.com/abpframework/abp/commit/c80ba38d3de0dc2446f32a043cefd70c51c7b513)) +* **core:** localization empty return problem ([1afaed3](https://github.com/abpframework/abp/commit/1afaed318d4ef7c27b1106115fe1426b76bea4f4)) +* **core:** redirect user to child routes instead of module root route ([298ad36](https://github.com/abpframework/abp/commit/298ad367a30a75be387199d9aca30a9e0dfbe83a)) +* remove unnecessary paths ([23b50c6](https://github.com/abpframework/abp/commit/23b50c6eb1e4c6fa9fe228306d24cd19a21104b4)) +* **core:** rename directives ([5e4be2a](https://github.com/abpframework/abp/commit/5e4be2ab4fec3e23461986318c7424076bb31e90)) +* **core:** store tenant instead of tenant id ([b1c30fd](https://github.com/abpframework/abp/commit/b1c30fdcd15e6b9471d44fcbd2cb65290566ab60)) +* **identity:** add localization key to search input placeholder ([c079dbc](https://github.com/abpframework/abp/commit/c079dbcf4f07d73e225d94f8292a837d34b991e2)) +* **identity:** change request url ([e23b337](https://github.com/abpframework/abp/commit/e23b3372cdaa60269f8b7bc0ec5a2f04b19a8cb7)) +* **identity:** disable input when editing a static role ([c1ab80a](https://github.com/abpframework/abp/commit/c1ab80a3efdd1c6b47fe5ede103b09049c8c6f3e)) +* **identity:** hide password field of modal when editing an existing user ([c5508d2](https://github.com/abpframework/abp/commit/c5508d2f25613cb34d7df027a1a98ce7c41625aa)) +* **multi-tenancy:** correctly set TenantId on create in AppService ([2a4c319](https://github.com/abpframework/abp/commit/2a4c319081a0f95e8f437a932fb84299d2fcfc9b)), closes [#1360](https://github.com/abpframework/abp/issues/1360) +* **ng-core:** add type error control ([5f24fb8](https://github.com/abpframework/abp/commit/5f24fb86c7704e1c9ea76eb11a575b70c973802a)) +* **permission-management:** disabled checkbox bug in permission modal ([774c338](https://github.com/abpframework/abp/commit/774c33886bb1658f494972f7958a36f54e2a9db1)) +* **permission-management:** disabled checkboxes ([23aa91d](https://github.com/abpframework/abp/commit/23aa91da5481556c92b48d562afe3736c66c16c6)) +* **scripts:** add missing import ([a5048f1](https://github.com/abpframework/abp/commit/a5048f12e4ad7c6ffbb51fb89c439855dcb0e395)) +* **tenant-management:** change request urls ([f869794](https://github.com/abpframework/abp/commit/f869794e163ffd3558ab5bae19bfef40cc94e3fc)) +* **tenant-management:** fix request search value of abp-button and handle form submit ([0047492](https://github.com/abpframework/abp/commit/00474927dda8a2555104693e3ab4f8f33ec34b60)) +* **tenant-management:** prod build error ([0dc1e1f](https://github.com/abpframework/abp/commit/0dc1e1fa87d289ea9f775ef5ad85fb646bed736d)) +* **tenant-management:** remove parentName in child route ([c1cefc7](https://github.com/abpframework/abp/commit/c1cefc777ea41a38e2481e7d2b13b1551d9217c4)) +* **tenant-management:** rename GetTenant action to GetTenants ([ed7cbc1](https://github.com/abpframework/abp/commit/ed7cbc18487cac5336b089f7efd94d209d192de7)) +* **theme-basic:** add pointer class to nav elements ([e1a4a12](https://github.com/abpframework/abp/commit/e1a4a12d611b365d0493880c611fc84866021e59)) +* **theme-basic:** change-password and profile modals ([5b6abc5](https://github.com/abpframework/abp/commit/5b6abc517f82af18c3a53a2b070ae4a4526aa9c4)) +* **theme-basic:** close navbar dropdowns on window resize ([d49de5f](https://github.com/abpframework/abp/commit/d49de5f88b93ab83f7e969d7adb0a3d668709325)) +* **theme-basic:** fix navigation dropdowns ([35cd51a](https://github.com/abpframework/abp/commit/35cd51a92cb6be8b06779ef32b660847639c9664)) +* **theme-basic:** navigation dropdown visibility and alignment ([7451adc](https://github.com/abpframework/abp/commit/7451adcada8424621ab39f433524b6bc3d713394)) +* **theme-basic:** rename EmptyLayout to EmptyLayoutComponent ([84f5132](https://github.com/abpframework/abp/commit/84f51324153e441a02f9ab45f480f5e6a5bd09ea)) +* **theme-basic:** translation keys ([7311801](https://github.com/abpframework/abp/commit/73118018913f0b737ac0e649a1dc5d764daa9c63)) +* **theme-shared:** button code quality ([9f9ce58](https://github.com/abpframework/abp/commit/9f9ce5810ef892806f3e31f92ecaacb5e9db7fbc)) +* **theme-shared:** button-component disabled attribute ([7272912](https://github.com/abpframework/abp/commit/72729125c1add763537604779964a3630e34af06)) +* **theme-shared:** fix accessibility issue with loading state of button component ([60c64fb](https://github.com/abpframework/abp/commit/60c64fb93b250e654c4d51c96e7a9a5b4ba8d585)) +* **theme-shared:** improve code quality of error.handler ([2809ec8](https://github.com/abpframework/abp/commit/2809ec8d4e17fdc05e67254346d0dea7fbd08677)) +* **theme-shared:** modal component ([9676ea1](https://github.com/abpframework/abp/commit/9676ea1bed44f1399190fe18c56c4110da7fa4e3)) +* **theme-shared:** modal component click listening ([ae5c398](https://github.com/abpframework/abp/commit/ae5c398b8ae655d9a6e1d8a08d5b2a827dd73556)) +* **theme-shared:** remove constructor function ([eed7807](https://github.com/abpframework/abp/commit/eed7807b8d0b3a9462d85673ca648cc41a4ea5c0)) +* **theme-shared:** undo keyup changes ([be16db3](https://github.com/abpframework/abp/commit/be16db3898eef1207a1a0558f1f458cfd2f9d696)) +* **theme-shared:** validation-error component ([700d768](https://github.com/abpframework/abp/commit/700d768807d317b68e764a563732ad717dadaae2)) +* **user, permission:** bug fix ([0004677](https://github.com/abpframework/abp/commit/0004677796022b0c3b0a2c621aebf56ce0e5280f)) +* change peerDependencies to dependencies in tenant-management ([161edb6](https://github.com/abpframework/abp/commit/161edb6f81174b526cb287682ecf81db7c16e382)) +* child dropdown width and ellipsis width ([602d24b](https://github.com/abpframework/abp/commit/602d24bbda1c076e4a1c74766e94304fd91e915a)) +* localizations ([e5c1f2e](https://github.com/abpframework/abp/commit/e5c1f2e00eb769adda9bf7a8c05995512688f8cd)) +* pr feedbacks ([a1b7c6d](https://github.com/abpframework/abp/commit/a1b7c6d730c794c8626f61e1df4647325f646486)) +* remove comment lines ([12bd324](https://github.com/abpframework/abp/commit/12bd3244d91637ada5e427f17b0c3891095c5d6c)) +* translation keys ([ad092ca](https://github.com/abpframework/abp/commit/ad092ca11d37cf293ec452f6de0e2446b3a27895)) +* update commit message sync.js ([6738b26](https://github.com/abpframework/abp/commit/6738b2694ea946f22182d3bb3c0face930497a94)) + + +### Features + +* **theme-basic:** change modal ([902731f](https://github.com/abpframework/abp/commit/902731f01d9d30dce0b79808dd85ec433a1ed95c)) +* **theme-shared:** change modal style and logic ([ae93dc4](https://github.com/abpframework/abp/commit/ae93dc432ced052c5e88ec486bbe47363b84e5ee)) + + +### Performance Improvements + +* **permission-management:** handle attr.disabled while rendering to DOM ([4b09f02](https://github.com/abpframework/abp/commit/4b09f02e096fb39fdb0ca8e752ba25209a035c09)) + diff --git a/npm/ng-packs/CONTRIBUTING.md b/npm/ng-packs/CONTRIBUTING.md new file mode 100644 index 0000000000..76a18c04c3 --- /dev/null +++ b/npm/ng-packs/CONTRIBUTING.md @@ -0,0 +1,133 @@ +# Contributing to ABP Angular UI + +We would love for you to contribute to ABP Angular UI and help make it even better than it is today. + +# Development + +Run `yarn` to install all dependencies, then run `yarn prepare:workspace` to prepare the ABP packages (might take 2 minutes). + +Run `yarn start` to start the `dev-app`. Navigate to http://localhost:4200/. + +## Package + +[Symlink Manager](https://github.com/mehmet-erim/symlink-manager) is used to manage symbolic link processes. Run `yarn symlink copy` to select the packages to develop. + +## Application + +The `dev-app` project is the same as the Angular UI template project. `dev-app` is used to see changes instantly. + +If you will only develop the `dev-app`, you don't need to run `symlink-manager`. + +> Reminder! If you have developed the `dev-app` template, you should do the same for the application and module templates. + +For more information, see the [docs.abp.io](https://docs.abp.io) + +# Committing changes + +Before you commit, please ensure that your code passes the existing unit tests. + +New features should be accompanied by new tests. + +Every commit should contain only the changes related to the subject of that commit. + +## Commit message format + +Each commit message consists of a **header**, a **body** and a **footer**. The header has a special +format that includes a **type**, a **scope** and a **subject**: + +``` +(): + + + +