Browse Source

Merge branch 'dev' into add-CorrelationId-to-distributed-events

pull/16795/head
maliming 3 years ago
parent
commit
783414e2e8
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 14
      .github/scripts/update_versions.py
  2. 44
      .github/workflows/publish-release.yml
  3. 2
      .github/workflows/update-versions.yml
  4. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  5. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  6. 17
      docs/en/API/Dynamic-CSharp-API-Clients.md
  7. 2
      docs/en/API/Swagger-Integration.md
  8. 6
      docs/en/Application-Startup.md
  9. 23
      docs/en/Autofac-Integration.md
  10. 2
      docs/en/Background-Jobs-Hangfire.md
  11. 2
      docs/en/Background-Jobs-Quartz.md
  12. 4
      docs/en/CLI-New-Command-Samples.md
  13. 19
      docs/en/Entity-Framework-Core.md
  14. 8
      docs/en/Getting-Started-AspNetCore-Application.md
  15. 41
      docs/en/Getting-Started-React-Native.md
  16. 8
      docs/en/Localization.md
  17. 8
      docs/en/Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md
  18. 8
      docs/en/Modules/Virtual-File-Explorer.md
  19. 6
      docs/en/MongoDB.md
  20. 8
      docs/en/PlugIn-Modules.md
  21. 6
      docs/en/Repositories.md
  22. 2
      docs/en/SMS-Sending.md
  23. 2
      docs/en/SignalR-Integration.md
  24. 2
      docs/en/Text-Templating-Razor.md
  25. 41
      docs/en/UI/AspNetCore/Bundling-Minification.md
  26. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/StandardLayouts.cs
  27. 13
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/AbpThemingOptions.cs
  28. 34
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/DefaultThemeManager.cs
  29. 36
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/DefaultThemeSelector.cs
  30. 8
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ITheme.cs
  31. 6
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/IThemeManager.cs
  32. 6
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/IThemeSelector.cs
  33. 23
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeDictionary.cs
  34. 27
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeExtensions.cs
  35. 24
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeInfo.cs
  36. 23
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeNameAttribute.cs
  37. 12
      framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs
  38. 12
      framework/src/Volo.Abp.Data/Volo/Abp/Data/AppliedDatabaseMigrationsEto.cs
  39. 318
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/DatabaseMigrationEventHandlerBase.cs
  40. 145
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreRuntimeDatabaseMigratorBase.cs
  41. 2
      framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj
  42. 2
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs
  43. 3
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs
  44. 14
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs
  45. 14
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs
  46. 13
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs
  47. 29
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs
  48. 83
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs
  49. 6
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs
  50. 18
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs
  51. 81
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs
  52. 4
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs
  53. 11
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs
  54. 8
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs
  55. 56
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider.cs
  56. 18
      framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs
  57. 5
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs
  58. 2
      framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs
  59. 2
      framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs
  60. 20
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
  61. 2
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs
  62. 19
      framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateContentFileProvider_Tests.cs
  63. 19
      framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ScribanTemplateContentFileProvider_Tests.cs
  64. 17
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs
  65. 2
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs
  66. 29
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider_Tests.cs
  67. 6
      framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs
  68. 2
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Volo.Abp.BackgroundJobs.DemoApp.HangFire.csproj
  69. 16
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/AbpAspNetCoreComponentsWebBasicThemeModule.cs
  70. 26
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/BasicTheme.cs
  71. 3
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NullLayout.razor
  72. 8
      modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs
  73. 9
      modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs
  74. 2
      modules/openiddict/app/OpenIddict.Demo.Client.Console/Program.cs
  75. 23
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.ClientCredentials.cs
  76. 1
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateAuthorizedParty.cs
  77. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/SettingManagement.razor
  78. 4
      modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.js
  79. 2
      npm/ng-packs/apps/dev-app/src/app/app.module.ts
  80. 2
      npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html
  81. 4
      npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html
  82. 2
      npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html
  83. 30
      npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts
  84. 2
      npm/ng-packs/packages/core/src/lib/directives/index.ts
  85. 16
      npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts
  86. 2
      npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html
  87. 4
      npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts

14
.github/scripts/update_versions.py

@ -39,14 +39,16 @@ def create_pr():
branch=branch_name,
)
pr = repo.create_pull(title="Update latest-versions.json",
body="Automated PR to update the latest-versions.json file.",
head=branch_name, base="dev")
try:
pr = repo.create_pull(title="Update latest-versions.json",
body="Automated PR to update the latest-versions.json file.",
head=branch_name, base="dev")
except Exception as e:
print(f"Error while creating PR: {e}")
pr.create_review_request(reviewers=["ebicoglu", "gizemmutukurt", "skoc10"])
pr.create_review_request(reviewers=["gizemmutukurt"])
if __name__ == "__dev__":
if __name__ == "__main__":
should_create_pr = update_latest_versions()
if should_create_pr:
create_pr()

44
.github/workflows/publish-release.yml

@ -0,0 +1,44 @@
name: Create Release
on:
workflow_dispatch:
inputs:
tag_name:
description: 'Tag Name'
required: true
prerelease:
description: 'Pre-release?'
required: true
branchName:
description: 'Branch Name'
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.branchName }}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
with:
tag_name: ${{ github.event.inputs.tag_name }}
release_name: ${{ github.event.inputs.tag_name }}
draft: false
prerelease: ${{ github.event.inputs.prerelease }}
- name: Checkout code at tag
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.tag_name }}
- name: Build Project
run: |
# add your build commands here, depending on your project's requirements.
echo "Build project here"

2
.github/workflows/update-versions.yml

@ -28,6 +28,6 @@ jobs:
- name: Update latest-versions.json and create PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
python .github/scripts/update_versions.py

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

@ -212,6 +212,9 @@
"SpringCampaign": "Welcome <br>Spring Sale!",
"SpringCampaign2": "<span>Limited <br> Time Offer!</span>",
"AboutUs": "About Us",
"HowItWorks": "How it works?"
"HowItWorks": "How it works?",
"ReleaseNotes": "Release Notes",
"DetailedChangeNotes" : "Detailed Change Notes",
"SeeTrainings": "See Trainings"
}
}

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

@ -844,7 +844,7 @@
"BlazoriseSupportExplanation5": "You can post your questions on the support website and generate a product token for your application.",
"AbpLiveTrainingPackages": "ABP Live Training Packages",
"Releases": "Releases",
"ReleasesDescription": "ABP Commercial releases and their changelogs.",
"ReleasesDescription": "Release logs of ABP Commercial.",
"ReleaseDate": "Release Date",
"Labels": "Labels",
"PreRelease": "Pre-release",

17
docs/en/API/Dynamic-CSharp-API-Clients.md

@ -38,20 +38,15 @@ Implement this class in your service application. You can use [auto API controll
## Client Proxy Generation
First, add [Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget package to your client project:
> The startup templates already comes pre-configured for the client proxy generation, in the `HttpApi.Client` project.
If you're not using a startup template, then execute the following command in the folder that contains the .csproj file of your client project:
````
Install-Package Volo.Abp.Http.Client
abp add-package Volo.Abp.Http.Client
````
Then add `AbpHttpClientModule` dependency to your module:
````csharp
[DependsOn(typeof(AbpHttpClientModule))] //add the dependency
public class MyClientAppModule : AbpModule
{
}
````
> If you haven't done it yet, you first need to install the [ABP CLI](../CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Http.Client).
Now, it's ready to create the client proxies. Example:
@ -74,8 +69,6 @@ public class MyClientAppModule : AbpModule
`AddHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, creates and registers proxy classes.
> The startup templates already comes pre-configured for the client proxy generation, in the `HttpApi.Client` project.
### Endpoint Configuration
`RemoteServices` section in the `appsettings.json` file is used to get remote service address by default. The simplest configuration is shown below:

2
docs/en/API/Swagger-Integration.md

@ -21,6 +21,8 @@ Open a command line window in the folder of the `Web` or `HttpApi.Host` project
abp add-package Volo.Abp.Swashbuckle
```
> If you haven't done it yet, you first need to install the [ABP CLI](../CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Swashbuckle).
### Manual Installation
If you want to manually install;

6
docs/en/Application-Startup.md

@ -18,12 +18,14 @@ If you [create a new console application with Visual Studio](https://learn.micro
This example uses the [top level statements](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/top-level-statements), so it consists of only a single line of code.
The first step is to install the [Volo.Abp.Core](https://www.nuget.org/packages/Volo.Abp.Core) NuGet package, which is the most core NuGet package of the ABP framework. You can install it using the [Package Manager Console](https://learn.microsoft.com/en-us/nuget/consume-packages/install-use-packages-powershell) in Visual Studio:
The first step is to install the [Volo.Abp.Core](https://www.nuget.org/packages/Volo.Abp.Core) NuGet package, which is the most core NuGet package of the ABP framework. You can install it using the ABP CLI. Execute the following command in the folder of the .csproj file that you want to install the package on:
````bash
Install-Package Volo.Abp.Core
abp add-package Volo.Abp.Core
````
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Core).
Alternatively, you can use a command-line terminal in the root folder of the project (the folder containing the `MyConsoleDemo.csproj` file, for this example):
````bash

23
docs/en/Autofac-Integration.md

@ -6,27 +6,14 @@
> All the [startup templates](Startup-Templates/Index.md) and samples are Autofac integrated. So, most of the time you don't need to manually install this package.
Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) nuget package to your project (for a multi-projects application, it's suggested to add to the executable/web project).
If you're not using a startup template, you can use the [ABP CLI](CLI.md) to install it to your project. Execute the following command in the folder that contains the .csproj file of your project (suggested to add it to the executable/web project):
````bash
abp add-package Volo.Abp.Autofac
````
Install-Package Volo.Abp.Autofac
````
Then add `AbpAutofacModule` dependency to your module:
```csharp
using Volo.Abp.Modularity;
using Volo.Abp.Autofac;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpAutofacModule))]
public class MyModule : AbpModule
{
//...
}
}
```
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Autofac).
>
Finally, configure `AbpApplicationCreationOptions` to replace default dependency injection services by Autofac. It depends on the application type.

2
docs/en/Background-Jobs-Hangfire.md

@ -16,6 +16,8 @@ Open a command line window in the folder of the project (.csproj file) and type
abp add-package Volo.Abp.BackgroundJobs.HangFire
````
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.BackgroundJobs.HangFire).
### Manual Installation
If you want to manually install;

2
docs/en/Background-Jobs-Quartz.md

@ -16,6 +16,8 @@ Open a command line window in the folder of the project (.csproj file) and type
abp add-package Volo.Abp.BackgroundJobs.Quartz
````
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.BackgroundJobs.Quartz).
### Manual Installation
If you want to manually install;

4
docs/en/CLI-New-Command-Samples.md

@ -73,9 +73,9 @@ The following commands are for creating MVC UI projects:
_Note that Public Website is only included in PRO templates._
## Blazor
## Blazor WebAssembly
The following commands are for creating Blazor projects:
The following commands are for creating Blazor WASM projects:
* **Entity Framework Core**, no mobile app:

19
docs/en/Entity-Framework-Core.md

@ -7,24 +7,11 @@ This document explains how to integrate EF Core as an ORM provider to ABP based
`Volo.Abp.EntityFrameworkCore` is the main NuGet package for the EF Core integration. Install it to your project (for a layered application, to your data/infrastructure layer):
```` shell
Install-Package Volo.Abp.EntityFrameworkCore
abp add-package Volo.Abp.EntityFrameworkCore
````
Then add `AbpEntityFrameworkCoreModule` module dependency (`DependsOn` attribute) to your [module](Module-Development-Basics.md):
````c#
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class MyModule : AbpModule
{
//...
}
}
````
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.EntityFrameworkCore).
>
> Note: Instead, you can directly download a [startup template](https://abp.io/Templates) with EF Core pre-installed.

8
docs/en/Getting-Started-AspNetCore-Application.md

@ -18,11 +18,13 @@ This tutorial explains how to start ABP from scratch with minimal dependencies.
## Install Volo.Abp.AspNetCore.Mvc Package
Volo.Abp.AspNetCore.Mvc is the AspNet Core MVC integration package for ABP. So, install it on your project:
You can use the [ABP CLI](CLI.md) to install the Volo.Abp.AspNetCore.Mvc package to your project. Execute the following command in the folder of the .csproj file that you want to install the package on:
````bash
abp add-package Volo.Abp.AspNetCore.Mvc
````
Install-Package Volo.Abp.AspNetCore.Mvc
````
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.AspNetCore.Mvc).
## Create the First ABP Module

41
docs/en/Getting-Started-React-Native.md

@ -36,17 +36,9 @@ abp new MyCompanyName.MyProjectName -csf -u <angular or mvc> -m react-native
This command will prepare a solution with an **Angular** or an **MVC** (depends on your choice), a **.NET Core**, and a **React Native** project in it.
### 2. Direct Download
### 2. Generating a CLI Command from Get Started Page
You may [download a solution scaffold directly on ABP.io](https://abp.io/get-started) if you are more comfortable with GUI or simply want to try ABP without installing the CLI.
Please do the following:
1. Click on the "DIRECT DOWNLOAD" tab.
2. Fill out the short form about your project.
3. Click on the "Create now" button.
...and a customized download will start in a few seconds.
You can generate a CLI command on the [get started page of the abp.io website](https://abp.io/get-started). Then, use the command on your terminal to create a new [Startup Template](./Startup-Templates/Index.md).
## How to Configure & Run the Backend
@ -54,26 +46,6 @@ Please do the following:
> When you are using OpenIddict, You should remove 'clientSecret' on Environment.js (if exists) and disable "HTTPS-only" settings. (Openiddict has default since Version 6.0)
### How to disable Https-only in Openiddict.
You should add this code on {{ if Tiered == "No" }}`MyProjectNameHttpApiHostModule`{{ else if Tiered == "Yes" }}`MyProjectNameAuthServerModule`{{ end }}.
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
#if DEBUG
PreConfigure<OpenIddictServerBuilder>(options =>
{
options
.UseAspNetCore()
.DisableTransportSecurityRequirement();
});
#endif
//....
}
```
A React Native application running on an Android emulator or a physical phone **can not connect to the backend** on `localhost`. To fix this problem, it is necessary to run the backend application on your **local IP address**.
{{ if Tiered == "No"}}
@ -99,13 +71,14 @@ Run the backend application as described in the [getting started document](Getti
## How to disable the Https-only settings of OpenIddict
Go to MyProjectNameHttpApiHostModule.cs under the host project. And put these codes under the `PreConfigureServices` function.
Open the {{ if Tiered == "No" }}`MyProjectNameHttpApiHostModule`{{ else if Tiered == "Yes" }}`MyProjectNameAuthServerModule`{{ end }} project and copy-paste the below code-block to the `PreConfigureServices` method:
```csharp
#if DEBUG
PreConfigure<OpenIddictServerBuilder>(options => {
options.UseAspNetCore()
.DisableTransportSecurityRequirement();
PreConfigure<OpenIddictServerBuilder>(options =>
{
options.UseAspNetCore()
.DisableTransportSecurityRequirement();
});
#endif
```

8
docs/en/Localization.md

@ -6,11 +6,13 @@ ABP's localization system is seamlessly integrated to the `Microsoft.Extensions.
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
Volo.Abp.Localization is the core package of the localization system. Install it to your project using the package manager console (PMC):
You can use the [ABP CLI](CLI.md) to install the Volo.Abp.Localization package to your project. Execute the following command in the folder of the .csproj file that you want to install the package on:
```bash
abp add-package Volo.Abp.Localization
```
Install-Package Volo.Abp.Localization
```
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Localization).
Then you can add **AbpLocalizationModule** dependency to your module:

8
docs/en/Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md

@ -0,0 +1,8 @@
# ABP Version 7.4 Migration Guide
This document is a guide for upgrading ABP v7.3 solutions to ABP v7.4. There are a few changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application.
## TemplateDefinition
The `LocalizationResource(Type)` of `TemplateDefinition` class is changed to `LocalizationResourceName(string)`.

8
docs/en/Modules/Virtual-File-Explorer.md

@ -10,9 +10,13 @@ Virtual File Explorer Module provided a simple UI to view all files in [virtual
#### 1- Use ABP CLI
It is recommended to use the ABP CLI to install the module, open the CMD window in the solution file (`.sln`) directory, and run the following command:
It is recommended to use the [ABP CLI](../CLI.md) to install the module, open the CMD window in the solution file (`.sln`) directory, and run the following command:
`abp add-module Volo.VirtualFileExplorer`
```
abp add-module Volo.VirtualFileExplorer
```
> If you haven't done it yet, you first need to install the [ABP CLI](../CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.VirtualFileExplorer.Web).
#### 2- Manually install

6
docs/en/MongoDB.md

@ -4,12 +4,14 @@ This document explains how to integrate MongoDB as a database provider to ABP ba
## Installation
`Volo.Abp.MongoDB` is the main nuget package for the MongoDB integration. Install it to your project (for a layered application, to your data/infrastructure layer):
`Volo.Abp.MongoDB` is the main NuGet package for the MongoDB integration. Install it to your project (for a layered application, to your data/infrastructure layer), You can use the [ABP CLI](CLI.md) to install it to your project. Execute the following command in the folder of the .csproj file of the layer:
```
Install-Package Volo.Abp.MongoDB
abp add-package Volo.Abp.MongoDB
```
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.MongoDB).
Then add `AbpMongoDbModule` module dependency to your [module](Module-Development-Basics.md):
```c#

8
docs/en/PlugIn-Modules.md

@ -61,11 +61,13 @@ Create a simple **Class Library Project** in a solution:
![simple-plugin-library](images/simple-plugin-library.png)
You can add ABP Framework packages you need to use in the module. At least, you should add the `Volo.Abp.Core` package to the project:
You can add the ABP Framework packages that you need to use in the module. At least, you should add the `Volo.Abp.Core` package to the project, Execute the following command in the folder of the .csproj file that you want to install the package on:
````bash
abp add-package Volo.Abp.Core
````
Install-Package Volo.Abp.Core
````
If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Core).
Every [module](Module-Development-Basics.md) must declare a class derived from the `AbpModule`. Here, a simple module class that resolves a service and initializes it on the application startup:

6
docs/en/Repositories.md

@ -140,9 +140,9 @@ public async Task<List<PersonDto>> GetListAsync(string filter)
Any standard LINQ method can be used over the `IQueryable` returned from the repository.
> This sample uses `ToList()` method, but it is **strongly suggested to use the asynchronous methods** to perform database queries, like `ToListAsync()` for this example.
>
> See the **IQueryable & Async Operations** section to learn how you can do it.
> This sample uses `ToList()` method, but it is **strongly suggested to use the asynchronous methods** to perform database queries, like `ToListAsync()` for this example. See the **`IQueryable` & Async Operations** section to learn how you can do it.
> **Exposing `IQueryable` to outside of a repository** class may leak your data access logic to the application layer. If you want to strictly follow the **layered architecture** principles, you can consider to implement a custom repository class and wrap your data access logic inside your repository class. You can see the ***Custom Repositories*** section to learn how to create custom repository classes for your application.
### Bulk Operations

2
docs/en/SMS-Sending.md

@ -17,6 +17,8 @@ Open a command line window in the folder of the project (.csproj file) and type
abp add-package Volo.Abp.Sms
```
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.Sms).
### Manual Installation
If you want to manually install;

2
docs/en/SignalR-Integration.md

@ -18,6 +18,8 @@ abp add-package Volo.Abp.AspNetCore.SignalR
> You typically want to add this package to the web or API layer of your application, depending on your architecture.
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.AspNetCore.SignalR).
#### Manual Installation
If you want to manually install;

2
docs/en/Text-Templating-Razor.md

@ -16,6 +16,8 @@ Open a command line window in the folder of the project (.csproj file) and type
abp add-package Volo.Abp.TextTemplating.Razor
````
> If you haven't done it yet, you first need to install the [ABP CLI](CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.TextTemplating.Razor).
### Manual Installation
If you want to manually install;

41
docs/en/UI/AspNetCore/Bundling-Minification.md

@ -12,27 +12,13 @@ ABP offers a simple, dynamic, powerful, modular and built-in way.
> This package is already installed by default with the startup templates. So, most of the time, you don't need to install it manually.
Install the `Volo.Abp.AspNetCore.Mvc.UI.Bundling` nuget package to your project:
If you're not using a startup template, you can use the [ABP CLI](../../CLI.md) to install it to your project. Execute the following command in the folder that contains the .csproj file of your project:
````
install-package Volo.Abp.AspNetCore.Mvc.UI.Bundling
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Bundling
````
Then you can add the `AbpAspNetCoreMvcUiBundlingModule` dependency to your module:
````C#
using Volo.Abp.Modularity;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))]
public class MyWebModule : AbpModule
{
//...
}
}
````
> If you haven't done it yet, you first need to install the [ABP CLI](../../CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.AspNetCore.Mvc.UI.Bundling).
## Razor Bundling Tag Helpers
@ -308,28 +294,13 @@ Using the built-in contributors for standard packages;
> This package is already installed by default in the startup templates. So, most of the time, you don't need to install it manually.
Standard package contributors are defined in the `Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet package.
To install it to your project:
If you're not using a startup template, you can use the [ABP CLI](../../CLI.md) to install it to your project. Execute the following command in the folder that contains the .csproj file of your project:
````
install-package Volo.Abp.AspNetCore.Mvc.UI.Packages
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Packages
````
Then add the `AbpAspNetCoreMvcUiPackagesModule` module dependency to your own module;
````C#
using Volo.Abp.Modularity;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpAspNetCoreMvcUiPackagesModule))]
public class MyWebModule : AbpModule
{
//...
}
}
````
> If you haven't done it yet, you first need to install the [ABP CLI](../../CLI.md). For other installation options, see [the package description page](https://abp.io/package-detail/Volo.Abp.AspNetCore.Mvc.UI.Packages).
### Bundle Inheritance

7
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/StandardLayouts.cs

@ -1,6 +1,11 @@
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout;
using System;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout;
public static class StandardLayouts
{
public const string Application = "Application";
public const string Account = "Account";
public const string Public = "Public";
public const string Empty = "Empty";
}

13
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/AbpThemingOptions.cs

@ -0,0 +1,13 @@
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public class AbpThemingOptions
{
public ThemeDictionary Themes { get; }
public string DefaultThemeName { get; set; }
public AbpThemingOptions()
{
Themes = new ThemeDictionary();
}
}

34
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/DefaultThemeManager.cs

@ -0,0 +1,34 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public class DefaultThemeManager : IThemeManager, IScopedDependency, IServiceProviderAccessor
{
public IServiceProvider ServiceProvider { get; }
public ITheme CurrentTheme => GetCurrentTheme();
private ITheme _currentTheme;
protected IThemeSelector ThemeSelector { get; }
public DefaultThemeManager(
IServiceProvider serviceProvider,
IThemeSelector themeSelector)
{
ServiceProvider = serviceProvider;
ThemeSelector = themeSelector;
}
protected virtual ITheme GetCurrentTheme()
{
if (_currentTheme != null)
{
return _currentTheme;
}
_currentTheme = (ITheme)ServiceProvider.GetRequiredService(ThemeSelector.GetCurrentThemeInfo().ThemeType);
return CurrentTheme;
}
}

36
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/DefaultThemeSelector.cs

@ -0,0 +1,36 @@
using System.Linq;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public class DefaultThemeSelector : IThemeSelector, ITransientDependency
{
protected AbpThemingOptions Options { get; }
public DefaultThemeSelector(IOptions<AbpThemingOptions> options)
{
Options = options.Value;
}
public virtual ThemeInfo GetCurrentThemeInfo()
{
if (!Options.Themes.Any())
{
throw new AbpException($"No theme registered! Use {nameof(AbpThemingOptions)} to register themes.");
}
if (Options.DefaultThemeName == null)
{
return Options.Themes.Values.First();
}
var themeInfo = Options.Themes.Values.FirstOrDefault(t => t.Name == Options.DefaultThemeName);
if (themeInfo == null)
{
throw new AbpException("Default theme is configured but it's not found in the registered themes: " + Options.DefaultThemeName);
}
return themeInfo;
}
}

8
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ITheme.cs

@ -0,0 +1,8 @@
using System;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public interface ITheme
{
Type GetLayout(string name, bool fallbackToDefault = true);
}

6
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/IThemeManager.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public interface IThemeManager
{
ITheme CurrentTheme { get; }
}

6
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/IThemeSelector.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public interface IThemeSelector
{
ThemeInfo GetCurrentThemeInfo();
}

23
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeDictionary.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public class ThemeDictionary : Dictionary<Type, ThemeInfo>
{
public ThemeInfo Add<TTheme>()
where TTheme : ITheme
{
return Add(typeof(TTheme));
}
public ThemeInfo Add(Type themeType)
{
if (ContainsKey(themeType))
{
throw new AbpException("This theme is already added before: " + themeType.AssemblyQualifiedName);
}
return this[themeType] = new ThemeInfo(themeType);
}
}

27
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeExtensions.cs

@ -0,0 +1,27 @@
using System;
using Volo.Abp.AspNetCore.Components.Web.Theming.Layout;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public static class ThemeExtensions
{
public static Type GetApplicationLayout(this ITheme theme, bool fallbackToDefault = true)
{
return theme.GetLayout(StandardLayouts.Application, fallbackToDefault);
}
public static Type GetAccountLayout(this ITheme theme, bool fallbackToDefault = true)
{
return theme.GetLayout(StandardLayouts.Account, fallbackToDefault);
}
public static Type GetPublicLayout(this ITheme theme, bool fallbackToDefault = true)
{
return theme.GetLayout(StandardLayouts.Public, fallbackToDefault);
}
public static Type GetEmptyLayout(this ITheme theme, bool fallbackToDefault = true)
{
return theme.GetLayout(StandardLayouts.Empty, fallbackToDefault);
}
}

24
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeInfo.cs

@ -0,0 +1,24 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
public class ThemeInfo
{
public Type ThemeType { get; }
public string Name { get; }
public ThemeInfo([NotNull] Type themeType)
{
Check.NotNull(themeType, nameof(themeType));
if (!typeof(ITheme).IsAssignableFrom(themeType))
{
throw new AbpException($"Given {nameof(themeType)} ({themeType.AssemblyQualifiedName}) should be type of {typeof(ITheme).AssemblyQualifiedName}");
}
ThemeType = themeType;
Name = ThemeNameAttribute.GetName(themeType);
}
}

23
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Theming/ThemeNameAttribute.cs

@ -0,0 +1,23 @@
using System;
using System.Linq;
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
[AttributeUsage(AttributeTargets.Class)]
public class ThemeNameAttribute : Attribute
{
public string Name { get; set; }
public ThemeNameAttribute(string name)
{
Name = name;
}
public static string GetName(Type themeType)
{
return themeType
.GetCustomAttributes(true)
.OfType<ThemeNameAttribute>()
.FirstOrDefault()?.Name ?? themeType.Name;
}
}

12
framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs

@ -24,4 +24,16 @@ public class AbpDatabaseInfo
DatabaseName = databaseName;
MappedConnections = new HashSet<string>();
}
/// <summary>
/// Shortcut method to add one or multiple connections to the <see cref="MappedConnections"/> collection.
/// </summary>
/// <param name="connectionNames"></param>
public void MapConnection(params string[] connectionNames)
{
foreach (var connectionName in connectionNames)
{
MappedConnections.AddIfNotContains(connectionName);
}
}
}

12
framework/src/Volo.Abp.Data/Volo/Abp/Data/AppliedDatabaseMigrationsEto.cs

@ -0,0 +1,12 @@
using System;
using Volo.Abp.EventBus;
namespace Volo.Abp.Data;
[Serializable]
[EventName("abp.data.applied_database_migrations")]
public class AppliedDatabaseMigrationsEto
{
public string DatabaseName { get; set; }
public Guid? TenantId { get; set; }
}

318
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/DatabaseMigrationEventHandlerBase.cs

@ -0,0 +1,318 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
namespace Volo.Abp.EntityFrameworkCore.Migrations;
public abstract class DatabaseMigrationEventHandlerBase<TDbContext> :
IDistributedEventHandler<TenantCreatedEto>,
IDistributedEventHandler<TenantConnectionStringUpdatedEto>,
IDistributedEventHandler<ApplyDatabaseMigrationsEto>,
ITransientDependency
where TDbContext : DbContext, IEfCoreDbContext
{
protected string DatabaseName { get; }
protected const string TryCountPropertyName = "__TryCount";
protected int MaxEventTryCount { get; set; } = 3;
/// <summary>
/// As milliseconds.
/// </summary>
protected int MinValueToWaitOnFailure { get; set; } = 5000;
/// <summary>
/// As milliseconds.
/// </summary>
protected int MaxValueToWaitOnFailure { get; set; } = 15000;
protected ICurrentTenant CurrentTenant { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected ITenantStore TenantStore { get; }
protected IDistributedEventBus DistributedEventBus { get; }
protected ILogger<DatabaseMigrationEventHandlerBase<TDbContext>> Logger { get; }
protected DatabaseMigrationEventHandlerBase(
string databaseName,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
ITenantStore tenantStore,
IDistributedEventBus distributedEventBus,
ILoggerFactory loggerFactory)
{
CurrentTenant = currentTenant;
UnitOfWorkManager = unitOfWorkManager;
TenantStore = tenantStore;
DatabaseName = databaseName;
DistributedEventBus = distributedEventBus;
Logger = loggerFactory.CreateLogger<DatabaseMigrationEventHandlerBase<TDbContext>>();
}
public virtual async Task HandleEventAsync(ApplyDatabaseMigrationsEto eventData)
{
if (eventData.DatabaseName != DatabaseName)
{
return;
}
var schemaMigrated = false;
try
{
schemaMigrated = await MigrateDatabaseSchemaAsync(eventData.TenantId);
await SeedAsync(eventData.TenantId);
if (schemaMigrated)
{
await DistributedEventBus.PublishAsync(
new AppliedDatabaseMigrationsEto
{
DatabaseName = DatabaseName,
TenantId = eventData.TenantId
}
);
}
}
catch (Exception ex)
{
await HandleErrorOnApplyDatabaseMigrationAsync(eventData, ex);
}
await AfterApplyDatabaseMigrations(eventData, schemaMigrated);
}
protected virtual Task AfterApplyDatabaseMigrations(ApplyDatabaseMigrationsEto eventData, bool schemaMigrated)
{
return Task.CompletedTask;
}
public virtual async Task HandleEventAsync(TenantCreatedEto eventData)
{
var schemaMigrated = false;
try
{
schemaMigrated = await MigrateDatabaseSchemaAsync(eventData.Id);
await SeedAsync(eventData.Id);
if (schemaMigrated)
{
await DistributedEventBus.PublishAsync(
new AppliedDatabaseMigrationsEto
{
DatabaseName = DatabaseName,
TenantId = eventData.Id
}
);
}
}
catch (Exception ex)
{
await HandleErrorTenantCreatedAsync(eventData, ex);
}
await AfterTenantCreated(eventData, schemaMigrated);
}
protected virtual Task AfterTenantCreated(TenantCreatedEto eventData, bool schemaMigrated)
{
return Task.CompletedTask;
}
public virtual async Task HandleEventAsync(TenantConnectionStringUpdatedEto eventData)
{
if (eventData.ConnectionStringName != DatabaseName &&
eventData.ConnectionStringName != Volo.Abp.Data.ConnectionStrings.DefaultConnectionStringName ||
eventData.NewValue.IsNullOrWhiteSpace())
{
return;
}
var schemaMigrated = false;
try
{
schemaMigrated = await MigrateDatabaseSchemaAsync(eventData.Id);
await SeedAsync(eventData.Id);
if (schemaMigrated)
{
await DistributedEventBus.PublishAsync(
new AppliedDatabaseMigrationsEto
{
DatabaseName = DatabaseName,
TenantId = eventData.Id
}
);
}
}
catch (Exception ex)
{
await HandleErrorTenantConnectionStringUpdatedAsync(eventData, ex);
}
await AfterTenantConnectionStringUpdated(eventData, schemaMigrated);
}
protected virtual Task AfterTenantConnectionStringUpdated(TenantConnectionStringUpdatedEto eventData,
bool schemaMigrated)
{
return Task.CompletedTask;
}
protected virtual Task SeedAsync(Guid? tenantId)
{
return Task.CompletedTask;
}
/// <summary>
/// Apply pending EF Core schema migrations to the database.
/// Returns true if any migration has applied.
/// </summary>
protected virtual async Task<bool> MigrateDatabaseSchemaAsync(Guid? tenantId)
{
var result = false;
using (CurrentTenant.Change(tenantId))
{
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
{
async Task<bool> MigrateDatabaseSchemaWithDbContextAsync()
{
var dbContext = await uow.ServiceProvider
.GetRequiredService<IDbContextProvider<TDbContext>>()
.GetDbContextAsync();
if ((await dbContext.Database.GetPendingMigrationsAsync()).Any())
{
await dbContext.Database.MigrateAsync();
return true;
}
return false;
}
if (tenantId == null)
{
//Migrating the host database
Logger.LogInformation($"Migrating database of host. Database Name = {DatabaseName}");
result = await MigrateDatabaseSchemaWithDbContextAsync();
}
else
{
var tenantConfiguration = await TenantStore.FindAsync(tenantId.Value);
if (!tenantConfiguration.ConnectionStrings.Default.IsNullOrWhiteSpace() ||
!tenantConfiguration.ConnectionStrings.GetOrDefault(DatabaseName).IsNullOrWhiteSpace())
{
//Migrating the tenant database (only if tenant has a separate database)
Logger.LogInformation(
$"Migrating separate database of tenant. Database Name = {DatabaseName}, TenantId = {tenantId}");
result = await MigrateDatabaseSchemaWithDbContextAsync();
}
}
await uow.CompleteAsync();
}
}
return result;
}
protected virtual async Task HandleErrorOnApplyDatabaseMigrationAsync(
ApplyDatabaseMigrationsEto eventData,
Exception exception)
{
var tryCount = IncrementEventTryCount(eventData);
if (tryCount <= MaxEventTryCount)
{
Logger.LogWarning(
$"Could not apply database migrations. Re-queueing the operation. TenantId = {eventData.TenantId}, Database Name = {eventData.DatabaseName}.");
Logger.LogException(exception, LogLevel.Warning);
await Task.Delay(RandomHelper.GetRandom(MinValueToWaitOnFailure, MaxValueToWaitOnFailure));
await DistributedEventBus.PublishAsync(eventData);
}
else
{
Logger.LogError(
$"Could not apply database migrations. Canceling the operation. TenantId = {eventData.TenantId}, DatabaseName = {eventData.DatabaseName}.");
Logger.LogException(exception);
}
}
protected virtual async Task HandleErrorTenantCreatedAsync(
TenantCreatedEto eventData,
Exception exception)
{
var tryCount = IncrementEventTryCount(eventData);
if (tryCount <= MaxEventTryCount)
{
Logger.LogWarning(
$"Could not perform tenant created event. Re-queueing the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}.");
Logger.LogException(exception, LogLevel.Warning);
await Task.Delay(RandomHelper.GetRandom(5000, 15000));
await DistributedEventBus.PublishAsync(eventData);
}
else
{
Logger.LogError(
$"Could not perform tenant created event. Canceling the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}.");
Logger.LogException(exception);
}
}
protected virtual async Task HandleErrorTenantConnectionStringUpdatedAsync(
TenantConnectionStringUpdatedEto eventData,
Exception exception)
{
var tryCount = IncrementEventTryCount(eventData);
if (tryCount <= MaxEventTryCount)
{
Logger.LogWarning(
$"Could not perform tenant connection string updated event. Re-queueing the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}.");
Logger.LogException(exception, LogLevel.Warning);
await Task.Delay(RandomHelper.GetRandom(5000, 15000));
await DistributedEventBus.PublishAsync(eventData);
}
else
{
Logger.LogError(
$"Could not perform tenant connection string updated event. Canceling the operation. TenantId = {eventData.Id}, TenantName = {eventData.Name}.");
Logger.LogException(exception);
}
}
private static int GetEventTryCount(EtoBase eventData)
{
var tryCountAsString = eventData.Properties.GetOrDefault(TryCountPropertyName);
if (tryCountAsString.IsNullOrEmpty())
{
return 0;
}
return int.Parse(tryCountAsString);
}
private static void SetEventTryCount(EtoBase eventData, int count)
{
eventData.Properties[TryCountPropertyName] = count.ToString();
}
private static int IncrementEventTryCount(EtoBase eventData)
{
var count = GetEventTryCount(eventData) + 1;
SetEventTryCount(eventData, count);
return count;
}
}

145
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Migrations/EfCoreRuntimeDatabaseMigratorBase.cs

@ -0,0 +1,145 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DistributedLocking;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
namespace Volo.Abp.EntityFrameworkCore.Migrations;
public abstract class EfCoreRuntimeDatabaseMigratorBase<TDbContext> : ITransientDependency
where TDbContext : DbContext, IEfCoreDbContext
{
protected int MinValueToWaitOnFailure { get; set; } = 5000;
protected int MaxValueToWaitOnFailure { get; set; } = 15000;
protected string DatabaseName { get; }
/// <summary>
/// Enabling this might be inefficient if you have many tenants!
/// If disabled (default), tenant databases will be seeded only
/// if there is a schema migration applied to the host database.
/// If enabled, tenant databases will be seeded always on every service startup.
/// </summary>
protected bool AlwaysSeedTenantDatabases { get; set; } = false;
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IServiceProvider ServiceProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IAbpDistributedLock DistributedLock { get; }
protected IDistributedEventBus DistributedEventBus { get; }
protected ILogger<EfCoreRuntimeDatabaseMigratorBase<TDbContext>> Logger { get; }
protected EfCoreRuntimeDatabaseMigratorBase(
string databaseName,
IUnitOfWorkManager unitOfWorkManager,
IServiceProvider serviceProvider,
ICurrentTenant currentTenant,
IAbpDistributedLock abpDistributedLock,
IDistributedEventBus distributedEventBus,
ILoggerFactory loggerFactory)
{
DatabaseName = databaseName;
UnitOfWorkManager = unitOfWorkManager;
ServiceProvider = serviceProvider;
CurrentTenant = currentTenant;
DistributedLock = abpDistributedLock;
DistributedEventBus = distributedEventBus;
Logger = loggerFactory.CreateLogger<EfCoreRuntimeDatabaseMigratorBase<TDbContext>>();
}
public virtual async Task CheckAndApplyDatabaseMigrationsAsync()
{
await TryAsync(LockAndApplyDatabaseMigrationsAsync);
}
protected virtual async Task LockAndApplyDatabaseMigrationsAsync()
{
Logger.LogInformation($"Trying to acquire the distributed lock for database migration: {DatabaseName}.");
var schemaMigrated = false;
await using (var handle = await DistributedLock.TryAcquireAsync("DatabaseMigration_" + DatabaseName))
{
if (handle is null)
{
Logger.LogInformation($"Distributed lock could not be acquired for database migration: {DatabaseName}. Operation cancelled.");
return;
}
Logger.LogInformation($"Distributed lock is acquired for database migration: {DatabaseName}...");
using (CurrentTenant.Change(null))
{
// Create database tables if needed
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false))
{
var dbContext = await ServiceProvider
.GetRequiredService<IDbContextProvider<TDbContext>>()
.GetDbContextAsync();
var pendingMigrations = await dbContext
.Database
.GetPendingMigrationsAsync();
if (pendingMigrations.Any())
{
await dbContext.Database.MigrateAsync();
schemaMigrated = true;
}
await uow.CompleteAsync();
}
}
await SeedAsync();
if (schemaMigrated || AlwaysSeedTenantDatabases)
{
await DistributedEventBus.PublishAsync(
new AppliedDatabaseMigrationsEto
{
DatabaseName = DatabaseName,
TenantId = null
}
);
}
}
Logger.LogInformation($"Distributed lock has been released for database migration: {DatabaseName}...");
}
protected virtual Task SeedAsync()
{
return Task.CompletedTask;
}
protected virtual async Task TryAsync(Func<Task> task, int maxTryCount = 3)
{
try
{
await task();
}
catch (Exception ex)
{
maxTryCount--;
if (maxTryCount <= 0)
{
throw;
}
Logger.LogWarning($"{ex.GetType().Name} has been thrown. The operation will be tried {maxTryCount} times more. Exception:\n{ex.Message}. Stack Trace:\n{ex.StackTrace}");
await Task.Delay(RandomHelper.GetRandom(MinValueToWaitOnFailure, MaxValueToWaitOnFailure));
await TryAsync(task, maxTryCount);
}
}
}

2
framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj

@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.29" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.2" />
</ItemGroup>
<ItemGroup>

2
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs

@ -29,7 +29,7 @@ public class AbpTemplateRenderer : ITemplateRenderer, ITransientDependency
string cultureName = null,
Dictionary<string, object> globalContext = null)
{
var templateDefinition = TemplateDefinitionManager.Get(templateName);
var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName);
var renderEngine = templateDefinition.RenderEngine;

3
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs

@ -12,10 +12,13 @@ public class AbpTextTemplatingOptions
public string DefaultRenderingEngine { get; set; }
public HashSet<string> DeletedTemplates { get; }
public AbpTextTemplatingOptions()
{
DefinitionProviders = new TypeList<ITemplateDefinitionProvider>();
ContentContributors = new TypeList<ITemplateContentContributor>();
RenderingEngines = new Dictionary<string, Type>();
DeletedTemplates = new HashSet<string>();
}
}

14
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.TextTemplating;
public interface IDynamicTemplateDefinitionStore
{
Task<TemplateDefinition> GetAsync([NotNull] string name);
Task<IReadOnlyList<TemplateDefinition>> GetAllAsync();
Task<TemplateDefinition> GetOrNullAsync(string name);
}

14
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.TextTemplating;
public interface IStaticTemplateDefinitionStore
{
Task<TemplateDefinition> GetAsync([NotNull] string name);
Task<IReadOnlyList<TemplateDefinition>> GetAllAsync();
Task<TemplateDefinition> GetOrNullAsync(string name);
}

13
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs

@ -1,16 +1,17 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.TextTemplating;
public interface ITemplateDefinitionManager
{
[NotNull]
TemplateDefinition Get([NotNull] string name);
[ItemNotNull]
Task<TemplateDefinition> GetAsync([NotNull] string name);
[NotNull]
IReadOnlyList<TemplateDefinition> GetAll();
[ItemNotNull]
Task<IReadOnlyList<TemplateDefinition>> GetAllAsync();
[CanBeNull]
TemplateDefinition GetOrNull(string name);
[ItemCanBeNull]
Task<TemplateDefinition> GetOrNullAsync(string name);
}

29
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.TextTemplating;
public class NullIDynamicTemplateDefinitionStore : IDynamicTemplateDefinitionStore, ISingletonDependency
{
private readonly static Task<TemplateDefinition> CachedTemplateResult = Task.FromResult((TemplateDefinition)null);
private readonly static Task<IReadOnlyList<TemplateDefinition>> CachedFeaturesResult = Task.FromResult((IReadOnlyList<TemplateDefinition>)Array.Empty<TemplateDefinition>().ToImmutableList());
public Task<TemplateDefinition> GetAsync(string name)
{
return CachedTemplateResult;
}
public Task<IReadOnlyList<TemplateDefinition>> GetAllAsync()
{
return CachedFeaturesResult;
}
public Task<TemplateDefinition> GetOrNullAsync(string name)
{
return CachedTemplateResult;
}
}

83
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.TextTemplating;
public class StaticTemplateDefinitionStore : IStaticTemplateDefinitionStore, ISingletonDependency
{
protected Lazy<IDictionary<string, TemplateDefinition>> TemplateDefinitions { get; }
protected AbpTextTemplatingOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
public StaticTemplateDefinitionStore(IOptions<AbpTextTemplatingOptions> options, IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
Options = options.Value;
TemplateDefinitions = new Lazy<IDictionary<string, TemplateDefinition>>(CreateTextTemplateDefinitions, true);
}
public virtual Task<TemplateDefinition> GetAsync(string name)
{
Check.NotNull(name, nameof(name));
var template = GetOrNullAsync(name);
if (template == null)
{
throw new AbpException("Undefined template: " + name);
}
return template;
}
public virtual Task<IReadOnlyList<TemplateDefinition>> GetAllAsync()
{
return Task.FromResult<IReadOnlyList<TemplateDefinition>>(TemplateDefinitions.Value.Values.ToImmutableList());
}
public virtual Task<TemplateDefinition> GetOrNullAsync(string name)
{
return Task.FromResult(TemplateDefinitions.Value.GetOrDefault(name));
}
protected virtual IDictionary<string, TemplateDefinition> CreateTextTemplateDefinitions()
{
var templates = new Dictionary<string, TemplateDefinition>();
using (var scope = ServiceProvider.CreateScope())
{
var providers = Options
.DefinitionProviders
.Select(p => scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider)
.ToList();
var context = new TemplateDefinitionContext(templates);
foreach (var provider in providers)
{
provider.PreDefine(context);
}
foreach (var provider in providers)
{
provider.Define(context);
}
foreach (var provider in providers)
{
provider.PostDefine(context);
}
}
return templates;
}
}

6
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs

@ -26,14 +26,14 @@ public class TemplateContentProvider : ITemplateContentProvider, ITransientDepen
_templateDefinitionManager = templateDefinitionManager;
}
public virtual Task<string> GetContentOrNullAsync(
public virtual async Task<string> GetContentOrNullAsync(
[NotNull] string templateName,
[CanBeNull] string cultureName = null,
bool tryDefaults = true,
bool useCurrentCultureIfCultureNameIsNull = true)
{
var template = _templateDefinitionManager.Get(templateName);
return GetContentOrNullAsync(template, cultureName);
var template = await _templateDefinitionManager.GetAsync(templateName);
return await GetContentOrNullAsync(template, cultureName);
}
public virtual async Task<string> GetContentOrNullAsync(

18
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs

@ -28,7 +28,7 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName
public string Layout { get; set; }
[CanBeNull]
public Type LocalizationResource { get; set; }
public string LocalizationResourceName { get; set; }
public bool IsInlineLocalized { get; set; }
@ -60,14 +60,26 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName
public TemplateDefinition(
[NotNull] string name,
[CanBeNull] Type localizationResource = null,
[NotNull] Type localizationResource,
[CanBeNull] ILocalizableString displayName = null,
bool isLayout = false,
string layout = null,
string defaultCultureName = null)
: this(name, LocalizationResourceNameAttribute.GetName(localizationResource), displayName, isLayout, layout, defaultCultureName)
{
}
public TemplateDefinition(
[NotNull] string name,
[CanBeNull] string localizationResourceName = null,
[CanBeNull] ILocalizableString displayName = null,
bool isLayout = false,
string layout = null,
string defaultCultureName = null)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name), MaxNameLength);
LocalizationResource = localizationResource;
LocalizationResourceName = localizationResourceName;
DisplayName = displayName ?? new FixedLocalizableString(Name);
IsLayout = isLayout;
Layout = layout;

81
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs

@ -1,85 +1,50 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.TextTemplating;
public class TemplateDefinitionManager : ITemplateDefinitionManager, ISingletonDependency
{
protected Lazy<IDictionary<string, TemplateDefinition>> TemplateDefinitions { get; }
protected readonly IStaticTemplateDefinitionStore StaticStore;
protected readonly IDynamicTemplateDefinitionStore DynamicStore;
protected AbpTextTemplatingOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
public TemplateDefinitionManager(
IOptions<AbpTextTemplatingOptions> options,
IServiceProvider serviceProvider)
public TemplateDefinitionManager(IStaticTemplateDefinitionStore staticStore, IDynamicTemplateDefinitionStore dynamicStore)
{
ServiceProvider = serviceProvider;
Options = options.Value;
TemplateDefinitions =
new Lazy<IDictionary<string, TemplateDefinition>>(CreateTextTemplateDefinitions, true);
StaticStore = staticStore;
DynamicStore = dynamicStore;
}
public virtual TemplateDefinition Get(string name)
public virtual async Task<TemplateDefinition> GetAsync(string name)
{
Check.NotNull(name, nameof(name));
var template = GetOrNull(name);
if (template == null)
var permission = await GetOrNullAsync(name);
if (permission == null)
{
throw new AbpException("Undefined template: " + name);
throw new AbpException("Undefined Template: " + name);
}
return template;
return permission;
}
public virtual IReadOnlyList<TemplateDefinition> GetAll()
public virtual async Task<TemplateDefinition> GetOrNullAsync(string name)
{
return TemplateDefinitions.Value.Values.ToImmutableList();
}
Check.NotNull(name, nameof(name));
public virtual TemplateDefinition GetOrNull(string name)
{
return TemplateDefinitions.Value.GetOrDefault(name);
return await StaticStore.GetOrNullAsync(name) ?? await DynamicStore.GetOrNullAsync(name);
}
protected virtual IDictionary<string, TemplateDefinition> CreateTextTemplateDefinitions()
public virtual async Task<IReadOnlyList<TemplateDefinition>> GetAllAsync()
{
var templates = new Dictionary<string, TemplateDefinition>();
using (var scope = ServiceProvider.CreateScope())
{
var providers = Options
.DefinitionProviders
.Select(p => scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider)
.ToList();
var context = new TemplateDefinitionContext(templates);
var staticTemplates = await StaticStore.GetAllAsync();
var staticTemplateNames = staticTemplates
.Select(p => p.Name)
.ToImmutableHashSet();
foreach (var provider in providers)
{
provider.PreDefine(context);
}
foreach (var provider in providers)
{
provider.Define(context);
}
foreach (var provider in providers)
{
provider.PostDefine(context);
}
}
var dynamicTemplates = await DynamicStore.GetAllAsync();
return templates;
/* We prefer static Templates over dynamics */
return staticTemplates.Concat(dynamicTemplates.Where(d => !staticTemplateNames.Contains(d.Name))).ToImmutableList();
}
}

4
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs

@ -31,9 +31,9 @@ public abstract class TemplateRenderingEngineBase : ITemplateRenderingEngine
protected virtual IStringLocalizer GetLocalizerOrNull(TemplateDefinition templateDefinition)
{
if (templateDefinition.LocalizationResource != null)
if (templateDefinition.LocalizationResourceName != null)
{
return StringLocalizerFactory.Create(templateDefinition.LocalizationResource);
return StringLocalizerFactory.CreateByResourceName(templateDefinition.LocalizationResourceName);
}
return StringLocalizerFactory.CreateDefaultOrNull();

11
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs

@ -5,10 +5,12 @@ namespace Volo.Abp.TextTemplating.VirtualFiles;
public class FileInfoLocalizedTemplateContentReader : ILocalizedTemplateContentReader
{
private IFileInfo _fileInfo;
private string _content;
public async Task ReadContentsAsync(IFileInfo fileInfo)
{
_fileInfo = fileInfo;
_content = await fileInfo.ReadAsStringAsync();
}
@ -21,4 +23,13 @@ public class FileInfoLocalizedTemplateContentReader : ILocalizedTemplateContentR
return null;
}
public TemplateContentFileInfo GetFile()
{
return new TemplateContentFileInfo()
{
FileName = _fileInfo.Name,
FileContent = _content
};
}
}

8
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.TextTemplating.VirtualFiles;
public class TemplateContentFileInfo
{
public string FileName { get; set; }
public string FileContent { get; set; }
}

56
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider.cs

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.TextTemplating.VirtualFiles;
public class TemplateContentFileProvider : ITransientDependency
{
protected IVirtualFileProvider VirtualFileProvider { get; }
public TemplateContentFileProvider(IVirtualFileProvider virtualFileProvider)
{
VirtualFileProvider = virtualFileProvider;
}
public async Task<List<TemplateContentFileInfo>> GetFilesAsync(TemplateDefinition templateDefinition)
{
var files = new List<TemplateContentFileInfo>();
var virtualPath = templateDefinition.GetVirtualFilePathOrNull();
if (virtualPath == null)
{
return files;
}
var fileInfo = VirtualFileProvider.GetFileInfo(virtualPath);
if (!fileInfo.Exists)
{
var directoryContents = VirtualFileProvider.GetDirectoryContents(virtualPath);
if (!directoryContents.Exists)
{
throw new AbpException("Could not find a file/folder at the location: " + virtualPath);
}
fileInfo = new VirtualDirectoryFileInfo(virtualPath, virtualPath, DateTimeOffset.UtcNow);
}
if (fileInfo.IsDirectory)
{
//TODO: Configure file extensions.
var folderReader = new VirtualFolderLocalizedTemplateContentReader(new[] { ".tpl", ".cshtml" });
await folderReader.ReadContentsAsync(VirtualFileProvider, virtualPath);
files.AddRange(folderReader.GetFiles());
}
else
{
var singleFileReader = new FileInfoLocalizedTemplateContentReader();
await singleFileReader.ReadContentsAsync(fileInfo);
files.Add(singleFileReader.GetFile());
}
return files;
}
}

18
framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.VirtualFileSystem;
@ -8,7 +9,7 @@ namespace Volo.Abp.TextTemplating.VirtualFiles;
public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateContentReader
{
private Dictionary<string, string> _dictionary;
private Dictionary<string, TemplateContentFileInfo> _dictionary;
private readonly string[] _fileExtension;
public VirtualFolderLocalizedTemplateContentReader(string[] fileExtension)
@ -20,7 +21,7 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon
IVirtualFileProvider virtualFileProvider,
string virtualPath)
{
_dictionary = new Dictionary<string, string>();
_dictionary = new Dictionary<string, TemplateContentFileInfo>();
var directoryContents = virtualFileProvider.GetDirectoryContents(virtualPath);
if (!directoryContents.Exists)
@ -35,7 +36,11 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon
continue;
}
_dictionary.Add(file.Name.RemovePostFix(_fileExtension), await file.ReadAsStringAsync());
_dictionary.Add(file.Name.RemovePostFix(_fileExtension), new TemplateContentFileInfo()
{
FileName = file.Name,
FileContent = await file.ReadAsStringAsync()
});
}
}
@ -46,6 +51,11 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon
return null;
}
return _dictionary.GetOrDefault(cultureName);
return _dictionary.GetOrDefault(cultureName)?.FileContent;
}
public List<TemplateContentFileInfo> GetFiles()
{
return _dictionary.Values.ToList();
}
}

5
framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs

@ -45,6 +45,11 @@ public class DefaultAbpCompiledViewProvider : IAbpCompiledViewProvider, ITransie
}
var templateContent = await _templateContentProvider.GetContentOrNullAsync(templateDefinition);
if (templateContent == null)
{
throw new AbpException($"Razor template content of {templateDefinition.Name} is null!");
}
return CachedAssembles.GetOrAdd((templateDefinition.Name + templateContent).ToMd5(), await CreateAssembly(templateContent));
}

2
framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs

@ -74,7 +74,7 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi
Dictionary<string, object> globalContext,
object model = null)
{
var templateDefinition = TemplateDefinitionManager.Get(templateName);
var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName);
var renderedContent = await RenderSingleTemplateAsync(
templateDefinition,

2
framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs

@ -61,7 +61,7 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran
Dictionary<string, object> globalContext,
object model = null)
{
var templateDefinition = TemplateDefinitionManager.Get(templateName);
var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName);
var renderedContent = await RenderSingleTemplateAsync(
templateDefinition,

20
framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs

@ -75,7 +75,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
if (Options != null)
{
throw new AbpException("This unit of work is already initialized before!");
throw new AbpException("This unit of work has already been initialized.");
}
Options = _defaultOptions.Normalize(options.Clone());
@ -84,7 +84,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
public virtual void Reserve(string reservationName)
{
Check.NotNull(reservationName, nameof(reservationName));
Check.NotNullOrWhiteSpace(reservationName, nameof(reservationName));
ReservationName = reservationName;
IsReserved = true;
@ -188,12 +188,12 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
public virtual void AddDatabaseApi(string key, IDatabaseApi api)
{
Check.NotNull(key, nameof(key));
Check.NotNullOrWhiteSpace(key, nameof(key));
Check.NotNull(api, nameof(api));
if (_databaseApis.ContainsKey(key))
{
throw new AbpException("There is already a database API in this unit of work with given key.");
throw new AbpException("This unit of work already contains a database API for the given key.");
}
_databaseApis.Add(key, api);
@ -201,7 +201,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
public virtual IDatabaseApi GetOrAddDatabaseApi(string key, Func<IDatabaseApi> factory)
{
Check.NotNull(key, nameof(key));
Check.NotNullOrWhiteSpace(key, nameof(key));
Check.NotNull(factory, nameof(factory));
return _databaseApis.GetOrAdd(key, factory);
@ -209,19 +209,19 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
public virtual ITransactionApi FindTransactionApi(string key)
{
Check.NotNull(key, nameof(key));
Check.NotNullOrWhiteSpace(key, nameof(key));
return _transactionApis.GetOrDefault(key);
}
public virtual void AddTransactionApi(string key, ITransactionApi api)
{
Check.NotNull(key, nameof(key));
Check.NotNullOrWhiteSpace(key, nameof(key));
Check.NotNull(api, nameof(api));
if (_transactionApis.ContainsKey(key))
{
throw new AbpException("There is already a transaction API in this unit of work with given key.");
throw new AbpException("This unit of work already contains a transaction API for the given key.");
}
_transactionApis.Add(key, api);
@ -229,7 +229,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
public virtual ITransactionApi GetOrAddTransactionApi(string key, Func<ITransactionApi> factory)
{
Check.NotNull(key, nameof(key));
Check.NotNullOrWhiteSpace(key, nameof(key));
Check.NotNull(factory, nameof(factory));
return _transactionApis.GetOrAdd(key, factory);
@ -332,7 +332,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
{
if (IsCompleted || _isCompleting)
{
throw new AbpException("Complete is called before!");
throw new AbpException("Completion has already been requested for this unit of work.");
}
}

2
framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs

@ -38,7 +38,7 @@ public class AbpCompiledViewProviderOptions_Tests : TemplateDefinitionTests<Razo
[Fact]
public async Task Custom_TemplateReferences_Test()
{
var templateDefinition = _templateDefinitionManager.GetOrNull(RazorTestTemplates.TestTemplate);
var templateDefinition = await _templateDefinitionManager.GetOrNullAsync(RazorTestTemplates.TestTemplate);
var assembly = await _compiledViewProvider.GetAssemblyAsync(templateDefinition);

19
framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateContentFileProvider_Tests.cs

@ -0,0 +1,19 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.TextTemplating.VirtualFiles;
using Xunit;
namespace Volo.Abp.TextTemplating.Razor;
public class RazorTemplateContentFileProvider_Tests : TemplateContentFileProvider_Tests<RazorTextTemplatingTestModule>
{
[Fact]
public async Task GetRazorFilesAsync()
{
var definition = await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail);
var files = await TemplateContentFileProvider.GetFilesAsync(definition);
files.Count.ShouldBe(2);
files.ShouldContain(x => x.FileName == "en.cshtml" && x.FileContent.Contains("Welcome @Model.Name to the abp.io!"));
files.ShouldContain(x => x.FileName == "tr.cshtml" && x.FileContent.Contains("Merhaba @Model.Name, abp.io'ya hoşgeldiniz!"));
}
}

19
framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ScribanTemplateContentFileProvider_Tests.cs

@ -0,0 +1,19 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.TextTemplating.VirtualFiles;
using Xunit;
namespace Volo.Abp.TextTemplating.Scriban.SampleTemplates;
public class ScribanTemplateContentFileProvider_Tests : TemplateContentFileProvider_Tests<ScribanTextTemplatingTestModule>
{
[Fact]
public async Task GetScribanFilesAsync()
{
var definition = await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail);
var files = await TemplateContentFileProvider.GetFilesAsync(definition);
files.Count.ShouldBe(2);
files.ShouldContain(x => x.FileName == "en.tpl" && x.FileContent.Contains("Welcome {{model.name}} to the abp.io!"));
files.ShouldContain(x => x.FileName == "tr.tpl" && x.FileContent.Contains("Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!"));
}
}

17
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs

@ -1,4 +1,5 @@
using Shouldly;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
@ -15,28 +16,28 @@ public abstract class TemplateDefinitionTests<TStartupModule> : AbpTextTemplatin
}
[Fact]
public void Should_Retrieve_Template_Definition_By_Name()
public async Task Should_Retrieve_Template_Definition_By_Name()
{
var welcomeEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail);
var welcomeEmailTemplate = await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail);
welcomeEmailTemplate.Name.ShouldBe(TestTemplates.WelcomeEmail);
welcomeEmailTemplate.IsInlineLocalized.ShouldBeFalse();
var forgotPasswordEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail);
var forgotPasswordEmailTemplate = await TemplateDefinitionManager.GetAsync(TestTemplates.ForgotPasswordEmail);
forgotPasswordEmailTemplate.Name.ShouldBe(TestTemplates.ForgotPasswordEmail);
forgotPasswordEmailTemplate.IsInlineLocalized.ShouldBeTrue();
}
[Fact]
public void Should_Get_Null_If_Template_Not_Found()
public async Task Should_Get_Null_If_Template_Not_Found()
{
var definition = TemplateDefinitionManager.GetOrNull("undefined-template");
var definition = await TemplateDefinitionManager.GetOrNullAsync("undefined-template");
definition.ShouldBeNull();
}
[Fact]
public void Should_Retrieve_All_Template_Definitions()
public async Task Should_Retrieve_All_Template_Definitions()
{
var definitions = TemplateDefinitionManager.GetAll();
var definitions = await TemplateDefinitionManager.GetAllAsync();
definitions.Count.ShouldBeGreaterThan(1);
}
}

2
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs

@ -24,7 +24,7 @@ public abstract class LocalizedTemplateContentReaderFactory_Tests<TStartupModule
[Fact]
public async Task Create_Should_Work_With_PhysicalFileProvider()
{
var reader = await LocalizedTemplateContentReaderFactory.CreateAsync(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail));
var reader = await LocalizedTemplateContentReaderFactory.CreateAsync(await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail));
reader.GetContentOrNull("en").ShouldBe(WelcomeEmailEnglishContent);
reader.GetContentOrNull("tr").ShouldBe(WelcomeEmailTurkishContent);

29
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider_Tests.cs

@ -0,0 +1,29 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.TextTemplating.VirtualFiles;
public abstract class TemplateContentFileProvider_Tests<TStartupModule> : AbpTextTemplatingTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
protected readonly TemplateContentFileProvider TemplateContentFileProvider;
protected readonly ITemplateDefinitionManager TemplateDefinitionManager;
protected TemplateContentFileProvider_Tests()
{
TemplateContentFileProvider = GetRequiredService<TemplateContentFileProvider>();
TemplateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>();
}
[Fact]
public async Task GetFilesAsync()
{
var definition = await TemplateDefinitionManager.GetAsync(TestTemplates.HybridTemplateScriban);
var files = await TemplateContentFileProvider.GetFilesAsync(definition);
files.Count.ShouldBe(1);
files.ShouldContain(x => x.FileName == "TestScribanTemplate.tpl" && x.FileContent == "Hello {{model.name}}, {{L \"HowAreYou\" }}");
}
}

6
framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs

@ -24,13 +24,13 @@ public abstract class VirtualFileTemplateContributor_Tests<TStartupModule> : Abp
public async Task Should_Get_Localized_Content_By_Culture()
{
(await VirtualFileTemplateContentContributor.GetOrNullAsync(
new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail),
new TemplateContentContributorContext(await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail),
ServiceProvider,
"en")))
.ShouldBe(WelcomeEmailEnglishContent);
(await VirtualFileTemplateContentContributor.GetOrNullAsync(
new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail),
new TemplateContentContributorContext(await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail),
ServiceProvider,
"tr")))
.ShouldBe(WelcomeEmailTurkishContent);
@ -41,7 +41,7 @@ public abstract class VirtualFileTemplateContributor_Tests<TStartupModule> : Abp
{
(await VirtualFileTemplateContentContributor.GetOrNullAsync(
new TemplateContentContributorContext(
TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail),
await TemplateDefinitionManager.GetAsync(TestTemplates.ForgotPasswordEmail),
ServiceProvider,
null)))
.ShouldBe(ForgotPasswordEmailEnglishContent);

2
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Volo.Abp.BackgroundJobs.DemoApp.HangFire.csproj

@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Hangfire.SqlServer" Version="1.7.29" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.2" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.BackgroundJobs.HangFire\Volo.Abp.BackgroundJobs.HangFire.csproj" />
<ProjectReference Include="..\Volo.Abp.BackgroundJobs.DemoApp.Shared\Volo.Abp.BackgroundJobs.DemoApp.Shared.csproj" />

16
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/AbpAspNetCoreComponentsWebBasicThemeModule.cs

@ -1,12 +1,24 @@
using Volo.Abp.AspNetCore.Components.Web.Theming;
using Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme;
[DependsOn(
typeof(AbpAspNetCoreComponentsWebThemingModule)
)]
)]
public class AbpAspNetCoreComponentsWebBasicThemeModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpThemingOptions>(options =>
{
options.Themes.Add<BasicTheme>();
}
if (options.DefaultThemeName == null)
{
options.DefaultThemeName = BasicTheme.Name;
}
});
}
}

26
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/BasicTheme.cs

@ -0,0 +1,26 @@
using System;
using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic;
using Volo.Abp.AspNetCore.Components.Web.Theming.Layout;
using Volo.Abp.AspNetCore.Components.Web.Theming.Theming;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme;
[ThemeName(Name)]
public class BasicTheme : ITheme, ITransientDependency
{
public const string Name = "Basic";
public virtual Type GetLayout(string name, bool fallbackToDefault = true)
{
switch (name)
{
case StandardLayouts.Application:
case StandardLayouts.Account:
case StandardLayouts.Empty:
return typeof(MainLayout);
default:
return fallbackToDefault ? typeof(MainLayout) : typeof(NullLayout);
}
}
}

3
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NullLayout.razor

@ -0,0 +1,3 @@
@inherits LayoutComponentBase
@Body

8
modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs

@ -252,10 +252,10 @@ public class EfCoreIdentityUserRepository : EfCoreRepository<IIdentityDbContext,
.WhereIf(!string.IsNullOrWhiteSpace(emailAddress), x => x.Email == emailAddress)
.WhereIf(!string.IsNullOrWhiteSpace(name), x => x.Name == name)
.WhereIf(!string.IsNullOrWhiteSpace(surname), x => x.Surname == surname)
.WhereIf(isLockedOut.HasValue, x => x.LockoutEnabled && x.LockoutEnd.Value.CompareTo(DateTime.UtcNow) > 0)
.WhereIf(notActive.HasValue, x => !x.IsActive)
.WhereIf(emailConfirmed.HasValue, x => x.EmailConfirmed)
.WhereIf(isExternal.HasValue, x => x.IsExternal)
.WhereIf(isLockedOut.HasValue, x => (x.LockoutEnabled && x.LockoutEnd.HasValue && x.LockoutEnd.Value.CompareTo(DateTime.UtcNow) > 0) == isLockedOut.Value)
.WhereIf(notActive.HasValue, x => x.IsActive == !notActive.Value)
.WhereIf(emailConfirmed.HasValue, x => x.EmailConfirmed == emailConfirmed.Value)
.WhereIf(isExternal.HasValue, x => x.IsExternal == isExternal.Value)
.WhereIf(maxCreationTime != null, p => p.CreationTime <= maxCreationTime)
.WhereIf(minCreationTime != null, p => p.CreationTime >= minCreationTime)
.WhereIf(maxModifitionTime != null, p => p.LastModificationTime <= maxModifitionTime)

9
modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs

@ -257,10 +257,11 @@ public class MongoIdentityUserRepository : MongoDbRepository<IAbpIdentityMongoDb
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(!string.IsNullOrWhiteSpace(emailAddress), x => x.Email == emailAddress)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(!string.IsNullOrWhiteSpace(name), x => x.Name == name)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(!string.IsNullOrWhiteSpace(surname), x => x.Surname == surname)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(isLockedOut.HasValue, x => x.LockoutEnabled && x.LockoutEnd > DateTimeOffset.UtcNow)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(notActive.HasValue, x => !x.IsActive)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(emailConfirmed.HasValue, x => x.EmailConfirmed)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(isExternal.HasValue, x => x.IsExternal)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(isLockedOut.HasValue && isLockedOut.Value, x => x.LockoutEnabled && x.LockoutEnd != null && x.LockoutEnd > DateTimeOffset.UtcNow)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(isLockedOut.HasValue && !isLockedOut.Value, x => !(x.LockoutEnabled && x.LockoutEnd != null && x.LockoutEnd > DateTimeOffset.UtcNow))
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(notActive.HasValue, x => x.IsActive == !notActive.Value)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(emailConfirmed.HasValue, x => x.EmailConfirmed == emailConfirmed.Value)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(isExternal.HasValue, x => x.IsExternal == isExternal.Value)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(maxCreationTime != null, p => p.CreationTime <= maxCreationTime)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(minCreationTime != null, p => p.CreationTime >= minCreationTime)
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(maxModifitionTime != null, p => p.LastModificationTime <= maxModifitionTime)

2
modules/openiddict/app/OpenIddict.Demo.Client.Console/Program.cs

@ -134,7 +134,7 @@ tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCreden
ClientId = clientId,
ClientSecret = clientSecret,
Scope = "AbpAPI profile roles email phone offline_access",
Scope = "AbpAPI offline_access",
});
if (tokenResponse.IsError)

23
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.ClientCredentials.cs

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
@ -47,27 +45,8 @@ public partial class TokenController
principal.SetScopes(request.GetScopes());
principal.SetResources(await GetResourcesAsync(request.GetScopes()));
foreach (var claim in principal.Claims)
{
claim.SetDestinations(GetDestinations(claim));
}
await OpenIddictClaimsPrincipalManager.HandleAsync(request, principal);
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
protected virtual IEnumerable<string> GetDestinations(Claim claim)
{
// Note: by default, claims are NOT automatically included in the access and identity tokens.
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
// whether they should be included in access tokens, in identity tokens or in both.
return claim.Type switch {
OpenIddictConstants.Claims.PreferredUsername or OpenIddictConstants.Claims.Subject
=> ImmutableArray.Create(OpenIddictConstants.Destinations.AccessToken,
OpenIddictConstants.Destinations.IdentityToken),
_ => ImmutableArray.Create(OpenIddictConstants.Destinations.AccessToken)
};
}
}

1
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateAuthorizedParty.cs

@ -25,7 +25,6 @@ public class AbpValidateAuthorizedParty : AbpOpenIddictWildcardDomainBase<OpenId
public async override ValueTask HandleAsync(OpenIddictServerEvents.ValidateLogoutRequestContext context)
{
Check.NotNull(context, nameof(context));
Check.NotNull(context.IdentityTokenHintPrincipal, nameof(context.IdentityTokenHintPrincipal));
if (await CheckWildcardDomainAsync(context.PostLogoutRedirectUri))
{

2
modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/SettingManagement.razor

@ -23,7 +23,7 @@
<Content>
@foreach (var group in SettingComponentCreationContext.Groups)
{
<TabPanel Name="@GetNormalizedString(group.Id)">
<TabPanel Name="@GetNormalizedString(group.Id)" class="abp-md-form">
<h2>@group.DisplayName</h2>
<Divider />

4
modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.js

@ -19,8 +19,8 @@
processData: false
}).done(function (response) {
$('#tab-content').children('.tab-pane').removeClass('show').removeClass('active');
_this.attr('data-bs-target', '#' + $.escapeSelector($.escapeSelector(id)));
$('#tab-content').append('<div id=' + $.escapeSelector(id) + ' class="tab-pane fade active show">' + response + '</div>');
_this.attr('data-bs-target', '#' + $.escapeSelector(id));
$('#tab-content').append('<div id=' + $.escapeSelector(id) + ' class="tab-pane fade active show abp-md-form">' + response + '</div>');
})
});
}).first().click();

2
npm/ng-packs/apps/dev-app/src/app/app.module.ts

@ -12,7 +12,7 @@ import { SettingManagementConfigModule } from '@abp/ng.setting-management/config
import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config';
import { FeatureManagementModule } from '@abp/ng.feature-management';
import { AccountConfigModule } from '@abp/ng.account/config';
import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account/account-layout';
import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

2
npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html

@ -1,4 +1,4 @@
<form [formGroup]="form" (ngSubmit)="onSubmit()" [mapErrorsFn]="mapErrorsFn" validateOnSubmit>
<form [formGroup]="form" (ngSubmit)="onSubmit()" [mapErrorsFn]="mapErrorsFn" validateOnSubmit class="abp-md-form">
<div *ngIf="!hideCurrentPassword" class="mb-3 form-group">
<label for="current-password" class="form-label">{{
'AbpIdentity::DisplayName:CurrentPassword' | abpLocalization

4
npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html

@ -1,6 +1,6 @@
<div id="AbpContentToolbar"></div>
<div class="card border-0 shadow-sm min-h-400" [abpLoading]="!(profile$ | async)?.userName">
.
<div class="card border-0 shadow-sm min-h-400" [abpLoading]="!(profile$ | async)?.userName" >
<div class="card-body">
<div class="row">
<div class="col-12 col-md-3">

2
npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html

@ -1,4 +1,4 @@
<form [formGroup]="form" *ngIf="form" (ngSubmit)="submit()" validateOnSubmit>
<form [formGroup]="form" *ngIf="form" (ngSubmit)="submit()" validateOnSubmit class="abp-md-form">
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
<abp-button

30
npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts

@ -0,0 +1,30 @@
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
@Directive({
standalone: true,
selector: '[abpCapsLock]',
})
export class TrackCapsLockDirective {
@Output('abpCapsLock') capsLock = new EventEmitter<Boolean>();
@HostListener('window:keydown', ['$event'])
onKeyDown(event: KeyboardEvent): void {
this.capsLock.emit(this.isCapsLockOpen(event));
}
@HostListener('window:keyup', ['$event'])
onKeyUp(event: KeyboardEvent): void {
this.capsLock.emit(this.isCapsLockOpen(event));
}
isCapsLockOpen(e): boolean {
var s = String.fromCharCode(e.which);
if (
(s.toUpperCase() === s && s.toLowerCase() !== s && e.shiftKey) ||
(s.toUpperCase() !== s && s.toLowerCase() === s && e.shiftKey) ||
e.getModifierState('CapsLock')
) {
return true;
}
return false;
}
}

2
npm/ng-packs/packages/core/src/lib/directives/index.ts

@ -6,3 +6,5 @@ export * from './init.directive';
export * from './permission.directive';
export * from './replaceable-template.directive';
export * from './stop-propagation.directive';
export * from './show-password.directive';
export * from './caps-lock.directive';

16
npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts

@ -0,0 +1,16 @@
import { Directive, ElementRef, Input, inject } from '@angular/core';
@Directive({
standalone: true,
selector: '[abpShowPassword]',
})
export class ShowPasswordDirective {
protected readonly elementRef = inject(ElementRef);
@Input() set abpShowPassword(visible: boolean) {
const element = this.elementRef.nativeElement as HTMLInputElement;
if (!element) return;
element.type = visible ? 'text' : 'password';
}
}

2
npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html

@ -2,7 +2,7 @@
<hr class="my-3" />
<form *ngIf="form" [formGroup]="form" (ngSubmit)="submit()" [validateOnSubmit]="true">
<form *ngIf="form" [formGroup]="form" class="abp-md-form" (ngSubmit)="submit()" [validateOnSubmit]="true">
<div class="mb-3 form-group">
<label class="form-label"
>{{ 'AbpSettingManagement::DefaultFromDisplayName' | abpLocalization

4
npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts

@ -147,4 +147,8 @@ background-color: rgba(0, 0, 0, 0.6);
background-color: transparent;
padding: 0.27rem;
}
.abp-md-form {
max-width: 540px;
}
`;

Loading…
Cancel
Save