diff --git a/docs/en/CLI.md b/docs/en/CLI.md index b5db5fbe2a..7a5e59a62a 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -124,7 +124,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample * `--separate-auth-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side. * `--mobile` or `-m`: Specifies the mobile application framework. If not specified, no mobile application will be created. Available options: * `react-native`: React Native. - * `maui`: MAUI. + * `maui`: MAUI. This mobile option is only available for ABP Commercial. * `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers: * `ef`: Entity Framework Core. * `mongodb`: MongoDB. @@ -145,7 +145,8 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample * `mongodb`: MongoDB. * `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes: * `leptonx-lite`: [LeptonX Lite Theme](/Themes/LeptonXLite/mvc.md). - * `basic`: [Basic Theme](/UI/AspNetCore/Basic-Theme.md). + * `basic`: [Basic Theme](/UI/AspNetCore/Basic-Theme.md). + * **`maui`**: .NET MAUI. A minimalist .NET MAUI application will be created if you specify this option. * `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory. * `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version. * `--preview`: Use latest preview version. @@ -245,7 +246,7 @@ It can also create a new module for your solution and add it to your solution. S > A business module generally consists of several packages (because of layering, different database provider options or other reasons). Using `add-module` command dramatically simplifies adding a module to a solution. However, each module may require some additional configurations which is generally indicated in the documentation of the related module. -Usage +Usage: ````bash abp add-module [options] @@ -279,7 +280,7 @@ abp add-module ProductManagement --new --add-to-solution-file Lists names of open-source application modules. -Usage +Usage: ````bash abp list-modules [options] @@ -295,11 +296,21 @@ abp list-modules * `--include-pro-modules`: Includes commercial (pro) modules in the output. +### list-templates + +Lists all available templates to create a solution. + +Usage: + +```bash +abp list-templates +``` + ### get-source Downloads the source code of a module to your computer. -Usage +Usage: ````bash abp get-source [options] diff --git a/docs/en/Deployment/Deploy-Azure-App-Service.md b/docs/en/Deployment/Deploy-Azure-App-Service.md new file mode 100644 index 0000000000..e7536947bf --- /dev/null +++ b/docs/en/Deployment/Deploy-Azure-App-Service.md @@ -0,0 +1,425 @@ +# Deploy Abp Webapp to Azure App Service + +> In this document, you'll learn how to create and deploy your first abp web app to [Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/overview). The App Service supports various versions of .NET apps, and provides a highly scalable, self-patching web hosting service. Abp web apps are cross-platform and can be hosted on Linux and Windows. + +****Prerequisites**** + +- An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/dotnet). +- A GitHub account [Create an account for free](http://github.com/). + + +## Create a new ABP Framework application + +Create a repository on [GitHub.com](https://github.com/) (keep all the default settings) + +Open the command prompt and clone the repository into a folder on your computer + +```bash +git clone https://github.com/your-username/your-repository-name.git +``` +Check your dotnet version. It should be at least 3.1.x +```bash +dotnet --version +``` +Install or update the *ABP CLI* using a command line window + +```bash +dotnet tool install -g Volo.Abp.Cli || dotnet tool update -g Volo.Abp.Cli +``` + +Open the command prompt in the *GitHub repository folder* and create a *new abp Blazor solution* with the command below + +```bash +abp new YourAppName -u blazor +``` + +Open the command prompt in the *[YourAppName].DbMigrator* project and enter the command below to apply the database migrations + +```bash +dotnet run +``` + +Open the command prompt in the *[YourAppName].HttpApi.Host* project to run the API project + +```bash +dotnet run +``` + +Navigate to the *applicationUrl* specified in *the launchSettings.json* file of the *[YourAppName].HttpApi.Host project*. You should get the *Swagger window* + +Open the command prompt in the *[YourAppName].Blazor* folder and enter the command below to run the Blazor project + +```bash +dotnet run +``` + +Navigate to the *applicationUrl* specified in the *launchSettings.json* file of the *[YourAppName].Blazor* project. You should get the *ABP Framework Welcome window* + +Stop both the *API* and the *Blazor* project by pressing **CTRL+C** + +Before the github commit, you have to delete "**/wwwroot/libs/*" at *.gitignore* file. + +![azdevops-23](../images/azdevops-23.png) + +Open the command prompt in the root folder of your project and *add, commit and push* all your changes to your GitHub repository + +```bash +git add . +git commit -m initialcommit +git push +``` + + +## Create a SQL Database on Azure and change the connection string in the appsettings.json files + +* Login into [Azure Portal](https://portal.azure.com/) + +* Click **Create a resource** + +* Search for *SQL Database* + +* Click the **Create** button in the *SQL Database window* + +* Create a new resource group. Name it *rg[YourAppName]* + +* Enter *[YourAppName]Db* as database name + +* Create a new Server and name it *[yourappname]server* + +* Enter a serveradmin login and passwords. Click the **OK** button + +* Select your *Location* + +* Check *Allow Azure services to access server* + +* Click **Configure database**. Go to the *Basic* version and click the **Apply** button + +* Click the **Review + create** button. Click **Create** + +* Click **Go to resource** and click **SQL server** when the SQL Database is created + +* Click **Networking** under Security left side menu + +* Select **Selected networks** and click **Add your client IP$ address** at the Firewall rules + +* Select **Allow Azure and resources to access this seerver** and save + +* Go to your **SQL database**, click **Connection strings** and copy the connection string + +* Copy/paste the appsettings.json files of the [YourAppName].HttpApi.Host and the [YourAppName].DbMigrator project + +* Do not forget to replace {your_password} with the correct server password you entered in Azure SQL Database + +Open the command prompt in the [YourAppName].DbMigrator project again and enter the command below to apply the database migrations + +```bash +dotnet run +``` +Open the command prompt in the [YourAppName].HttpApi.Host project and enter the command below to check your API is working + +```bash +dotnet run +``` + +Stop the [YourAppName].HttpApi.Host by entering CTRL+C + +Open the command prompt in the root folder of your project and add, commit and push all your changes to your GitHub repository +```bash +git add . +git commit -m initialcommit +git push +``` + + +## Set up the Build pipeline in AzureDevops and publish the Build Artifacts + +* Sign in into Azure DevOps + +* Click **New organization** and follow the steps to create a new organisation. Name it [YourAppName]org + +* Enter [YourAppName]Proj as project name in the ***Create a project to get started*** window + +* Select **Public visibility** and click the **Create project** button + +* Click the **Pipelines** button to continue + +* Click the **Create Pipeline** button + + Select GitHub in the Select your repository window + +![azdevops-1](../images/azdevops-1.png) + +* Enter the Connection name. [YourAppName]GitHubConnection and click **Authorize using OAuth** + +* Select your **GitHub** [YourAppName]repo and click Continue + +* Search for **ASP.NET** in the ***Select a template*** window + +![azdevops-2](../images/azdevops-2.png) + +* Select the ASP.NET Core template and click the **Apply** button + +* Add the below commands block as a first step in the pipeline + + ``` + - task: UseDotNet@2 + inputs: + packageType: 'sdk' + version: '6.0.106' + ``` + +![azdevops-18](../images/azdevops-18.png) + +* Select **Settings** on the second task(Nugetcommand@2) in the pipeline + +* Select **Feeds in my Nuget.config** and type **Nuget.config** in the text box + +![azdevops-3](../images/azdevops-3.png) + +* Add the below commands block to the end of the pipeline + + ``` + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact' + inputs: + PathtoPublish: '$(build.artifactstagingdirectory)' + ArtifactName: '$(Parameters.ArtifactName)' + condition: succeededOrFailed() + ``` +![azdevops-4](../images/azdevops-4.png) + +``` +# ASP.NET +# Build and test ASP.NET projects. +# Add steps that publish symbols, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4 + +trigger: +- main + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + +steps: +- task: UseDotNet@2 + inputs: + packageType: 'sdk' + version: '6.0.106' + +- task: NuGetToolInstaller@1 + +- task: NuGetCommand@2 + inputs: + command: 'restore' + restoreSolution: '$(solution)' + feedsToUse: 'config' + nugetConfigPath: 'NuGet.config' + +- task: VSBuild@1 + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + inputs: + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact' + inputs: + PathtoPublish: '$(build.artifactstagingdirectory)' + ArtifactName: '$(Parameters.ArtifactName)' + publishLocation: 'Container' + condition: succeededOrFailed() +``` + +* Click **Save & queue** in the top menu. Click **Save & queue** again and click **Save and run** to run the Build pipeline + +* When the Build pipeline has finished. Click **1 published; 1 consumed** + + + +## Create a Web App in the Azure Portal to deploy [YourAppName].HttpApi.Host project + +* Search for Web App in the *Search the Marketplace* field + +* Click the **Create** button in the Web App window + +* Select rg[YourAppName] in the *Resource Group* dropdown + +* Enter [YourAppName]API in the *Name input* field + +* Select code, .NET Core 3.1 (LTS) and windows as *Operating System* + +* Enter [YourAppName]API in the *Name input* field + +* Select .NET Core 3.1 (LTS) in the *Runtime stack* dropdown + +* Select Windows as *Operating System* + +* Select the same *Region* as in the SQL server you created in Part 3 + +![azdevops-5](../images/azdevops-5.png) + +* Click **Create new** in the Windows Plan. Name it [YourAppName]ApiWinPlan + +* Click **Change size** in Sku and size. Go to the Dev/Test Free F1 version and click the **Apply** button + +![azdevops-6](../images/azdevops-6.png) + +* Click the **Review + create** button. Click the **Create** button + +* Click **Go to resource** when the Web App has been created + + + +## Create a Release pipeline in the AzureDevops and deploy [YourAppName].HttpApi.Host project + +* Sign in into [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) + +* Click [YourAppName]Proj and click **Releases** in the *Pipelines* menu + +* Click the **New pipeline** button in the *No release pipelines found* window + +* Select *Azure App Service deployment* and click the **Apply** button + +![azdevops-7](../images/azdevops-7.png) + +* Enter *[YourAppName]staging* in the *Stage name* field in the *Stage* window. And close the window + +* Click **+ Add an artifact** in the *Pipeline* tab + +* Select the **Build** icon as *Source type* in the *Add an artifact* window + +* Select Build pipeline in the *Source (build pipeline)* dropdown and click the **Add** button + +![azdevops-8](../images/azdevops-8.png) + +* Click the **Continuous deployment trigger (thunderbolt icon)** + +* Set the toggle to **Enabled** in the the *Continuous deployment trigger* window + +* Click **+ Add** in *No filters added*. Select **Include** in the *Type* dropdown. Select your branch in the *Build branch* dropdown and close the window + +![azdevops-9](../images/azdevops-9.png) + +* Click **the little red circle with the exclamation mark** in the *Tasks* tab menu + +* Select your subscription in the *Azure subscription* dropdown. + +![azdevops-10](../images/azdevops-10.png) + +* Click **Authorize** and enter your credentials in the next screens + +* After Authorization, select the **[YourAppName]API** in the *App service name* dropdown + +* Click the **Deploy Azure App Service** task + +* Select **[YourAppName].HttpApi.Host.zip** in the *Package or folder* input field + +![azdevops-11](../images/azdevops-11.png) + +* Click the **Save** icon in the top menu and click **OK** + +* Click **Create release** in the top menu. Click **Create** to create a release + +* Click the *Pipeline* tab and wait until the Deployment succeeds + +![azdevops-12](../images/azdevops-12.png) + +* Open a browser and navigate to the URL of your Web App + +``` +https://[YourAppName]api.azurewebsites.net +``` + +![azdevops-13](../images/azdevops-13.png) + + + +## Create a Web App in Azure Portal to deploy [YourAppName].Blazor project + +* Login into [Azure Portal](https://portal.azure.com/) + +* Click **Create a resource** + +* Search for *Web App* in the *Search the Marketplace* field + +* Click the **Create** button in the *Web App* window + +* Select *rg[YourAppName]* in the *Resource Group* dropdown + +* Enter *[YourAppName]Blazor* in the *Name* input field + +* Select *.NET Core 3.1 (LTS)* in the *Runtime stack* dropdown + +* Select *Windows* as *Operating System* + +* Select the same region as the SQL server you created in Part 3 + +* Select the [YourAppName]ApiWinPlan in the *Windows Plan* dropdown + +![azdevops-14](../images/azdevops-14.png) + +* Click the **Review + create** button. Click **Create** button + +* Click **Go to resource** when the Web App has been created + +* Copy the URL of the Blazor Web App for later use + +``` +https://[YourAppName]blazor.azurewebsites.net +``` + + +## Change the Web App configuration for the Azure App Service + +Copy the URL of the Api Host and Blazor Web App. Change appsettings.json files in the Web App as follows images. + +![azdevops-19](../images/azdevops-19.png) + +![azdevops-20](../images/azdevops-20.png) + +![azdevops-21](../images/azdevops-21.png) + + + +## Add an extra Stage in the Release pipeline in the AzureDevops to deploy [YourAppName].Blazor project + +* Go to the *Release* pipeline in [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) and click **Edit** + +* Click the **+ Add** link and add a **New Stage** + +![azdevops-15](../images/azdevops-15.png) + +* Select *Azure App Service deployment* and click the **Apply** button + +* Enter *BlazorDeployment* in the *Stage name* input field and close the *Stage* window + +* Click the **little red circle with the exclamation mark** in the BlazorDeployment stage + +* Select your subscription in the *Azure subscription* dropdown + +* Select your Blazor Web App in the *App service name* dropdown + +* Click the **Deploy Azure App Service task** + +* Select *[YourAppName].Blazor.zip* in the *Package or folder* input field + +![azdevops-16](../images/azdevops-16.png) + +* Click **Save** in the top menu and click the **OK** button after + +* Click **Create release** in the top menu and click the **Create** button + +![azdevops-17](../images/azdevops-17.png) + +![azdevops-22](../images/azdevops-22.png) \ No newline at end of file diff --git a/docs/en/Deployment/Index.md b/docs/en/Deployment/Index.md index dc1cca300e..a1c2e2d5f8 100644 --- a/docs/en/Deployment/Index.md +++ b/docs/en/Deployment/Index.md @@ -6,4 +6,7 @@ However, there are some topics that you should care about when you are deploying ## Guides -* [Deploying to a clustered environment](Clustered-Environment.md): Explains how to configure your application when you want to run multiple instances of your application concurrently. \ No newline at end of file +* [Deploying to a clustered environment](Clustered-Environment.md): Explains how to configure your application when you want to run multiple instances of your application concurrently. + + +* [Deploy Abp Webapp to Azure App Service](Deploy-Azure-App-Service.md): Explains how to create and deploy your first abp web app to [Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/overview). \ No newline at end of file diff --git a/docs/en/Modules/OpenIddict.md b/docs/en/Modules/OpenIddict.md index 85ece92ffc..6dc1224e59 100644 --- a/docs/en/Modules/OpenIddict.md +++ b/docs/en/Modules/OpenIddict.md @@ -216,7 +216,7 @@ https://documentation.openiddict.com/guides/index.html#events-model ## Migrating Guide -[Migrating from IdentityServer to OpenIddict Step by Step Guide ](Migration-Guides/OpenIddict-Step-by-Step.md) +[Migrating from IdentityServer to OpenIddict Step by Step Guide ](../Migration-Guides/OpenIddict-Step-by-Step.md) ## Sponsor diff --git a/docs/en/UI/Angular/Theming.md b/docs/en/UI/Angular/Theming.md index c7f303763d..435acc6930 100644 --- a/docs/en/UI/Angular/Theming.md +++ b/docs/en/UI/Angular/Theming.md @@ -16,10 +16,11 @@ In order to accomplish these goals, ABP Framework; ### Current Themes -Currently, two themes are **officially provided**: +Currently, three themes are **officially provided**: * The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. * The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. +* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has both [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/angular) and [lite](../../Themes/LeptonXLite/Angular.md) choices. ## Overall diff --git a/docs/en/UI/AspNetCore/Overall.md b/docs/en/UI/AspNetCore/Overall.md index 8cd9dd3f5e..bc24c56fb8 100644 --- a/docs/en/UI/AspNetCore/Overall.md +++ b/docs/en/UI/AspNetCore/Overall.md @@ -32,10 +32,11 @@ ABP Framework provides a complete [Theming](Theming.md) system with the followin ### Current Themes -Currently, two themes are **officially provided**: +Currently, three themes are **officially provided**: * The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. * The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. +* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has both [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/mvc) and [lite](../../Themes/LeptonXLite/AspNetCore.md) choices. There are also some community-driven themes for the ABP Framework (you can search on the web). diff --git a/docs/en/UI/AspNetCore/Page-Header.md b/docs/en/UI/AspNetCore/Page-Header.md index f6ec3074de..8b045c89ab 100644 --- a/docs/en/UI/AspNetCore/Page-Header.md +++ b/docs/en/UI/AspNetCore/Page-Header.md @@ -23,6 +23,8 @@ Page Title can be set as shown in the example below: ### Breadcrumb > **The [Basic Theme](Basic-Theme.md) currently doesn't implement the breadcrumbs.** +> +> The [LeptonX Lite Theme](../../Themes/LeptonXLite/AspNetCore.md) supports breadcrumbs. Breadcrumb items can be added to the `PageLayout.Content.BreadCrumb`. @@ -48,11 +50,13 @@ Any item that you add is inserted between Home and Current Page items. You can a ### The Selected Menu Item > **The [Basic Theme](Basic-Theme.md) currently doesn't implement the selected menu item since it is not applicable to the top menu which is the only option for the Basic Theme for now.** +> +> The [LeptonX Lite Theme](../../Themes/LeptonXLite/AspNetCore.md) supports selected menu item. You can set the Menu Item name related to this page: -````csharp +```csharp PageLayout.Content.MenuItemName = "BookStore.Books"; -```` +``` Menu item name should match a unique menu item name defined using the [Navigation / Menu](Navigation-Menu.md) system. In this case, it is expected from the theme to make the menu item "active" in the main menu. \ No newline at end of file diff --git a/docs/en/UI/AspNetCore/Toolbars.md b/docs/en/UI/AspNetCore/Toolbars.md index d82150b47e..975157151f 100644 --- a/docs/en/UI/AspNetCore/Toolbars.md +++ b/docs/en/UI/AspNetCore/Toolbars.md @@ -8,6 +8,12 @@ There is only one **standard toolbar** named "Main" (defined as a constant: `Sta In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here. +Also, [LeptonX Lite Theme](../../Themes/LeptonXLite/AspNetCore.md) has 2 different toolbars for desktop and mobile views which defined as constants: `LeptonXLiteToolbars.Main`, `LeptonXLiteToolbars.MainMobile`. + +| LeptonXLiteToolbars.Main | LeptonXLiteToolbars.MainMobile | +| :---: | :---: | +| ![leptonx](../../images/leptonxlite-toolbar-main-example.png) | ![leptonx](../../images/leptonxlite-toolbar-mainmobile-example.png) | + ## Example: Add a Notification Icon In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **view component**. So, first, create a new view component in your project: diff --git a/docs/en/UI/Blazor/Overall.md b/docs/en/UI/Blazor/Overall.md index ff361d6784..402d61acb0 100644 --- a/docs/en/UI/Blazor/Overall.md +++ b/docs/en/UI/Blazor/Overall.md @@ -75,10 +75,11 @@ ABP Framework provides a complete [Theming](Theming.md) system with the followin ### Current Themes -Currently, two themes are **officially provided**: +Currently, three themes are **officially provided**: * The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. * The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. +* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has both [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/blazor) and [lite](../../Themes/LeptonXLite/Blazor.md) choices. ### Base Libraries diff --git a/docs/en/UI/Blazor/Page-Header.md b/docs/en/UI/Blazor/Page-Header.md index 29cb006bd3..1bdc9c93c0 100644 --- a/docs/en/UI/Blazor/Page-Header.md +++ b/docs/en/UI/Blazor/Page-Header.md @@ -16,6 +16,8 @@ Once you add the `PageHeader` component to your page, you can control the relate ## Breadcrumb > **The [Basic Theme](Basic-Theme.md) currently doesn't implement the breadcrumbs.** +> +> The [LeptonX Lite Theme](../../Themes/LeptonXLite/Blazor.md) supports breadcrumbs. Breadcrumbs can be added using the `BreadcrumbItems` property. diff --git a/docs/en/UI/Blazor/Page-Layout.md b/docs/en/UI/Blazor/Page-Layout.md index 49ed1659f4..c6f3d62000 100644 --- a/docs/en/UI/Blazor/Page-Layout.md +++ b/docs/en/UI/Blazor/Page-Layout.md @@ -42,6 +42,10 @@ Menu item name can be set on runtime too. } ``` + +![leptonx selected menu item](../../images/leptonx-selected-menu-item-example.gif) + + > Be aware, The [Basic Theme](../Blazor/Basic-Theme.md) currently doesn't support the selected menu item since it is not applicable to the top menu. ## BreadCrumbs diff --git a/docs/en/UI/Blazor/Toolbars.md b/docs/en/UI/Blazor/Toolbars.md index 3ff1b7f135..c0878f080a 100644 --- a/docs/en/UI/Blazor/Toolbars.md +++ b/docs/en/UI/Blazor/Toolbars.md @@ -8,6 +8,12 @@ There is only one **standard toolbar** named "Main" (defined as a constant: `Sta In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here. +Also, [LeptonX Lite Theme](../../Themes/LeptonXLite/Blazor.md) has 2 different toolbars for desktop and mobile views which defined as constants: `LeptonXLiteToolbars.Main`, `LeptonXLiteToolbars.MainMobile`. + +| LeptonXLiteToolbars.Main | LeptonXLiteToolbars.MainMobile | +| :---: | :---: | +| ![leptonx](../../images/leptonxlite-toolbar-main-example.png) | ![leptonx](../../images/leptonxlite-toolbar-mainmobile-example.png) | + ## Example: Add a Notification Icon In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **Razor Component**. So, first, create a new razor component in your project (the location of the component doesn't matter): diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index db63a7136b..4b82495a00 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -43,6 +43,10 @@ "text": "WPF Application", "path": "Startup-Templates/WPF.md" }, + { + "text": "MAUI", + "path": "Startup-Templates/MAUI.md" + }, { "text": "Empty Web Project", "path": "Getting-Started-AspNetCore-Application.md" @@ -1278,6 +1282,10 @@ { "text": "Deploying to a Clustered Environment", "path": "Deployment/Clustered-Environment.md" + }, + { + "text": "Deploy Abp Webapp to Azure App Service", + "path": "Deployment/Deploy-Azure-App-Service.md" } ] }, diff --git a/docs/en/images/azdevops-1.png b/docs/en/images/azdevops-1.png new file mode 100644 index 0000000000..78181e4b7c Binary files /dev/null and b/docs/en/images/azdevops-1.png differ diff --git a/docs/en/images/azdevops-10.png b/docs/en/images/azdevops-10.png new file mode 100644 index 0000000000..75a273ba52 Binary files /dev/null and b/docs/en/images/azdevops-10.png differ diff --git a/docs/en/images/azdevops-11.png b/docs/en/images/azdevops-11.png new file mode 100644 index 0000000000..422a0ddbc0 Binary files /dev/null and b/docs/en/images/azdevops-11.png differ diff --git a/docs/en/images/azdevops-12.png b/docs/en/images/azdevops-12.png new file mode 100644 index 0000000000..e1bc1399f9 Binary files /dev/null and b/docs/en/images/azdevops-12.png differ diff --git a/docs/en/images/azdevops-13.png b/docs/en/images/azdevops-13.png new file mode 100644 index 0000000000..e83f972b20 Binary files /dev/null and b/docs/en/images/azdevops-13.png differ diff --git a/docs/en/images/azdevops-14.png b/docs/en/images/azdevops-14.png new file mode 100644 index 0000000000..a4bd3b65d0 Binary files /dev/null and b/docs/en/images/azdevops-14.png differ diff --git a/docs/en/images/azdevops-15.png b/docs/en/images/azdevops-15.png new file mode 100644 index 0000000000..ed4b9dc6a0 Binary files /dev/null and b/docs/en/images/azdevops-15.png differ diff --git a/docs/en/images/azdevops-16.png b/docs/en/images/azdevops-16.png new file mode 100644 index 0000000000..402f6b7d5e Binary files /dev/null and b/docs/en/images/azdevops-16.png differ diff --git a/docs/en/images/azdevops-17.png b/docs/en/images/azdevops-17.png new file mode 100644 index 0000000000..5441a87035 Binary files /dev/null and b/docs/en/images/azdevops-17.png differ diff --git a/docs/en/images/azdevops-18.png b/docs/en/images/azdevops-18.png new file mode 100644 index 0000000000..8e358172d5 Binary files /dev/null and b/docs/en/images/azdevops-18.png differ diff --git a/docs/en/images/azdevops-19.png b/docs/en/images/azdevops-19.png new file mode 100644 index 0000000000..ff282de4d5 Binary files /dev/null and b/docs/en/images/azdevops-19.png differ diff --git a/docs/en/images/azdevops-2.png b/docs/en/images/azdevops-2.png new file mode 100644 index 0000000000..9982431409 Binary files /dev/null and b/docs/en/images/azdevops-2.png differ diff --git a/docs/en/images/azdevops-20.png b/docs/en/images/azdevops-20.png new file mode 100644 index 0000000000..f8a00be927 Binary files /dev/null and b/docs/en/images/azdevops-20.png differ diff --git a/docs/en/images/azdevops-21.png b/docs/en/images/azdevops-21.png new file mode 100644 index 0000000000..7d55d11150 Binary files /dev/null and b/docs/en/images/azdevops-21.png differ diff --git a/docs/en/images/azdevops-22.png b/docs/en/images/azdevops-22.png new file mode 100644 index 0000000000..f103c8f56f Binary files /dev/null and b/docs/en/images/azdevops-22.png differ diff --git a/docs/en/images/azdevops-23.png b/docs/en/images/azdevops-23.png new file mode 100644 index 0000000000..7318b82d13 Binary files /dev/null and b/docs/en/images/azdevops-23.png differ diff --git a/docs/en/images/azdevops-3.png b/docs/en/images/azdevops-3.png new file mode 100644 index 0000000000..0ede96f42a Binary files /dev/null and b/docs/en/images/azdevops-3.png differ diff --git a/docs/en/images/azdevops-4.png b/docs/en/images/azdevops-4.png new file mode 100644 index 0000000000..52e025913c Binary files /dev/null and b/docs/en/images/azdevops-4.png differ diff --git a/docs/en/images/azdevops-5.png b/docs/en/images/azdevops-5.png new file mode 100644 index 0000000000..31384e5de5 Binary files /dev/null and b/docs/en/images/azdevops-5.png differ diff --git a/docs/en/images/azdevops-6.png b/docs/en/images/azdevops-6.png new file mode 100644 index 0000000000..cc493dfd43 Binary files /dev/null and b/docs/en/images/azdevops-6.png differ diff --git a/docs/en/images/azdevops-7.png b/docs/en/images/azdevops-7.png new file mode 100644 index 0000000000..e5f0cda151 Binary files /dev/null and b/docs/en/images/azdevops-7.png differ diff --git a/docs/en/images/azdevops-8.png b/docs/en/images/azdevops-8.png new file mode 100644 index 0000000000..5c2f996cf8 Binary files /dev/null and b/docs/en/images/azdevops-8.png differ diff --git a/docs/en/images/azdevops-9.png b/docs/en/images/azdevops-9.png new file mode 100644 index 0000000000..0c8a7b557e Binary files /dev/null and b/docs/en/images/azdevops-9.png differ diff --git a/docs/en/images/breadcrumbs-example.png b/docs/en/images/breadcrumbs-example.png index 17ae5f8ba5..8b4bbc62d7 100644 Binary files a/docs/en/images/breadcrumbs-example.png and b/docs/en/images/breadcrumbs-example.png differ diff --git a/docs/en/images/leptonx-selected-menu-item-example.gif b/docs/en/images/leptonx-selected-menu-item-example.gif new file mode 100644 index 0000000000..8f1170cd55 Binary files /dev/null and b/docs/en/images/leptonx-selected-menu-item-example.gif differ diff --git a/docs/en/images/leptonxlite-toolbar-main-example.png b/docs/en/images/leptonxlite-toolbar-main-example.png new file mode 100644 index 0000000000..30edcf547b Binary files /dev/null and b/docs/en/images/leptonxlite-toolbar-main-example.png differ diff --git a/docs/en/images/leptonxlite-toolbar-mainmobile-example.png b/docs/en/images/leptonxlite-toolbar-mainmobile-example.png new file mode 100644 index 0000000000..95815b5843 Binary files /dev/null and b/docs/en/images/leptonxlite-toolbar-mainmobile-example.png differ diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md index f890534795..f108bbcfec 100644 --- a/docs/zh-Hans/CLI.md +++ b/docs/zh-Hans/CLI.md @@ -123,6 +123,7 @@ abp new Acme.BookStore * `module`: [Module template](Startup-Templates/Module.md). 其他选项: * `--no-ui`: 不包含UI.仅创建服务模块(也称为微服务 - 没有UI). * **`console`**: [Console template](Startup-Templates/Console.md). + * **`maui`**: [Maui template](Startup-Templates/MAUI.md). * **`app-nolayers`**: 应用程序单层模板 * `--ui` 或者 `-u`: 指定ui框架.默认`mvc`框架.其他选项: * `mvc`: ASP.NET Core MVC. diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 203000c6c6..be30753fb3 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -61,6 +61,10 @@ { "text": "WPF", "path": "Startup-Templates/WPF.md" + }, + { + "text": "MAUI", + "path": "Startup-Templates/MAUI.md" } ] }, diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs index dd9e6cfe62..c0c56053d3 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs @@ -1,11 +1,14 @@ using System; +using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.WebClientInfo; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; +using Volo.Abp.ExceptionHandling; namespace Volo.Abp.AspNetCore.Auditing; @@ -57,28 +60,46 @@ public class AspNetCoreAuditLogContributor : AuditLogContributor, ITransientDepe public override void PostContribute(AuditLogContributionContext context) { + if (context.AuditInfo.HttpStatusCode != null) + { + return; + } + var httpContext = context.ServiceProvider.GetRequiredService().HttpContext; if (httpContext == null) { return; } - if (context.AuditInfo.HttpStatusCode == null) + if (context.AuditInfo.Exceptions.Any()) { - context.AuditInfo.HttpStatusCode = httpContext.Response.StatusCode; + var httpExceptionStatusCodeFinder = context.ServiceProvider.GetRequiredService(); + foreach (var auditInfoException in context.AuditInfo.Exceptions) + { + var statusCode = httpExceptionStatusCodeFinder.GetStatusCode(httpContext, auditInfoException); + context.AuditInfo.HttpStatusCode = (int) statusCode; + } + + if (context.AuditInfo.HttpStatusCode != null) + { + return; + } } + + context.AuditInfo.HttpStatusCode = httpContext.Response.StatusCode; } protected virtual string BuildUrl(HttpContext httpContext) { //TODO: Add options to include/exclude query, schema and host - var uriBuilder = new UriBuilder(); - - uriBuilder.Scheme = httpContext.Request.Scheme; - uriBuilder.Host = httpContext.Request.Host.Host; - uriBuilder.Path = httpContext.Request.Path.ToString(); - uriBuilder.Query = httpContext.Request.QueryString.ToString(); + var uriBuilder = new UriBuilder + { + Scheme = httpContext.Request.Scheme, + Host = httpContext.Request.Host.Host, + Path = httpContext.Request.Path.ToString(), + Query = httpContext.Request.QueryString.ToString() + }; return uriBuilder.Uri.AbsolutePath; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index eca456a16e..cc64d73ff2 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -123,7 +123,7 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien sb.AppendLine("--tiered (if supported by the template)"); sb.AppendLine("--no-ui (if supported by the template)"); sb.AppendLine("--no-random-port (Use template's default ports)"); - sb.AppendLine("--separate-identity-server (if supported by the template)"); + sb.AppendLine("--separate-auth-server (if supported by the template)"); sb.AppendLine("--local-framework-ref --abp-path (keeps local references to projects instead of replacing with NuGet package references)"); sb.AppendLine(""); sb.AppendLine("Examples:"); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs index 916f861460..33ecad0719 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs @@ -285,14 +285,12 @@ public class ChangeThemeStep : ProjectBuildPipelineStep {"Domain.Shared", "MyCompanyName.MyProjectName.Domain.Shared.csproj"}, {"Application", "MyCompanyName.MyProjectName.Application.csproj"}, {"Application.Contracts", "MyCompanyName.MyProjectName.Application.Contracts.csproj"}, - {"Blazor.WebAssembly", "MyCompanyName.MyProjectName.Blazor.csproj"}, - {"Blazor.Server", "MyCompanyName.MyProjectName.Blazor.Server.csproj"}, {"HttpApi", "MyCompanyName.MyProjectName.HttpApi.csproj"}, - {"HttpApi.Client", "MyCompanyName.MyProjectName.HttpApi.Client.csproj"}, - {"Web.Host", "MyCompanyName.MyProjectName.Web.Host.csproj"}, - {"Web", "MyCompanyName.MyProjectName.Web.csproj"}, + {"HttpApi.Client", "MyCompanyName.MyProjectName.HttpApi.Client.csproj"} }; - + + AddUiProjectToProjects(projects, context); + foreach (var project in projects) { AddLeptonThemeManagementReference(context, project); @@ -314,6 +312,28 @@ public class ChangeThemeStep : ProjectBuildPipelineStep AddLeptonThemeManagementReference(context, microserviceServiceProject); } } + + private void AddUiProjectToProjects(Dictionary projects, ProjectBuildContext context) + { + if (projects.IsNullOrEmpty()) + { + return; + } + + switch (context.BuildArgs.UiFramework) + { + case UiFramework.Mvc: + projects["Web.Host"] = "MyCompanyName.MyProjectName.Web.Host.csproj"; + projects["Web"] = "MyCompanyName.MyProjectName.Web.csproj"; + break; + case UiFramework.Blazor: + projects["Blazor.WebAssembly"] = "MyCompanyName.MyProjectName.Blazor.csproj"; + break; + case UiFramework.BlazorServer: + projects["Blazor.Server"] = "MyCompanyName.MyProjectName.Blazor.csproj"; + break; + } + } private void AddLeptonThemeManagementReference(ProjectBuildContext context, KeyValuePair projectInfo) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs index 44f6d3e0bd..ce61d9775f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs @@ -14,6 +14,8 @@ public class TemplateCodeDeleteStep : ProjectBuildPipelineStep file.Name.EndsWith(".json") || file.Name.EndsWith(".gitignore") || file.Name.EndsWith(".yml") || + file.Name.EndsWith(".yaml") || + file.Name.EndsWith(".md") || file.Name.EndsWith(".ps1") || file.Name.EndsWith(".html") || file.Name.EndsWith(".ts") || diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs index 71f090a576..c6a15389ef 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs @@ -130,6 +130,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo steps.Add(new RemoveFolderStep("/apps/blazor")); steps.Add(new RemoveProjectFromTyeStep("blazor")); steps.Add(new RemoveProjectFromTyeStep("blazor-server")); + + context.Symbols.Add("ui:angular"); break; case UiFramework.Blazor: @@ -147,7 +149,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo null, "/apps/blazor/src/MyCompanyName.MyProjectName.Blazor.Server")); steps.Add(new RemoveProjectFromTyeStep("blazor-server")); - + + context.Symbols.Add("ui:blazor"); break; case UiFramework.BlazorServer: @@ -169,7 +172,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.Blazor.Server", "MyCompanyName.MyProjectName.Blazor")); steps.Add(new RenameProjectInTyeStep("blazor-server", "blazor")); - + + context.Symbols.Add("ui:blazor-server"); break; case UiFramework.Mvc: @@ -186,6 +190,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo steps.Add(new RemoveProjectFromTyeStep("blazor-server")); steps.Add(new RemoveFolderStep("/apps/angular")); + + context.Symbols.Add("ui:mvc"); break; } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs index 363c3b3885..3aff8a78ad 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs @@ -1,19 +1,13 @@ using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; namespace Volo.Abp.DependencyInjection; -public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDependency +[ExposeServices(typeof(IAbpLazyServiceProvider))] +public class AbpLazyServiceProvider : CachedServiceProviderBase, IAbpLazyServiceProvider, ITransientDependency { - protected IDictionary CachedServices { get; set; } - - protected IServiceProvider ServiceProvider { get; set; } - public AbpLazyServiceProvider(IServiceProvider serviceProvider) + : base(serviceProvider) { - ServiceProvider = serviceProvider; - CachedServices = new Dictionary(); } public virtual T LazyGetRequiredService() @@ -23,7 +17,7 @@ public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDepende public virtual object LazyGetRequiredService(Type serviceType) { - return CachedServices.GetOrAdd(serviceType, () => ServiceProvider.GetRequiredService(serviceType)); + return GetService(serviceType); } public virtual T LazyGetService() @@ -33,7 +27,7 @@ public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDepende public virtual object LazyGetService(Type serviceType) { - return CachedServices.GetOrAdd(serviceType, () => ServiceProvider.GetService(serviceType)); + return GetService(serviceType); } public virtual T LazyGetService(T defaultValue) @@ -53,6 +47,9 @@ public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDepende public virtual object LazyGetService(Type serviceType, Func factory) { - return CachedServices.GetOrAdd(serviceType, () => factory(ServiceProvider)); + return CachedServices.GetOrAdd( + serviceType, + _ => new Lazy(() => factory(ServiceProvider)) + ).Value; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs index d543493ce9..c261d3a3bb 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs @@ -5,21 +5,21 @@ namespace Volo.Abp.DependencyInjection; public abstract class CachedServiceProviderBase { - private readonly IServiceProvider _serviceProvider; - private readonly ConcurrentDictionary> _cachedServices; + protected IServiceProvider ServiceProvider { get; } + protected ConcurrentDictionary> CachedServices { get; } protected CachedServiceProviderBase(IServiceProvider serviceProvider) { - _serviceProvider = serviceProvider; - _cachedServices = new ConcurrentDictionary>(); - _cachedServices.TryAdd(typeof(IServiceProvider), new Lazy(() => _serviceProvider)); + ServiceProvider = serviceProvider; + CachedServices = new ConcurrentDictionary>(); + CachedServices.TryAdd(typeof(IServiceProvider), new Lazy(() => ServiceProvider)); } public virtual object GetService(Type serviceType) { - return _cachedServices.GetOrAdd( + return CachedServices.GetOrAdd( serviceType, - _ => new Lazy(() => _serviceProvider.GetService(serviceType)) + _ => new Lazy(() => ServiceProvider.GetService(serviceType)) ).Value; } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AbpLazyServiceProvider_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AbpLazyServiceProvider_Tests.cs new file mode 100644 index 0000000000..c78dc9c989 --- /dev/null +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AbpLazyServiceProvider_Tests.cs @@ -0,0 +1,50 @@ +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Modularity; +using Volo.Abp.Testing.Utils; +using Xunit; + +namespace Volo.Abp.DependencyInjection; + +public class AbpLazyServiceProvider_Tests +{ + [Fact] + public void LazyServiceProvider_Should_Cache_Services() + { + using (var application = AbpApplicationFactory.Create()) + { + application.Initialize(); + + var lazyServiceProvider = application.ServiceProvider.GetRequiredService(); + + var transientTestService1 = lazyServiceProvider.LazyGetRequiredService(); + var transientTestService2 = lazyServiceProvider.LazyGetRequiredService(); + transientTestService1.ShouldBeSameAs(transientTestService2); + + var testCounter = application.ServiceProvider.GetRequiredService(); + testCounter.GetValue(nameof(TransientTestService)).ShouldBe(1); + } + } + + [DependsOn(typeof(AbpTestBaseModule))] + private class TestModule : AbpModule + { + public TestModule() + { + SkipAutoServiceRegistration = true; + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddType(); + } + } + + private class TransientTestService : ITransientDependency + { + public TransientTestService(ITestCounter counter) + { + counter.Increment(nameof(TransientTestService)); + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs index 4cfe025e1c..1400fd5f25 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs @@ -3,6 +3,9 @@ using Volo.Abp.Identity; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.ObjectExtending.Modularity; +using Volo.Abp.Threading; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; @@ -13,6 +16,8 @@ namespace Volo.Abp.Account; )] public class AbpAccountApplicationContractsModule : AbpModule { + private readonly static OneTimeRunner OneTimeRunner = new OneTimeRunner(); + public override void ConfigureServices(ServiceConfigurationContext context) { Configure(options => @@ -33,4 +38,17 @@ public class AbpAccountApplicationContractsModule : AbpModule options.MapCodeNamespace("Volo.Account", typeof(AccountResource)); }); } + + public override void PostConfigureServices(ServiceConfigurationContext context) + { + OneTimeRunner.Run(() => + { + ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToApi( + IdentityModuleExtensionConsts.ModuleName, + IdentityModuleExtensionConsts.EntityNames.User, + getApiTypes: new[] { typeof(ProfileDto) }, + updateApiTypes: new[] { typeof(UpdateProfileDto) } + ); + }); + } } diff --git a/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorAutoMapperProfile.cs b/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorAutoMapperProfile.cs index 8838cee634..af59d75321 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorAutoMapperProfile.cs +++ b/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorAutoMapperProfile.cs @@ -10,10 +10,11 @@ public class AbpAccountBlazorAutoMapperProfile : Profile public AbpAccountBlazorAutoMapperProfile() { CreateMap() + .MapExtraProperties() .Ignore(x => x.PhoneNumberConfirmed) .Ignore(x => x.EmailConfirmed); CreateMap() - .Ignore(x => x.ExtraProperties); + .MapExtraProperties(); } } diff --git a/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorModule.cs b/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorModule.cs index c1e52e9b5f..61b42e1807 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorModule.cs +++ b/modules/account/src/Volo.Abp.Account.Blazor/AbpAccountBlazorModule.cs @@ -1,8 +1,12 @@ using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Account.Blazor.Pages.Account; using Volo.Abp.AspNetCore.Components.Web.Theming; using Volo.Abp.AspNetCore.Components.Web.Theming.Routing; using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.ObjectExtending.Modularity; +using Volo.Abp.Threading; using Volo.Abp.UI.Navigation; namespace Volo.Abp.Account.Blazor; @@ -14,6 +18,8 @@ namespace Volo.Abp.Account.Blazor; )] public class AbpAccountBlazorModule : AbpModule { + private readonly static OneTimeRunner OneTimeRunner = new OneTimeRunner(); + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAutoMapperObjectMapper(); @@ -33,4 +39,17 @@ public class AbpAccountBlazorModule : AbpModule options.AdditionalAssemblies.Add(typeof(AbpAccountBlazorModule).Assembly); }); } + + public override void PostConfigureServices(ServiceConfigurationContext context) + { + OneTimeRunner.Run(() => + { + ModuleExtensionConfigurationHelper + .ApplyEntityConfigurationToUi( + IdentityModuleExtensionConsts.ModuleName, + IdentityModuleExtensionConsts.EntityNames.User, + editFormTypes: new[] { typeof(PersonalInfoModel) } + ); + }); + } } diff --git a/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor b/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor index a3a4e76b58..2a625f3e35 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor +++ b/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor @@ -1,5 +1,9 @@ @page "/account/manage-profile" @using Microsoft.AspNetCore.Components.Forms +@using Volo.Abp.Account.Localization +@using Volo.Abp.AspNetCore.Components.Web +@using Volo.Abp.BlazoriseUI.Components.ObjectExtending +@inject AbpBlazorMessageLocalizerHelper LH @inherits AbpAccountComponentBase @@ -58,6 +62,7 @@ @L["DisplayName:PhoneNumber"] + diff --git a/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor.cs b/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor.cs index 3a0aff243b..567363843b 100644 --- a/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor.cs +++ b/modules/account/src/Volo.Abp.Account.Blazor/Pages/Account/AccountManage.razor.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Components; using Volo.Abp.AspNetCore.Components.Messages; using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Account.Blazor.Pages.Account; @@ -58,7 +59,7 @@ public partial class AccountManage await UiMessageService.Success(L["PasswordChanged"]); } - protected async Task UpdatePersonalInfoAsync() + protected virtual async Task UpdatePersonalInfoAsync() { await ProfileAppService.UpdateAsync( ObjectMapper.Map(PersonalInfoModel) @@ -86,7 +87,7 @@ public class ChangePasswordModel } } -public class PersonalInfoModel +public class PersonalInfoModel : ExtensibleObject { public string UserName { get; set; } diff --git a/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebAutomapperProfile.cs b/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebAutomapperProfile.cs index 329f8f7ac1..cdc92e8b19 100644 --- a/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebAutomapperProfile.cs +++ b/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebAutomapperProfile.cs @@ -9,6 +9,7 @@ public class AbpAccountWebAutoMapperProfile : Profile { public AbpAccountWebAutoMapperProfile() { - CreateMap(); + CreateMap() + .MapExtraProperties(); } } diff --git a/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs b/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs index 0dc4f2fc48..9f670ffc82 100644 --- a/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs +++ b/modules/account/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Account.Localization; using Volo.Abp.Account.Web.Pages.Account; +using Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.PersonalInfo; using Volo.Abp.Account.Web.ProfileManagement; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; @@ -12,6 +13,9 @@ using Volo.Abp.ExceptionHandling; using Volo.Abp.Http.ProxyScripting.Generators.JQuery; using Volo.Abp.Identity.AspNetCore; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.ObjectExtending.Modularity; +using Volo.Abp.Threading; using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; @@ -26,6 +30,8 @@ namespace Volo.Abp.Account.Web; )] public class AbpAccountWebModule : AbpModule { + private readonly static OneTimeRunner OneTimeRunner = new OneTimeRunner(); + public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.PreConfigure(options => @@ -95,4 +101,17 @@ public class AbpAccountWebModule : AbpModule }); } + + public override void PostConfigureServices(ServiceConfigurationContext context) + { + OneTimeRunner.Run(() => + { + ModuleExtensionConfigurationHelper + .ApplyEntityConfigurationToUi( + IdentityModuleExtensionConsts.ModuleName, + IdentityModuleExtensionConsts.EntityNames.User, + editFormTypes: new[] { typeof(AccountProfilePersonalInfoManagementGroupViewComponent.PersonalInfoModel) } + ); + }); + } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs index 45705eb7f5..0dea3bc6eb 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/AccountProfilePersonalInfoManagementGroupViewComponent.cs @@ -5,6 +5,7 @@ using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.Widgets; using Volo.Abp.Domain.Entities; using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; using Volo.Abp.Validation; namespace Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.PersonalInfo; @@ -30,7 +31,7 @@ public class AccountProfilePersonalInfoManagementGroupViewComponent : AbpViewCom return View("~/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml", model); } - public class PersonalInfoModel : IHasConcurrencyStamp + public class PersonalInfoModel : ExtensibleObject, IHasConcurrencyStamp { [Required] [DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))] @@ -54,7 +55,6 @@ public class AccountProfilePersonalInfoManagementGroupViewComponent : AbpViewCom [Display(Name = "DisplayName:PhoneNumber")] public string PhoneNumber { get; set; } - [HiddenInput] - public string ConcurrencyStamp { get; set; } + [HiddenInput] public string ConcurrencyStamp { get; set; } } -} +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml index ba695a8557..b9b0783ab9 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.cshtml @@ -1,13 +1,24 @@ @using Volo.Abp.Account.Localization @using Volo.Abp.Users @using Microsoft.AspNetCore.Mvc.Localization +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using Microsoft.Extensions.Localization +@using Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.PersonalInfo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Alert +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid @using Volo.Abp.AspNetCore.Mvc.UI.Theming +@using Volo.Abp.Data @using Volo.Abp.Identity.Settings +@using Volo.Abp.Localization +@using Volo.Abp.ObjectExtending @using Volo.Abp.Settings @inject IHtmlLocalizer L @inject ICurrentUser CurrentUser @inject ISettingProvider SettingManager @inject IThemeManager ThemeManager +@inject IStringLocalizerFactory StringLocalizerFactory @model Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.PersonalInfo.AccountProfilePersonalInfoManagementGroupViewComponent.PersonalInfoModel @{ var isUserNameUpdateEnabled = string.Equals(await SettingManager.GetOrNullAsync(IdentitySettingNames.User.IsUserNameUpdateEnabled), "true", @@ -19,8 +30,8 @@

@L["PersonalSettings"]


- - + + @@ -37,5 +48,39 @@ + @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties()) + { + if (!propertyInfo.Name.EndsWith("_Text")) + { + if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty()) + { + if (propertyInfo.Type.IsEnum) + { + Model.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type); + } + + + } + else + { + + } + } + } + - + \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.js b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.js index 55a88e52e3..c8ff17ec67 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.js +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Components/ProfileManagementGroup/PersonalInfo/Default.js @@ -9,7 +9,7 @@ return false; } - var input = $('#PersonalSettingsForm').serializeFormToObject(); + var input = $('#PersonalSettingsForm').serializeFormToObject(false); volo.abp.account.profile.update(input).then(function (result) { abp.notify.success(l('PersonalSettingsSaved')); diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Contents/ContentParser.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Contents/ContentParser.cs index 7fe9fe5b60..617e7d61cc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Contents/ContentParser.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Contents/ContentParser.cs @@ -20,11 +20,11 @@ public class ContentParser : ITransientDependency public Task> ParseAsync(string content) { - if (!_options.WidgetConfigs.Any()) + if (!_options.WidgetConfigs.Any() || content is null) { return Task.FromResult(new List { - new ContentFragment { Type = Markdown }.SetProperty(Content, content), + new ContentFragment { Type = Markdown }.SetProperty(Content, content ?? string.Empty), }); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs index 47f20e1d72..7787d0c69d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs @@ -1,6 +1,6 @@ namespace Volo.CmsKit.GlobalResources; -public class GlobalResourceConsts +public static class GlobalResourceConsts { public const string GlobalStyleName = "GlobalStyle"; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs index 16e0575288..5d1ba87fe0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs @@ -1,8 +1,12 @@ -namespace Volo.CmsKit.Public.GlobalResources; +using System; +using Volo.Abp.Application.Dtos; -public class GlobalResourceDto +namespace Volo.CmsKit.Public.GlobalResources; + +[Serializable] +public class GlobalResourceDto : AuditedEntityDto { public string Name { get; set; } - + public string Value { get; set; } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs index 1e9503006c..d16e271e4e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs @@ -5,11 +5,10 @@ using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EventBus; using Volo.Abp.ObjectMapping; using Volo.CmsKit.GlobalResources; -using Volo.CmsKit.Public.GlobalResources; namespace Volo.CmsKit.Public.GlobalResources.Handlers; -public class GlobalResourceEventHandler: +public class GlobalResourceEventHandler : ILocalEventHandler>, ITransientDependency { @@ -23,11 +22,11 @@ public class GlobalResourceEventHandler: ObjectMapper = objectMapper; _resourceCache = resourceCache; } - + public async Task HandleEventAsync(EntityUpdatedEventData eventData) { await _resourceCache.SetAsync( - eventData.Entity.Name, + eventData.Entity.Name, ObjectMapper.Map(eventData.Entity)); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml index 11929dec03..fdcfb382bb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml @@ -1 +1,3 @@ - +@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style.GlobalStyleModel + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleModel.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleModel.cs new file mode 100644 index 0000000000..869f768987 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleModel.cs @@ -0,0 +1,6 @@ +namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style; + +public class GlobalStyleModel +{ + public long LastModificationTimeTimestamp { get; set; } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs index 3d9bc010c4..49062bdb06 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs @@ -1,13 +1,33 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Public.GlobalResources; namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style; public class GlobalStyleViewComponent : AbpViewComponent { + protected IGlobalResourcePublicAppService GlobalResourcePublicAppService { get; } + + public GlobalStyleViewComponent(IGlobalResourcePublicAppService globalResourcePublicAppService) + { + GlobalResourcePublicAppService = globalResourcePublicAppService; + } + + [BindProperty(SupportsGet = true)] + public DateTime? LastModificationTime { get; set; } + public async Task InvokeAsync() { - return View("~/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml"); + var lastModificationTime = (await GlobalResourcePublicAppService.GetGlobalStyleAsync())?.LastModificationTime; + var lastModificationTimeTimestamp = (long)(lastModificationTime.HasValue ? lastModificationTime.Value.Subtract(DateTime.UnixEpoch).TotalSeconds : 0); + + return View("~/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml", + new GlobalStyleModel() + { + LastModificationTimeTimestamp = lastModificationTimeTimestamp + }); } + } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs index a1e30a2679..4ef7c82c0d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using Markdig; using System.Threading.Tasks; using System.Web; -using Volo.Abp.DependencyInjection; using Ganss.XSS; +using Markdig; +using Volo.Abp.DependencyInjection; namespace Volo.CmsKit.Public.Web.Renderers; @@ -20,7 +20,7 @@ public class MarkdownToHtmlRenderer : IMarkdownToHtmlRenderer, ITransientDepende _htmlSanitizer = new HtmlSanitizer(); } - public async Task RenderAsync(string rawMarkdown, bool allowHtmlTags = true, bool preventXSS = true) + public Task RenderAsync(string rawMarkdown, bool allowHtmlTags = true, bool preventXSS = true) { if (!allowHtmlTags) { @@ -34,7 +34,7 @@ public class MarkdownToHtmlRenderer : IMarkdownToHtmlRenderer, ITransientDepende html = _htmlSanitizer.Sanitize(html); } - return html; + return Task.FromResult(html); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs index ce6c7d7049..0e86e4e526 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs @@ -62,7 +62,7 @@ public class IdentityRole : AggregateRoot, IMultiTenant Name = name; TenantId = tenantId; NormalizedName = name.ToUpperInvariant(); - ConcurrencyStamp = Guid.NewGuid().ToString(); + ConcurrencyStamp = Guid.NewGuid().ToString("N"); Claims = new Collection(); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs index 834f0d8d7a..eec620395c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs @@ -158,7 +158,7 @@ public class IdentityUser : FullAuditedAggregateRoot, IUser NormalizedUserName = userName.ToUpperInvariant(); Email = email; NormalizedEmail = email.ToUpperInvariant(); - ConcurrencyStamp = Guid.NewGuid().ToString(); + ConcurrencyStamp = Guid.NewGuid().ToString("N"); SecurityStamp = Guid.NewGuid().ToString(); IsActive = true; diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs index 8b08732378..65c3ff5a39 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserStore_Tests.cs @@ -112,7 +112,7 @@ public class IdentityUserStore_Tests : AbpIdentityDomainTestBase (await _identityUserStore.UpdateAsync(user)).Succeeded.ShouldBeTrue(); - user.ConcurrencyStamp = Guid.NewGuid().ToString(); + user.ConcurrencyStamp = Guid.NewGuid().ToString("N"); var identityResult = await _identityUserStore.UpdateAsync(user); identityResult.Succeeded.ShouldBeFalse(); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Scopes/AbpOpenIddictScopeCache.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Scopes/AbpOpenIddictScopeCache.cs index af5999fcc5..267fb175e2 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Scopes/AbpOpenIddictScopeCache.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Scopes/AbpOpenIddictScopeCache.cs @@ -9,11 +9,11 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.OpenIddict.Scopes; -public class AbpOpenIddictScopeCacheAbpOpenIddictAuthorizationCache : AbpOpenIddictCacheBase>, +public class AbpOpenIddictScopeCache : AbpOpenIddictCacheBase>, IOpenIddictScopeCache, ITransientDependency { - public AbpOpenIddictScopeCacheAbpOpenIddictAuthorizationCache( + public AbpOpenIddictScopeCache( IDistributedCache cache, IDistributedCache arrayCache, IOpenIddictScopeStore store) diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs index e0ce655235..5b388d9078 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs @@ -1,6 +1,7 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.TenantManagement.Localization; +using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Validation; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; @@ -25,5 +26,10 @@ public class AbpTenantManagementDomainSharedModule : AbpModule typeof(AbpValidationResource) ).AddVirtualJson("/Volo/Abp/TenantManagement/Localization/Resources"); }); + + Configure(options => + { + options.MapCodeNamespace("Volo.Abp.TenantManagement", typeof(AbpTenantManagementResource)); + }); } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json index 134da8c601..829a326d24 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json @@ -1,6 +1,7 @@ { "culture": "ar", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "اسم المستأجر موجود بالفعل: {Name}", "Menu:TenantManagement": "إدارة الجهات", "Tenants": "الجهات", "NewTenant": "جهة جديدة", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json index 16644b17aa..2033fdf1ed 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json @@ -1,6 +1,7 @@ { "culture": "de-DE", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Der Name des Mandanten ist bereits vorhanden: {Name}", "Menu:TenantManagement": "Mandantenverwaltung", "Tenants": "Mandanten", "NewTenant": "Neuer Mandant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json index ba4109c392..1a10c5b77a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json @@ -1,6 +1,7 @@ { "culture": "en", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Tenant name already exist: {Name}", "Menu:TenantManagement": "Tenant management", "Tenants": "Tenants", "NewTenant": "New tenant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json index cd18e3c33b..774201178b 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json @@ -1,6 +1,7 @@ { "culture": "es", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "El nombre del inquilino ya existe: {Name}", "Menu:TenantManagement": "Gestión de tenants", "Tenants": "Inquilinos", "NewTenant": "Nuevo inquilino", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json index cae6bf6cac..b24d67135e 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json @@ -1,6 +1,7 @@ { "culture": "fi", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Vuokralaisen nimi on jo olemassa: {Name}", "Menu:TenantManagement": "Vuokralaisten hallinta", "Tenants": "Vuokralaiset", "NewTenant": "Uusi vuokralainen", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json index 4aac3eebab..4d6ccd76b0 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json @@ -1,6 +1,7 @@ { "culture": "fr", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Le nom du locataire existe déjà: {Name}", "Menu:TenantManagement": "Gestion des locataires", "Tenants": "Locataires", "NewTenant": "Nouveau locataire", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json index 1094744a16..93f4a1a1ad 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json @@ -1,6 +1,7 @@ { "culture": "hi", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "किरायेदार नाम पहले से मौजूद है: {Name}", "Menu:TenantManagement": "किरायेदार प्रबंधन", "Tenants": "किरायेदारों", "NewTenant": "नया किरायेदार", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json index c80b7974ab..6deff1bd54 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json @@ -1,6 +1,7 @@ { "culture": "it", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Il nome del tenant esiste già: {Name}", "Menu:TenantManagement": "Gestione tenants", "Tenants": "Tenants", "NewTenant": "Nuovo Tenant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json index 6f43740161..d2c3ceecf1 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json @@ -1,6 +1,7 @@ { "culture": "pt-BR", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "O nome do ambiente já existe: {Name}", "Menu:TenantManagement": "Gerencimento de Inquilinos", "Tenants": "Inquilinos", "NewTenant": "Novo Inquilino", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json index 9e5732bbd7..b3585c20a4 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json @@ -1,6 +1,7 @@ { "culture": "ru", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Имя арендатора уже существует: {Name}", "Menu:TenantManagement": "Управление арендаторами", "Tenants": "Арендаторы", "NewTenant": "Новый арендатор", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json index df3cd3dd13..e37d605d16 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json @@ -1,6 +1,7 @@ { "culture": "sk", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Názov tenanta už existuje: {Name}", "Menu:TenantManagement": "Správa tenantov", "Tenants": "Tentanti", "NewTenant": "Nový tenant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json index b9df388d7c..9e5d1c215a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json @@ -1,6 +1,7 @@ { "culture": "sl", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Ime najemnika že obstaja: {Name}", "Menu:TenantManagement": "Upravljanje najemnikov", "Tenants": "Najemniki", "NewTenant": "Nov najemnik", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json index 25ca3f2407..ffbab818f2 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json @@ -1,6 +1,7 @@ { "culture": "tr", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Müşteri ismi zaten mevcut: {Name}", "Menu:TenantManagement": "Müşteri yönetimi", "Tenants": "Müşteriler", "NewTenant": "Yeni müşteri", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json index 034d4bac81..94ef8abba1 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json @@ -1,6 +1,7 @@ { "culture": "zh-Hans", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "租户名称已存在: {Name}", "Menu:TenantManagement": "租户管理", "Tenants": "租户", "NewTenant": "新租户", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json index 6950a1ca00..1403cb79d5 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json @@ -1,6 +1,7 @@ { "culture": "zh-Hant", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "租戶名稱已存在: {Name}", "Menu:TenantManagement": "租戶管理", "Tenants": "租戶", "NewTenant": "新租戶", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs index 8fc75d2ecb..fa388426d9 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs @@ -36,7 +36,7 @@ public class TenantManager : DomainService, ITenantManager var tenant = await TenantRepository.FindByNameAsync(name); if (tenant != null && tenant.Id != expectedId) { - throw new UserFriendlyException("Duplicate tenancy name: " + name); //TODO: A domain exception would be better..? + throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", name); } } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs index 6b86c8503c..b797e05566 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs @@ -66,7 +66,7 @@ public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase [Fact] public async Task CreateAsync_Should_Not_Allow_Duplicate_Names() { - await Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await _tenantAppService.CreateAsync(new TenantCreateDto { Name = "acme", AdminEmailAddress = "admin@admin.com", AdminPassword = "123456" }); }); @@ -90,7 +90,7 @@ public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase { var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); - await Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "volosoft" }); }); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs index fcacb22e37..161882e412 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs @@ -26,7 +26,7 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase [Fact] public async Task Create_Tenant_Name_Can_Not_Duplicate() { - await Assert.ThrowsAsync(async () => await _tenantManager.CreateAsync("volosoft")); + await Assert.ThrowsAsync(async () => await _tenantManager.CreateAsync("volosoft")); } [Fact] @@ -46,6 +46,6 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase var tenant = await _tenantRepository.FindByNameAsync("acme"); tenant.ShouldNotBeNull(); - await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); + await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); } } diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index 7873adf6ea..99d435c891 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -39,7 +39,7 @@ >
-
+