Browse Source

Merge branch 'dev' into ui-extensions-blazor

pull/7686/head
Ilkay Ilknur 6 years ago
parent
commit
6386fe44f1
  1. 8
      Directory.Build.props
  2. 10
      common.props
  3. 48
      docs/en/Community-Articles/2020-04-27-Use-Azure-Active-Directory-Authentication-for-MVC-Razor-Page-Applications/POST.md
  4. 12
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/POST.md
  5. 110
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/POST.md
  6. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/both-example-result.png
  7. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/cover-image.png
  8. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/data-grid-app-contract.png
  9. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/data-grid-application.png
  10. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/data-grid-blazor.png
  11. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/initial-project.png
  12. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/sample-appointment.gif
  13. 534
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md
  14. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/automated-nuget-feed-setup.png
  15. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/final-result.jpg
  16. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/sample-application.jpg
  17. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/telerik-blazor-component-1.jpg
  18. BIN
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/telerik-progress-bar.gif
  19. 1581
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/POST.md
  20. BIN
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/author-crud.gif
  21. BIN
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/author-with-books.gif
  22. BIN
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-create.gif
  23. BIN
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-delete.gif
  24. BIN
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-edit.gif
  25. BIN
      docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-list.gif
  26. 392
      docs/en/Module-Entity-Extensions.md
  27. 2
      docs/en/Modules/Identity.md
  28. 3
      docs/en/Tutorials/Part-3.md
  29. 2
      docs/en/Tutorials/Part-4.md
  30. 6
      docs/en/Tutorials/Part-7.md
  31. 2
      docs/en/Tutorials/Part-9.md
  32. 44
      docs/en/UI/Angular/List-Service.md
  33. 161
      docs/en/UI/AspNetCore/Data-Table-Column-Extensions.md
  34. 108
      docs/en/UI/AspNetCore/Entity-Action-Extensions.md
  35. 2
      docs/en/UI/AspNetCore/Theming.md
  36. 3
      docs/en/UI/Blazor/Testing.md
  37. BIN
      docs/en/images/add-new-propert-to-user-database-extra-properties.png
  38. BIN
      docs/en/images/add-new-propert-to-user-database-field.png
  39. BIN
      docs/en/images/add-new-property-enum.png
  40. BIN
      docs/en/images/add-new-property-to-user-form-validation-error-custom.png
  41. BIN
      docs/en/images/add-new-property-to-user-form-validation-error.png
  42. BIN
      docs/en/images/add-new-property-to-user-form.png
  43. BIN
      docs/en/images/add-new-property-to-user-table.png
  44. BIN
      docs/en/images/table-column-extension-example.png
  45. BIN
      docs/en/images/user-action-extension-click-me.png
  46. BIN
      docs/en/images/user-action-extension-on-solution.png
  47. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs
  48. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/tenant-switch.js
  49. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/CmsKit/CmsKitScriptContributor.cs
  50. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/CmsKit/CmsKitStyleContributor.cs
  51. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj
  52. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/StandardLayouts.cs
  53. 7
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/ThemeExtensions.cs
  54. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  55. 2
      framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj
  56. 3
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs
  57. 4
      framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj
  58. 43
      framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpAutofacConstructorFinder.cs
  59. 15
      framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
  60. 10
      framework/src/Volo.Abp.BlazoriseUI/Components/SubmitButton.razor
  61. 73
      framework/src/Volo.Abp.BlazoriseUI/Components/SubmitButton.razor.cs
  62. 2
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.csproj
  63. 4
      framework/src/Volo.Abp.BlobStoring.Aws/Volo.Abp.BlobStoring.Aws.csproj
  64. 2
      framework/src/Volo.Abp.BlobStoring.Azure/Volo.Abp.BlobStoring.Azure.csproj
  65. 8
      framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj
  66. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Module/ModuleTemplateBase.cs
  67. 28
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs
  68. 118
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
  69. 8
      framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj
  70. 2
      framework/src/Volo.Abp.Dapper/Volo.Abp.Dapper.csproj
  71. 2
      framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj
  72. 2
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
  73. 2
      framework/src/Volo.Abp.FluentValidation/Volo.Abp.FluentValidation.csproj
  74. 5
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs
  75. 2
      framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeature.cs
  76. 2
      framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionary.cs
  77. 2
      framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj
  78. 2
      framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj
  79. 2
      framework/src/Volo.Abp.Kafka/Volo.Abp.Kafka.csproj
  80. 2
      framework/src/Volo.Abp.MailKit/Volo.Abp.MailKit.csproj
  81. 2
      framework/src/Volo.Abp.Minify/Volo.Abp.Minify.csproj
  82. 2
      framework/src/Volo.Abp.MongoDB/Volo.Abp.MongoDB.csproj
  83. 1
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/EntityExtensionConfiguration.cs
  84. 6
      framework/src/Volo.Abp.Quartz/Volo.Abp.Quartz.csproj
  85. 2
      framework/src/Volo.Abp.RabbitMQ/Volo.Abp.RabbitMQ.csproj
  86. 4
      framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj
  87. 2
      framework/src/Volo.Abp.TextTemplating/Volo.Abp.TextTemplating.csproj
  88. 15
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs
  89. 11
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs
  90. 12
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs
  91. 2
      framework/src/Volo.Abp.Timing/Volo.Abp.Timing.csproj
  92. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj
  93. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json
  94. 224
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock
  95. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj
  96. 4
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json
  97. 256
      framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock
  98. 2
      framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo.Abp.AspNetCore.Serilog.Tests.csproj
  99. 4
      framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo/Abp/AspNetCore/Serilog/Serilog_Enrichers_Tests.cs
  100. 5
      framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj

8
Directory.Build.props

@ -2,16 +2,16 @@
<PropertyGroup> <PropertyGroup>
<!-- All Microsoft packages --> <!-- All Microsoft packages -->
<MicrosoftPackageVersion>5.0.0</MicrosoftPackageVersion> <MicrosoftPackageVersion>5.0.*</MicrosoftPackageVersion>
<!-- Microsoft.NET.Test.Sdk https://www.nuget.org/packages/Microsoft.NET.Test.Sdk --> <!-- Microsoft.NET.Test.Sdk https://www.nuget.org/packages/Microsoft.NET.Test.Sdk -->
<MicrosoftNETTestSdkPackageVersion>16.6.1</MicrosoftNETTestSdkPackageVersion> <MicrosoftNETTestSdkPackageVersion>16.8.3</MicrosoftNETTestSdkPackageVersion>
<!-- NSubstitute https://www.nuget.org/packages/NSubstitute --> <!-- NSubstitute https://www.nuget.org/packages/NSubstitute -->
<NSubstitutePackageVersion>4.2.2</NSubstitutePackageVersion> <NSubstitutePackageVersion>4.2.2</NSubstitutePackageVersion>
<!-- Shouldly https://www.nuget.org/packages/Shouldly --> <!-- Shouldly https://www.nuget.org/packages/Shouldly -->
<ShouldlyPackageVersion>3.0.2</ShouldlyPackageVersion> <ShouldlyPackageVersion>4.0.1</ShouldlyPackageVersion>
<!-- xunit https://www.nuget.org/packages/xUnit --> <!-- xunit https://www.nuget.org/packages/xUnit -->
<xUnitPackageVersion>2.4.1</xUnitPackageVersion> <xUnitPackageVersion>2.4.1</xUnitPackageVersion>
@ -20,7 +20,7 @@
<xUnitExtensibilityExecutionPackageVersion>2.4.1</xUnitExtensibilityExecutionPackageVersion> <xUnitExtensibilityExecutionPackageVersion>2.4.1</xUnitExtensibilityExecutionPackageVersion>
<!-- xunit.runner.visualstudio https://www.nuget.org/packages/xunit.runner.visualstudio --> <!-- xunit.runner.visualstudio https://www.nuget.org/packages/xunit.runner.visualstudio -->
<xUnitRunnerVisualstudioPackageVersion>2.4.2</xUnitRunnerVisualstudioPackageVersion> <xUnitRunnerVisualstudioPackageVersion>2.4.3</xUnitRunnerVisualstudioPackageVersion>
<!-- Mongo2Go https://www.nuget.org/packages/Mongo2Go --> <!-- Mongo2Go https://www.nuget.org/packages/Mongo2Go -->
<Mongo2GoPackageVersion>2.2.14</Mongo2GoPackageVersion> <Mongo2GoPackageVersion>2.2.14</Mongo2GoPackageVersion>

10
common.props

@ -9,8 +9,16 @@
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/abpframework/abp/</RepositoryUrl> <RepositoryUrl>https://github.com/abpframework/abp/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- https://github.com/dotnet/sourcelink -->
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="All" /> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

48
docs/en/Community-Articles/2020-04-27-Use-Azure-Active-Directory-Authentication-for-MVC-Razor-Page-Applications/POST.md

@ -6,9 +6,9 @@ Adding Azure Active Directory is pretty straightforward in ABP framework. Couple
Two different **alternative approaches** for AzureAD integration will be demonstrated for better coverage. Two different **alternative approaches** for AzureAD integration will be demonstrated for better coverage.
1. **AddAzureAD**: This approach uses Microsoft [AzureAD UI nuget package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/) which is very popular when users search the web about how to integrate AzureAD to their web application. 1. ~~**AddAzureAD**: This approach uses Microsoft [AzureAD UI nuget package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/) which is very popular when users search the web about how to integrate AzureAD to their web application.~~ Now marked **Obsolete** (see https://github.com/aspnet/Announcements/issues/439).
2. **AddOpenIdConnect**: This approach uses default [OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect/) which can be used for not only AzureAD but for all OpenId connections. 2. **AddOpenIdConnect**: This approach uses default [OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect/) which can be used for not only AzureAD but for all OpenId connections.
3. **AddMicrosoftIdentityWebAppAuthentication:** This approach uses newly introduced [Microsoft.Identity.Web nuget package](https://www.nuget.org/packages/Microsoft.Identity.Web/) to replace AddAzureAD.
> There is **no difference** in functionality between these approaches. AddAzureAD is an abstracted way of OpenIdConnection ([source](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADAuthenticationBuilderExtensions.cs#L122)) with predefined cookie settings. > There is **no difference** in functionality between these approaches. AddAzureAD is an abstracted way of OpenIdConnection ([source](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADAuthenticationBuilderExtensions.cs#L122)) with predefined cookie settings.
> >
@ -134,13 +134,50 @@ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfi
And that's it, integration is completed. Keep on mind that you can connect any other external authentication providers. And that's it, integration is completed. Keep on mind that you can connect any other external authentication providers.
## 3. AddMicrosoftIdentityWebAppAuthentication
With .Net 5.0, AzureAd is marked [obsolute](https://github.com/dotnet/aspnetcore/issues/25807) and will not be supported in the near future. However its expanded functionality is available in [microsoft-identity-web](https://github.com/AzureAD/microsoft-identity-web/wiki) packages.
Add (or replace with) the new nuget package Microsoft.Identity.Web nuget package](https://www.nuget.org/packages/Microsoft.Identity.Web/).
In your **.Web** project; you update the `ConfigureAuthentication` method located in your **ApplicationWebModule** with the following while having the AzureAd appsettings section as defined before:
````csharp
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = false;
options.ApiName = "Acme.BookStore";
});
context.Services.AddMicrosoftIdentityWebAppAuthentication(
configuration: configuration,
configSectionName: "AzureAd",
openIdConnectScheme:"AzureAD",
cookieScheme:null);
}
````
And that's all to add new Microsoft-Identity-Web.
> **Don't forget to:**
>
> * Pass **cookieScheme** parameter as **null** or your [*GetExternalLoginInfoAsync* method will always return null](https://github.com/AzureAD/microsoft-identity-web/issues/133#).
Keep in mind that [Microsoft-Identity-Web](https://github.com/AzureAD/microsoft-identity-web) is relatively new and keeps getting new enhancements, features and documentation.
## The Source Code ## The Source Code
You can find the source code of the completed example [here](https://github.com/abpframework/abp-samples/tree/master/Authentication-Customization). You can find the source code of the completed example [here](https://github.com/abpframework/abp-samples/tree/master/Authentication-Customization).
# FAQ # FAQ
* Help! `GetExternalLoginInfoAsync` returns `null`! * Help! `GetExternalLoginInfoAsync` returns `null`! (Using obsolute **AddAzureAD**)
* There can be 2 reasons for this; * There can be 2 reasons for this;
@ -158,6 +195,11 @@ You can find the source code of the completed example [here](https://github.com/
```` ````
* Help! `GetExternalLoginInfoAsync` returns `null`! (Using **AddMicrosoftIdentityWebAppAuthentication**)
* Pass cookieScheme parameter as **null**. (See [this issue](https://github.com/AzureAD/microsoft-identity-web/issues/133)).
* Help! I am getting ***System.ArgumentNullException: Value cannot be null. (Parameter 'userName')*** error! * Help! I am getting ***System.ArgumentNullException: Value cannot be null. (Parameter 'userName')*** error!

12
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/POST.md

@ -1,22 +1,22 @@
# How to Setup Azure Active Directory and Integrate Abp Angular Application # How to Setup Azure Active Directory and Integrate ABP Angular Application
This guide demonstrates how to register an application to Azure Active Directory and integrate AzureAD to an ABP angular application that enables users to sign in using OAuth 2.0 with credentials from **Azure Active Directory**. This guide demonstrates how to register an application to Azure Active Directory and integrate AzureAD to an ABP Angular application that enables users to sign in using OAuth 2.0 with credentials from **Azure Active Directory**.
## Authentication Flow ## Authentication Flow
Abp angular applications use **Authentication Code with PKCE** (specs [here](https://tools.ietf.org/html/rfc7636)) which is the most suitable flow for spa applications by the time this article is written since implicit flow is deprecated. ABP Angular application uses **Authentication Code with PKCE** (specs [here](https://tools.ietf.org/html/rfc7636)) which is the most suitable flow for SPA applications by the time this article is written since implicit flow is deprecated.
The most common question is; The most common question is;
> Where to put OpenId connection code in angular project? > Where to put OpenId connection code in the Angular project?
The answer is, **you don't**. Abp angular application is integrated with backend code (HttpApi.Host project) where it loads the configurations, **permissions** etc. For none-tiered angular applications, **HttpApi.Host** project also has IdentityServer4 embedded; also serving as **Authorization Server**. Angular application authentication flow is shown below. The answer is, **you don't**. ABP Angular application is integrated with the backend (HttpApi.Host project) where it loads the configurations, **permissions** etc. For none-tiered angular applications, **HttpApi.Host** project also has IdentityServer4 embedded; also serving as **Authorization Server**. Angular application authentication flow is shown below.
<img src="auth-diagram.jpeg" alt="auth-diagram" style="zoom:50%;" /> <img src="auth-diagram.jpeg" alt="auth-diagram" style="zoom:50%;" />
> What if I want Azure AD as my authorization server and not IdentityServer? > What if I want Azure AD as my authorization server and not IdentityServer?
This means your application will be using AzureAD user store for authentication. By registering both angular app and HttpApi to AzureAD, authentication might work but **authorization won't**. Users need to be registered to Abp identity system for auditing, permissions etc. So the flow should be 3rd party registration. This means your application will be using AzureAD user store for authentication. By registering both Angular app and HttpApi to AzureAD, authentication might work but **authorization won't**. Users need to be registered to ABP identity system for auditing, permissions etc. So the flow should be 3rd party registration.
## Setting up OpenId Connection ## Setting up OpenId Connection

110
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/POST.md

@ -0,0 +1,110 @@
## Using DevExpress Blazor UI Components With the ABP Framework
Hi, in this step by step article, I will show you how to integrate [DevExpress](https://demos.devexpress.com/blazor/) blazor UI components into ABP Framework-based applications.
![both-example-result](both-example-result.png)
*(A screenshot from the example application developed in this article)*
## Create the Project
> ABP Framework offers startup templates to get into business faster.
In this article, I will create a new startup template with EF Core as a database provider and Blazor for UI framework. But if you already have a project with Blazor UI, you don't need to create a new startup template, you can directly implement the following steps to your existing project.
> If you already have a project with the Blazor UI, you can skip this section.
* Before starting to development, we will create a solution named `DevExpressSample` (or whatever you want). We will create a new startup template with EF Core as a database provider and Blazor for UI framework by using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI):
````bash
abp new DevExpressSample -u blazor
````
![initial-project](initial-project.png)
* Our project boilerplate will be ready after the download is finished. Then, we can open the solution in the Visual Studio (or any other IDE) and run the `DevExpressSample.DbMigrator` to create the database and seed initial data (which creates the admin user, admin role, permissions etc.)
* After database and initial data created,
* Run the `DevExpressSample.HttpApi.Host` to see our server side working and
* Run the `DevExpressSample.Blazor` to see our UI working properly.
> _Default login credentials for admin: username is **admin** and password is **1q2w3E\***_
## Install DevExpress
You can follow [this documentation](https://docs.devexpress.com/Blazor/401986/getting-started/install-components-and-create-an-application/without-devexpress-installer/microsoft-templates) to install DevExpress packages into your computer.
> Don't forget to add _"DevExpress NuGet Feed"_ to your **Nuget Package Sources**.
### Adding DevExpress NuGet Packages
Add the `DevExpress.Blazor` NuGet package to the `DevExpressSample.Blazor` project.
```
Install-Package DevExpress.Blazor
```
### Register DevExpress Resources
1. Add the following line to the HEAD section of the `wwwroot/index.html` file within the `DevExpressSample.Blazor` project:
```Razor
<head>
<!--...-->
<link href="_content/DevExpress.Blazor/dx-blazor.css" rel="stylesheet" />
</head>
```
2. In the `DevExpressSampleBlazorModule` class, call the `AddDevExpressBlazor()` method from your project's `ConfigureServices()` method:
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var environment = context.Services.GetSingletonInstance<IWebAssemblyHostEnvironment>();
var builder = context.Services.GetSingletonInstance<WebAssemblyHostBuilder>();
// ...
builder.Services.AddDevExpressBlazor();
}
```
3. Register the **DevExpressSample.Blazor** namespace in the `_Imports.razor` file:
```Razor
@using DevExpress.Blazor
```
### Result
The installation step was done. You can use any DevExpress Blazor UI component in your application:
Example: A Scheduler:
![sample-appointment](sample-appointment.gif)
This example has been created by following [this documentation](https://demos.devexpress.com/blazor/SchedulerViewTypes).
## The Sample Application
We have created a sample application with [Data Grid](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxDataGrid-1) example.
### The Source Code
You can download the source code from [here](https://github.com/abpframework/abp-samples/tree/master/DevExpress-Blazor).
The related files for this example are marked in the following screenshots.
![data-grid-app-contract](data-grid-app-contract.png)
![data-grid-application](data-grid-application.png)
![data-grid-web](data-grid-blazor.png)
### Additional Notes
#### Data Storage
I've used an in-memory list to store data for this example, instead of a real database. Because it is not related to DevExpress usage. There is a `SampleDataService.cs` file in `Data` folder at `DevExpressSample.Application.Contracts` project. All the data is stored here.
## Conclusion
In this article, I've explained how to use [DevExpress](https://www.devexpress.com/blazor/) components in your application. ABP Framework is designed so that it can work with any UI library/framework.

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/both-example-result.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/data-grid-app-contract.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/data-grid-application.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/data-grid-blazor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/initial-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-DevExpress-Blazor-Component/sample-appointment.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 KiB

534
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md

@ -0,0 +1,534 @@
# How to Integrate the Telerik Blazor Components to the ABP Blazor UI?
## Introduction
Hi, in this step by step article, we will see how we can integrate the Telerik Blazor Components to our Blazor UI.
## Creating the Solution
> ABP Framework offers startup templates to get into business faster.
In this article, I will create a new startup template with EF Core as a database provider and Blazor for UI framework. But if you already have a project with Blazor UI, you don't need to create a new startup template, you can directly implement the following steps to your existing project.
> If you already have a project with the Blazor UI, you can skip this section.
* Before starting to development, we will create a solution named `TelerikComponents` (or whatever you want). We will create a new startup template with EF Core as a database provider and Blazor for UI framework by using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI):
```bash
abp new TelerikComponents --ui blazor --database-provider ef
```
* Our project boilerplate will be ready after the download is finished. Then, we can open the solution in the Visual Studio (or any other IDE) and run the `TelerikComponents.DbMigrator` to create the database and seed initial data (which creates the admin user, admin role, permissions, etc.)
* After the database and initial data created,
* Run the `TelerikComponents.HttpApi.Host` to see our server-side working and
* Run the `TelerikComponents.Blazor` to see our UI working.
> _Default login credentials for admin: username is **admin** and password is **1q2w3E\***_
## Starting the Development
### Pre-requisite
* First thing we need to do is downloading the [Progress Control Panel](https://www.telerik.com/download-trial-file/v2/control-panel?_ga=2.212029332.1667119438.1607582144-1944255175.1605161949) to get Telerik Blazor Components on our development machine.
* If you will use the Telerik Blazor Components for the first time or you don't have an active license you can click [here](https://www.telerik.com/login/v2/download-b?ReturnUrl=https%3a%2f%2fwww.telerik.com%2fdownload-trial-file%2fv2-b%2fui-for-blazor%3f_ga%3d2.212029332.1667119438.1607582144-1944255175.1605161949#register) to download free trial.
> You can find the more installation details from [here](https://docs.telerik.com/blazor-ui/getting-started/client-blazor?_ga=2.55603115.1667119438.1607582144-1944255175.1605161949&_gac=1.261851647.1607669357.CjwKCAiAq8f-BRBtEiwAGr3DgUDhBT25rs7hU0EQ8K-AfeUVxs3hSoIuIAuBOZ17CNPI4ZEArORPExoCyd4QAvD_BwE#step-0---download-the-components).
>**Notes:** To download Telerik Blazor packages via NuGet, we need to setup Telerik NuGet package source. We can state it in the installer as below. In this way, we can download the required Telerik Blazor packages via NuGet.
![setup-nuget-package-source](./automated-nuget-feed-setup.png)
### Step 1 (Configurations)
* We need to install the `Telerik.UI.for.Blazor` Nuget package to our Blazor project (`*.Blazor`). We need to choose package source to **telerik.com** for Visual Studio to see this package.
* If you use trial version of Telerik, you can download **Telerik.UI.for.Blazor.Trial** package via NuGet.
* After the installation finished, we need to open **index.html** (it's under *wwwroot* folder) to add css and js files in our application.
* Add the following lines just before the closing head tag (**/head**).
```html
...
<link rel="stylesheet" href="https:unpkg.com/@progress/kendo-theme-default@latest/dist/all.css" />
<script src="_content/Telerik.UI.for.Blazor/js/telerik-blazor.js" defer></script>
<!-- For Trial licenses use
<script src="_content/Telerik.UI.for.Blazor.Trial/js/telerik-blazor.js" defer></script>
-->
</head>
```
* After that, we need to add the Telerik Blazor Components to our application's service collection. So just open the `TelerikComponentsBlazorModule` and update the `ConfigureServices` method with the following content.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var environment = context.Services.GetSingletonInstance<IWebAssemblyHostEnvironment>();
var builder = context.Services.GetSingletonInstance<WebAssemblyHostBuilder>();
ConfigureAuthentication(builder);
ConfigureHttpClient(context, environment);
ConfigureBlazorise(context);
ConfigureRouter(context);
ConfigureUI(builder);
ConfigureMenu(context);
ConfigureAutoMapper(context);
//add this line to be able to use the components
builder.Services.AddTelerikBlazor();
}
```
* After the service added we will continue by opening **_Imports.razor** file and add the global using statements as below. This will bring our Telerik components into scope throughout the application.
![telerik-blazor-component-1](./telerik-blazor-component-1.jpg)
* After all of these steps, the Telerik UI Components are ready to be used anywhere in our application. We can use the Telerik Blazor Components by wrapping our components or pages between `<TelerikRootComponent>` and `</TelerikRootComponent>` tags.
### Step 2 - Checking Configurations
* We should check, have we done the right configurations or not. For that, we can open the **Index.razor** file and we can update the component with the following content.
```razor
@page "/"
@using Volo.Abp.MultiTenancy
@inherits TelerikComponentsComponentBase
@inject ICurrentTenant CurrentTenant
@inject AuthenticationStateProvider AuthenticationStateProvider
@using System.Timers
@implements IDisposable
<TelerikRootComponent>
<div class="progress-bar-wrapper">
<h5 class="progress-info-title">Telerik Progress Bar Component</h5>
<TelerikProgressBar Value="@ProgressValue" Max="100"></TelerikProgressBar>
</div>
</TelerikRootComponent>
@code {
private const int TimerInterval = 1000;
private const int TotalTime = 10 * TimerInterval;
private double ProgressValue = 0;
private int ProgressStep = 100 / (TotalTime / TimerInterval);
private Timer Timer { get; set; } = new Timer();
private void Dispose()
{
StopProgress();
Timer?.Close();
}
protected override void OnAfterRender(bool firstRender)
{
if (Timer.Enabled == false)
{
Timer.Interval = TimerInterval;
Timer.Elapsed -= OnTimerElapsed;
Timer.Elapsed += OnTimerElapsed;
Timer.AutoReset = true;
Timer.Start();
}
}
private void OnTimerElapsed(Object source, ElapsedEventArgs e)
{
if (ProgressValue < 100)
{
UpdateProgress();
}
else
{
StopProgress();
}
}
private void UpdateProgress()
{
ProgressValue += ProgressStep;
InvokeAsync(StateHasChanged);
}
private void StopProgress()
{
Timer?.Stop();
}
}
<style>
.progress-info-title {
font-weight: bold;
font-size: 1.4em;
}
</style>
```
* In here, we've just added the `TelerikProgressBar` component to check the integration configured properly.
* When we run `*.HttpApi.Host` and `*.Blazor` projects, we should see that the `TelerikProgressBar` component works and has similar view as the below gif.
![telerik-progress-bar](./telerik-progress-bar.gif)
* If you haven't seen this component like above, you should check the above configurations and be assure every step done as stated.
### Step 3 - Using The Telerik Blazor Components (Sample Application)
* Let's create a sample application for use other Telerik Blazor Components (like DataGrid).
* We will use [jsonplaceholder](https://jsonplaceholder.typicode.com/) as **mock data** to the listing, adding, updating and deleting posts.
* Firstly, we can create a folder named `Posts` and inside this folder, we can create the classes which are highlighted in the following screenshot.
![sample-application](./sample-application.jpg)
* After classes created we can fill the classes with the following contents.
**Post.cs**
```csharp
using System;
namespace TelerikComponents.Posts
{
[Serializable]
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public int UserId { get; set; }
}
}
```
**Comment.cs**
```csharp
using System;
namespace TelerikComponents.Posts
{
[Serializable]
public class Comment
{
public int PostId { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Body { get; set; }
}
}
```
**IPostAppService.cs**
```csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace TelerikComponents.Posts
{
public interface IPostAppService : IApplicationService
{
Task<List<Post>> GetPostsAsync();
Task<Post> AddPostAsync(Post post);
Task<Post> UpdatePostAsync(int postId, Post post);
Task DeletePostAsync(int postId);
Task<Comment> GetFirstCommentByPostIdAsync(int postId);
}
}
```
* In here, we basically created two class (which are **Post** and **Comment**). These classes are used to hold data returned as JSON.
* After that, we need to implement `IPostAppService`. For achieve this, we can create a folder named `Posts` in **\*.Application** layer and inside this folder we can create a class named `PostAppService` with the following content.
**PostAppService.cs**
```csharp
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace TelerikComponents.Posts
{
public class PostAppService : ApplicationService, IPostAppService
{
private JsonSerializerOptions _options = new JsonSerializerOptions
{
IncludeFields = true,
PropertyNameCaseInsensitive = true
};
public async Task<List<Post>> GetPostsAsync()
{
var url = "https://jsonplaceholder.typicode.com/posts";
List<Post> _posts = new List<Post>();
using (var client = new HttpClient())
{
var result = await client.GetAsync(url);
if (result.IsSuccessStatusCode)
{
var content = await result.Content.ReadAsStringAsync();
var deserializedPosts = JsonSerializer.Deserialize<List<Post>>(content, _options);
_posts = deserializedPosts;
}
}
return _posts;
}
public async Task<Post> AddPostAsync(Post post)
{
var url = "https://jsonplaceholder.typicode.com/posts";
Post addedPost = null;
using (var client = new HttpClient())
{
var serializePost = JsonSerializer.Serialize(post);
var content = new StringContent(serializePost, Encoding.UTF8, "application/json");
var result = await client.PostAsync(url, content);
if (result.IsSuccessStatusCode)
{
var response = await result.Content.ReadAsStringAsync();
addedPost = JsonSerializer.Deserialize<Post>(response);
}
}
return addedPost;
}
public async Task<Post> UpdatePostAsync(int postId, Post post)
{
var url = $"https://jsonplaceholder.typicode.com/posts/{postId}";
Post updatedPost = null;
using (var client = new HttpClient())
{
var serializePost = JsonSerializer.Serialize(post);
var content = new StringContent(serializePost, Encoding.UTF8, "application/json");
var result = await client.PutAsync(url, content);
if (result.IsSuccessStatusCode)
{
var response = await result.Content.ReadAsStringAsync();
updatedPost = JsonSerializer.Deserialize<Post>(response);
}
}
return updatedPost;
}
public async Task DeletePostAsync(int postId)
{
var url = $"https://jsonplaceholder.typicode.com/posts/{postId}";
using (var client = new HttpClient())
{
await client.DeleteAsync(url);
}
}
public async Task<Comment> GetFirstCommentByPostIdAsync(int postId)
{
var url = $"https://jsonplaceholder.typicode.com/posts/{postId}/comments";
List<Comment> _comments = new List<Comment>();
using (var client = new HttpClient())
{
var result = await client.GetAsync(url);
if (result.IsSuccessStatusCode)
{
var content = await result.Content.ReadAsStringAsync();
var deserializedPosts = JsonSerializer.Deserialize<List<Comment>>(content, _options);
_comments = deserializedPosts;
}
}
return _comments[0];
}
}
}
```
* In here, we've implemented `IPostAppService` methods by using [jsonplaceholder](https://jsonplaceholder.typicode.co) API. These endpoints provide us basic crud functionallity.
* After the implemenation, we can start to create the user interface.
#### Blazor UI
* We can create **/Posts** page for listing, updating, deleting and creating our posts. So, create a razor page named `Posts.razor` under **Pages** folder in `*.Blazor` project.
**Posts.razor**
```razor
@page "/Posts"
@using TelerikComponents.Posts
@using IconName = Telerik.Blazor.IconName
@inject IPostAppService PostAppService
<h3>Posts</h3>
<TelerikRootComponent>
<TelerikGrid Data="@GridData"
OnUpdate="@UpdateHandler"
OnDelete="@DeleteHandler"
OnCreate="@CreateHandler"
@ref="@Grid"
Pageable="true"
Groupable="true"
Sortable="true"
FilterMode="GridFilterMode.FilterMenu"
Resizable="true"
Reorderable="true"
EditMode="GridEditMode.Popup"
SelectionMode="GridSelectionMode.Single"
PageSize="5"
Navigable="true">
<GridColumns>
<GridColumn Field="@nameof(Post.Title)"/>
<GridColumn Field="@nameof(Post.Body)"/>
<GridCommandColumn Width="190px">
<GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton>
<GridCommandButton Command="Edit" Icon="edit">Edit</GridCommandButton>
<GridCommandButton Command="Delete" Icon="delete" Primary="true">Delete</GridCommandButton>
<GridCommandButton Icon="@IconName.Window" OnClick="(e) => PostDetailAsync(e)">Display Comment</GridCommandButton>
<GridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</GridCommandButton>
</GridCommandColumn>
</GridColumns>
<GridToolBar>
<GridCommandButton Command="Add" Icon="add">Add Post</GridCommandButton>
</GridToolBar>
</TelerikGrid>
@* Modal *@
<TelerikWindow Class="demo-window" Width="500px" Height="250px" Centered="true" @bind-Visible=@ModalVisible Modal="true">
<WindowTitle>
<strong>Comment</strong>
</WindowTitle>
<WindowActions>
<WindowAction Name="Close" />
</WindowActions>
<WindowContent>
<p><b>Email:</b> @Comment.Email</p>
<p>
<b>Message:</b> @Comment.Body
</p>
</WindowContent>
</TelerikWindow>
</TelerikRootComponent>
```
**Post.razor.cs**
```csharp
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Telerik.Blazor.Components;
using TelerikComponents.Posts;
namespace TelerikComponents.Blazor.Pages
{
public partial class Posts
{
private List<Post> GridData { get; set; }
private TelerikGrid<Post> Grid { get; set; }
private bool ModalVisible { get; set; } = false;
private Comment Comment { get; set; }
public Posts()
{
Comment = new Comment();
}
protected override async Task OnInitializedAsync()
{
await LoadDataAsync();
}
private async Task LoadDataAsync()
{
GridData = await PostAppService.GetPostsAsync();
}
private async Task UpdateHandler(GridCommandEventArgs args)
{
var post = (Post) args.Item;
await PostAppService.UpdatePostAsync(post.Id, post);
var matchingPost = GridData.FirstOrDefault(x => x.Id == post.Id);
if (matchingPost != null)
{
matchingPost.Body = post.Body;
matchingPost.Title = post.Title;
}
}
private async Task DeleteHandler(GridCommandEventArgs args)
{
var post = (Post) args.Item;
GridData.Remove(post);
}
private async Task CreateHandler(GridCommandEventArgs args)
{
var post = (Post) args.Item;
var addedPost = await PostAppService.AddPostAsync(post);
GridData.Insert(0, addedPost);
}
private async Task PostDetailAsync(GridCommandEventArgs args)
{
var post = (Post) args.Item;
Comment = await PostAppService.GetFirstCommentByPostIdAsync(post.Id);
ModalVisible = true;
}
}
}
```
* In here, we've used `TelerikGrid` component.
* The `Telerik Grid` is a powerful component, which allows you to visualize and edit data via its table representation. It provides a variety of options about how to present and perform operations over the underlying data, such as paging, sorting, filtering and editing.
* The Blazor UI Grid allows flexible customization of its items exposing rows, columns and edit templates for this purpose.
### Final Result
* After all of these steps, we can finally run our application.
* Run `*.HttpApi.Host` project for use the required endpoints,
* Run `*.Blazor` project for see the Blazor UI.
* When we navigate to `Posts` route, we should see the following screenshot in this page.
![final-result](./final-result.jpg)
## Conclusion
In this article, I've tried to explain how we can integrate [Telerik Blazor Component](https://www.telerik.com/blazor-ui) to our Blazor UI. ABP Framework designed as modular, so that it can work with any UI library/framework.

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/automated-nuget-feed-setup.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/final-result.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/sample-application.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/telerik-blazor-component-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/telerik-progress-bar.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

1581
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/POST.md

File diff suppressed because it is too large

BIN
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/author-crud.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

BIN
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/author-with-books.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

BIN
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-create.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

BIN
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-delete.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-edit.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
docs/en/Community-Articles/2020-12-11-Using-Angular-Material-Components-With-ABP-Framework/book-list.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 KiB

392
docs/en/Module-Entity-Extensions.md

@ -1,3 +1,393 @@
# Module Entity Extensions # Module Entity Extensions
See https://docs.abp.io/en/commercial/latest/guides/module-entity-extensions (it will be moved here soon). ## Introduction
Module entity extension system is a **high level** extension system that allows you to **define new properties** for existing entities of the depended modules. It automatically **adds properties to the entity, database, HTTP API and the user interface** in a single point.
> The module must be developed the *Module Entity Extensions* system in mind. All the **official modules** supports this system wherever possible.
## Quick Example
Open the *YourProjectNameModuleExtensionConfigurator* class inside the `Domain.Shared` project of your solution and change the `ConfigureExtraProperties`method as shown below to add a `SocialSecurityNumber` property to the `IdentityUser` entity of the [Identity Module](Modules/Identity.md).
````csharp
public static void ConfigureExtraProperties()
{
OneTimeRunner.Run(() =>
{
ObjectExtensionManager.Instance.Modules()
.ConfigureIdentity(identity =>
{
identity.ConfigureUser(user =>
{
user.AddOrUpdateProperty<string>( //property type: string
"SocialSecurityNumber", //property name
property =>
{
//validation rules
property.Attributes.Add(new RequiredAttribute());
property.Attributes.Add(
new StringLengthAttribute(64) {
MinimumLength = 4
}
);
//...other configurations for this property
}
);
});
});
});
}
````
>This method is called inside the `YourProjectNameDomainSharedModule` at the beginning of the application. `OneTimeRunner` is a utility class that guarantees to execute this code only one time per application, since multiple calls are unnecessary.
* `ObjectExtensionManager.Instance.Modules()` is the starting point to configure a module. `ConfigureIdentity(...)` method is used to configure the entities of the Identity Module.
* `identity.ConfigureUser(...)` is used to configure the user entity of the identity module. Not all entities are designed to be extensible (since it is not needed). Use the intellisense to discover the extensible modules and entities.
* `user.AddOrUpdateProperty<string>(...)` is used to add a new property to the user entity with the `string` type (`AddOrUpdateProperty` method can be called multiple times for the same property of the same entity. Each call can configure the options of the same property, but only one property is added to the entity with the same property name). You can call this method with different property names to add more properties.
* `SocialSecurityNumber` is the name of the new property.
* `AddOrUpdateProperty` gets a second argument (the `property =>` lambda expression) to configure additional options for the new property.
* We can add data annotation attributes like shown here, just like adding a data annotation attribute to a class property.
#### Create & Update Forms
Once you define a property, it appears in the create and update forms of the related entity:
![add-new-property-to-user-form](images/add-new-property-to-user-form.png)
`SocialSecurityNumber` field comes into the form. Next sections will explain the localization and the validation for this new property.
### Data Table
New properties also appear in the data table of the related page:
![add-new-property-to-user-form](images/add-new-property-to-user-table.png)
`SocialSecurityNumber` column comes into the table. Next sections will explain the option to hide this column from the data table.
## Property Options
There are some options that you can configure while defining a new property.
### Display Name
You probably want to set a different (human readable) display name for the property that is shown on the user interface.
#### Don't Want to Localize?
If your application is not localized, you can directly set the `DisplayName` for the property to a `FixedLocalizableString` object. Example:
````csharp
property =>
{
property.DisplayName = new FixedLocalizableString("Social security no");
}
````
#### Localizing the Display Name
If you want to localize the display name, you have two options.
##### Localize by Convention
Instead of setting the `property.DisplayName`, you can directly open your localization file (like `en.json`) and add the following entry to the `texts` section:
````json
"SocialSecurityNumber": "Social security no"
````
Define the same `SocialSecurityNumber` key (the property name you've defined before) in your localization file for each language you support. That's all!
In some cases, the localization key may conflict with other keys in your localization files. In such cases, you can use the `DisplayName:` prefix for display names in the localization file (`DisplayName:SocialSecurityNumber` as the localization key for this example). Extension system looks for prefixed version first, then fallbacks to the non prefixed name (it then fallbacks to the property name if you haven't localized it).
> This approach is recommended since it is simple and suitable for most scenarios.
##### Localize using the `DisplayName` Property
If you want to specify the localization key or the localization resource, you can still set the `DisplayName` option:
````csharp
property =>
{
property.DisplayName =
LocalizableString.Create<MyProjectNameResource>(
"UserSocialSecurityNumberDisplayName"
);
}
````
* `MyProjectNameResource` is the localization resource and `UserSocialSecurityNumberDisplayName` is the localization key in the localization resource.
> See [the localization document](Localization.md) if you want to learn more about the localization system.
#### Default Value
A default value is automatically set for the new property, which is the natural default value for the property type, like `null` for `string`, `false` for `bool` or `0` for `int`.
There are two ways to override the default value:
##### DefaultValue Option
`DefaultValue` option can be set to any value:
````csharp
property =>
{
property.DefaultValue = 42;
}
````
##### DefaultValueFactory Options
`DefaultValueFactory` can be set to a function that returns the default value:
````csharp
property =>
{
property.DefaultValueFactory = () => DateTime.Now;
}
````
`options.DefaultValueFactory` has a higher priority than the `options.DefaultValue` .
> Tip: Use `DefaultValueFactory` option only if the default value may change over the time (like `DateTime.Now` in this example). If it is a constant value, then use the `DefaultValue` option.
### Validation
Entity extension system allows you to define validation for extension properties in a few ways.
#### Data Annotation Attributes
`Attributes` is a list of attributes associated to this property. The example code below adds two [data annotation validation attributes](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation) to the property:
````csharp
property =>
{
property.Attributes.Add(new RequiredAttribute());
property.Attributes.Add(new StringLengthAttribute(64) {MinimumLength = 4});
}
````
When you run the application, you see that the validation works out of the box:
![add-new-propert-to-user-form](images/add-new-property-to-user-form-validation-error.png)
Since we've added the `RequiredAttribute`, it doesn't allow to left it blank. The validation system works;
* On the user interface (with automatic localization).
* On the HTTP API. Even if you directly perform an HTTP request, you get validation errors with a proper HTTP status code.
* On the `SetProperty(...)` method on the entity (see [the document](Entities.md) if you wonder what is the `SetProperty()` method).
So, it automatically makes a full stack validation.
> See the [ASP.NET Core MVC Validation document](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation) to learn more about the attribute based validation.
##### Default Validation Attributes
There are some attributes **automatically added** when you create certain type of properties;
* `RequiredAttribute` is added for **non nullable** primitive property types (e.g. `int`, `bool`, `DateTime`...) and `enum` types. If you want to allow nulls, make the property nullable (e.g. `int?`).
* `EnumDataTypeAttribute` is added for **enum types**, to prevent to set invalid enum values.
Use `property.Attributes.Clear();` if you don't want these attributes.
#### Validation Actions
Validation actions allows you to execute a custom code to perform the validation. The example below checks if the `SocialSecurityNumber` starts with `B` and adds a validation error if so:
````csharp
property =>
{
property.Attributes.Add(new RequiredAttribute());
property.Attributes.Add(new StringLengthAttribute(64) {MinimumLength = 4});
property.Validators.Add(context =>
{
if (((string) context.Value).StartsWith("B"))
{
context.ValidationErrors.Add(
new ValidationResult(
"Social security number can not start with the letter 'B', sorry!",
new[] {"extraProperties.SocialSecurityNumber"}
)
);
}
});
}
````
Using a `RegularExpressionAttribute` might be better in this case, but this is just an example. Anyway, if you enter a value starts with the letter `B` you get the following error **while saving the form**:
![add-new-propert-to-user-form](images/add-new-property-to-user-form-validation-error-custom.png)
##### The Context Object
The `context` object has useful properties that can be used in your custom validation action. For example, you can use the `context.ServiceProvider` to resolve services from the [dependency injection system](Dependency-Injection.md). The example below gets the localizer and adds a localized error message:
````csharp
if (((string) context.Value).StartsWith("B"))
{
var localizer = context.ServiceProvider
.GetRequiredService<IStringLocalizer<MyProjectNameResource>>();
context.ValidationErrors.Add(
new ValidationResult(
localizer["SocialSecurityNumberCanNotStartWithB"],
new[] {"extraProperties.SocialSecurityNumber"}
)
);
}
````
>`context.ServiceProvider` is nullable! It can be `null` only if you use the `SetProperty(...)` method on the object. Because DI system is not available on this time. While this is a rare case, you should perform a fallback logic when `context.ServiceProvider` is `null`. For this example, you would add a non-localized error message. This is not a problem since setting an invalid value to a property generally is a programmer mistake and you mostly don't need to localization in this case. In any way, you would not be able to use localization even in a regular property setter. But, if you are serious about localization, you can throw a business exception (see the [exception handling document](https://docs.abp.io/en/abp/latest/Exception-Handling) to learn how to localize a business exception).
### UI Visibility
When you define a property, it appears on the data table, create and edit forms on the related UI page. However, you can control each one individually. Example:
````csharp
property =>
{
property.UI.OnTable.IsVisible = false;
//...other configurations
}
````
Use `property.UI.OnCreateForm` and `property.UI.OnEditForm` to control forms too. If a property is required, but not added to the create form, you definitely get a validation exception, so use this option carefully. But a required property may not be in the edit form if that's your requirement.
### HTTP API Availability
Even if you disable a property on UI, it can be still available through the HTTP API. By default, a property is available on all APIs.
Use the `property.Api` options to make a property unavailable in some API endpoints.
````csharp
property =>
{
property.Api.OnUpdate.IsAvailable = false;
}
````
In this example, Update HTTP API will not allow to set a new value to this property. In this case, you also want to disable this property on the edit form:
````csharp
property =>
{
property.Api.OnUpdate.IsAvailable = false;
property.UI.OnEditForm.IsVisible = false;
}
````
In addition to the `property.Api.OnUpdate`, you can set `property.Api.OnCreate` and `property.Api.OnGet` for a fine control the API endpoint.
## Special Types
### Enum
Module extension system naturally supports the `enum` types.
An example enum type:
````csharp
public enum UserType
{
Regular,
Moderator,
SuperUser
}
````
You can add enum properties just like others:
````csharp
user.AddOrUpdateProperty<UserType>("Type");
````
An enum properties is shown as combobox (select) in the create/edit forms:
![add-new-property-enum](images/add-new-property-enum.png)
#### Localization
Enum member name is shown on the table and forms by default. If you want to localize it, just create a new entry on your [localization](https://docs.abp.io/en/abp/latest/Localization) file:
````json
"UserType.SuperUser": "Super user"
````
One of the following names can be used as the localization key:
* `Enum:UserType.SuperUser`
* `UserType.SuperUser`
* `SuperUser`
Localization system searches for the key with the given order. Localized text are used on the table and the create/edit forms.
## Database Mapping
For relational databases, all extension property values are stored in a single field in the table:
![add-new-propert-to-user-database-extra-properties](images/add-new-propert-to-user-database-extra-properties.png)
`ExtraProperties` field stores the properties as a JSON object. While that's fine for some scenarios, you may want to create a dedicated field for your new property. Fortunately, it is very easy to configure.
If you are using the Entity Framework Core database provider, you can configure the database mapping as shown below:
````csharp
ObjectExtensionManager.Instance
.MapEfCoreProperty<IdentityUser, string>(
"SocialSecurityNumber",
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasMaxLength(64);
}
);
````
Write this inside the `YourProjectNameEfCoreEntityExtensionMappings` class in your `.EntityFrameworkCore` project. Then you need to use the standard `Add-Migration` and `Update-Database` commands to create a new database migration and apply the change to your database.
Add-Migration create a new migration as shown below:
````csharp
public partial class Added_SocialSecurityNumber_To_IdentityUser : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "SocialSecurityNumber",
table: "AbpUsers",
maxLength: 128,
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SocialSecurityNumber",
table: "AbpUsers");
}
}
````
Once you update your database, you will see that the `AbpUsers` table has the new property as a standard table field:
![add-new-propert-to-user-database-extra-properties](images/add-new-propert-to-user-database-field.png)
> If you first created a property without a database table field, then you later needed to move this property to a database table field, it is suggested to execute an SQL command in your migration to copy the old values to the new field.
>
> However, if you don't make it, the ABP Framework seamlessly manages it. It uses the new database field, but fallbacks to the `ExtraProperties` field if it is null. When you save the entity, it moves the value to the new field.
See the [Extending Entities](Customizing-Application-Modules-Extending-Entities.md) document for more.
## More
See the [Customizing the Modules](Customizing-Application-Modules-Guide.md) guide for an overall index for all the extensibility options.
Here, a few things you can do:
* You can create a second entity that maps to the same database table with the extra property as a standard class property (if you've defined the EF Core mapping). For the example above, you can add a `public string SocialSecurityNumber {get; set;}` property to the `AppUser` entity in your application, since the `AppUser` entity is mapped to the same `AbpUser` table. Do this only if you need it, since it brings more complexity to your application.
* You can override a domain or application service to perform custom logics with your new property.
* You can low level control how to add/render a field in the data table on the UI.

2
docs/en/Modules/Identity.md

@ -1,6 +1,6 @@
# Identity Management Module # Identity Management Module
Identity module is used to manage [organization units](Organization-Units.md), roles, users and their permissions, based on the Microsoft Identity library. Identity module is used to manage organization units, roles, users and their permissions, based on the Microsoft Identity library.
> **See [the source code](https://github.com/abpframework/abp/tree/dev/modules/identity). Documentation will come soon...** > **See [the source code](https://github.com/abpframework/abp/tree/dev/modules/identity). Documentation will come soon...**

3
docs/en/Tutorials/Part-3.md

@ -1386,7 +1386,7 @@ Open the `Books.razor` page and add the following `EntityAction` under the "Edit
<EntityAction TItem="BookDto" <EntityAction TItem="BookDto"
Text="@L["Delete"]" Text="@L["Delete"]"
Clicked="() => DeleteEntityAsync(context)" Clicked="() => DeleteEntityAsync(context)"
ConfirmationMessage="@() => GetDeleteConfirmationMessage(context)" /> ConfirmationMessage="() => GetDeleteConfirmationMessage(context)" />
```` ````
* `DeleteEntityAsync` is defined in the base class that deletes the entity by performing a call to the server. * `DeleteEntityAsync` is defined in the base class that deletes the entity by performing a call to the server.
@ -1429,6 +1429,7 @@ Here the complete code to create the book management CRUD page, that has been de
<DataGrid TItem="BookDto" <DataGrid TItem="BookDto"
Data="Entities" Data="Entities"
ReadData="OnDataGridReadAsync" ReadData="OnDataGridReadAsync"
CurrentPage="CurrentPage"
TotalItems="TotalCount" TotalItems="TotalCount"
ShowPager="true" ShowPager="true"
PageSize="PageSize"> PageSize="PageSize">

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

@ -53,7 +53,7 @@ This part covers the **server side** tests. There are several test projects in t
Each project is used to test the related project. Test projects use the following libraries for testing: Each project is used to test the related project. Test projects use the following libraries for testing:
* [Xunit](https://xunit.github.io/) as the main test framework. * [Xunit](https://xunit.github.io/) as the main test framework.
* [Shoudly](http://shouldly.readthedocs.io/en/latest/) as the assertion library. * [Shoudly](https://github.com/shouldly/shouldly) as the assertion library.
* [NSubstitute](http://nsubstitute.github.io/) as the mocking library. * [NSubstitute](http://nsubstitute.github.io/) as the mocking library.
{{if DB=="EF"}} {{if DB=="EF"}}

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

@ -150,7 +150,7 @@ namespace Acme.BookStore.Authors
} }
```` ````
* Inherited from the `EfCoreAuthorRepository`, so it inherits the standard repository method implementations. * Inherited from the `EfCoreRepository`, so it inherits the standard repository method implementations.
* `WhereIf` is a shortcut extension method of the ABP Framework. It adds the `Where` condition only if the first condition meets (it filters by name, only if the filter was provided). You could do the same yourself, but these type of shortcut methods makes our life easier. * `WhereIf` is a shortcut extension method of the ABP Framework. It adds the `Where` condition only if the first condition meets (it filters by name, only if the filter was provided). You could do the same yourself, but these type of shortcut methods makes our life easier.
* `sorting` can be a string like `Name`, `Name ASC` or `Name DESC`. It is possible by using the [System.Linq.Dynamic.Core](https://www.nuget.org/packages/System.Linq.Dynamic.Core) NuGet package. * `sorting` can be a string like `Name`, `Name ASC` or `Name DESC`. It is possible by using the [System.Linq.Dynamic.Core](https://www.nuget.org/packages/System.Linq.Dynamic.Core) NuGet package.
@ -211,7 +211,7 @@ namespace Acme.BookStore.Authors
} }
``` ```
* Inherited from the `MongoDbAuthorRepository`, so it inherits the standard repository method implementations. * Inherited from the `MongoDbRepository`, so it inherits the standard repository method implementations.
* `WhereIf` is a shortcut extension method of the ABP Framework. It adds the `Where` condition only if the first condition meets (it filters by name, only if the filter was provided). You could do the same yourself, but these type of shortcut methods makes our life easier. * `WhereIf` is a shortcut extension method of the ABP Framework. It adds the `Where` condition only if the first condition meets (it filters by name, only if the filter was provided). You could do the same yourself, but these type of shortcut methods makes our life easier.
* `sorting` can be a string like `Name`, `Name ASC` or `Name DESC`. It is possible by using the [System.Linq.Dynamic.Core](https://www.nuget.org/packages/System.Linq.Dynamic.Core) NuGet package. * `sorting` can be a string like `Name`, `Name ASC` or `Name DESC`. It is possible by using the [System.Linq.Dynamic.Core](https://www.nuget.org/packages/System.Linq.Dynamic.Core) NuGet package.
@ -221,4 +221,4 @@ namespace Acme.BookStore.Authors
## The Next Part ## The Next Part
See the [next part](Part-8.md) of this tutorial. See the [next part](Part-8.md) of this tutorial.

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

@ -1188,4 +1188,4 @@ That's all! This is a fully working CRUD page, you can create, edit and delete t
## The Next Part ## The Next Part
See the [next part](Part-10.md) of this tutorial. See the [next part](Part-10.md) of this tutorial.

44
docs/en/UI/Angular/List-Service.md

@ -68,6 +68,50 @@ Bind `ListService` to ngx-datatable like this:
</ngx-datatable> </ngx-datatable>
``` ```
## Extending query with custom variables
You can extend the query parameter of the `ListService`'s `hookToQuery` method.
Firstly, you should pass your own type to `ListService` as shown below:
```typescript
constructor(public readonly list: ListService<BooksSearchParamsDto>) { }
```
Then update the `bookStreamCreator` constant like following:
```typescript
const bookStreamCreator = (query) => this.bookService.getList({...query, name: 'name here'});
```
You can also create your params object.
Define a variable like this:
```typescript
booksSearchParams = {} as BooksSearchParamsDto;
```
Update the `bookStreamCreator` constant:
```typescript
const bookStreamCreator = (query) => this.bookService.getList({...query, ...this.booksSearchParams});
```
Then you can place inputs to the HTML:
```html
<div class="form-group">
<input
class="form control"
placeholder="Name"
(keyup.enter)="list.get()"
[(ngModel)]="booksSearchParams.name"
/>
</div>
```
`ListService` emits the hookToQuery stream when you call the `this.list.get()` method.
## Usage with Observables ## Usage with Observables

161
docs/en/UI/AspNetCore/Data-Table-Column-Extensions.md

@ -0,0 +1,161 @@
# Data Table Column Extensions for ASP.NET Core UI
## Introduction
Data table column extension system allows you to add a **new table column** on the user interface. The example below adds a new column with the "Social security no" title:
![user-action-extension-click-me](../../images/table-column-extension-example.png)
You can use the standard column options to fine control the table column.
> Note that this is a low level API to find control the table column. If you want to show an extension property on the table, see the [module entity extension](../../Module-Entity-Extensions.md) document.
## How to Set Up
### Create a JavaScript File
First, add a new JavaScript file to your solution. We added inside the `/Pages/Identity/Users` folder of the `.Web` project:
![user-action-extension-on-solution](../../images/user-action-extension-on-solution.png)
Here, the content of this JavaScript file:
```js
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
columnList.addTail({ //add as the last column
title: 'Social security no',
data: 'extraProperties.SocialSecurityNumber',
orderable: false,
render: function (data, type, row) {
if (row.extraProperties.SocialSecurityNumber) {
return '<strong>' +
row.extraProperties.SocialSecurityNumber +
'<strong>';
} else {
return '<i class="text-muted">undefined</i>';
}
}
});
});
```
This example defines a custom `render` function to return a custom HTML to render in the column.
### Add the File to the User Management Page
Then you need to add this JavaScript file to the user management page. You can take the power of the [Bundling & Minification system](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification).
Write the following code inside the `ConfigureServices` of your module class:
```csharp
Configure<AbpBundlingOptions>(options =>
{
options.ScriptBundles.Configure(
typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName,
bundleConfiguration =>
{
bundleConfiguration.AddFiles(
"/Pages/Identity/Users/my-user-extensions.js"
);
});
});
```
This configuration adds `my-user-extensions.js` to the user management page of the Identity Module. `typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName` is the name of the bundle in the user management page. This is a common convention used for all the ABP Commercial modules.
### Rendering the Column
This example assumes that you've defined a `SocialSecurityNumber` extra property using the [module entity extension](../../Module-Entity-Extensions.md) system. However;
* You can add a new column that is related to an existing property of the user (that was not added to the table by default). Example:
````js
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
columnList.addTail({
title: 'Phone confirmed?',
data: 'phoneNumberConfirmed',
render: function (data, type, row) {
if (row.phoneNumberConfirmed) {
return '<strong style="color: green">YES<strong>';
} else {
return '<i class="text-muted">NO</i>';
}
}
});
});
````
* You can add a new custom column that is not related to any entity property, but a completely custom information. Example:
````js
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
columnList.addTail({
title: 'Custom column',
data: {},
orderable: false,
render: function (data) {
if (data.phoneNumber) {
return "call: " + data.phoneNumber;
} else {
return '';
}
}
});
});
````
## API
This section explains details of the `abp.ui.extensions.tableColumns` JavaScript API.
### abp.ui.extensions.tableColumns.get(entityName)
This method is used to access the table columns for an entity of a specific module. It takes one parameter:
* **entityName**: The name of the entity defined by the related module.
### abp.ui.extensions.tableColumns.get(entityName).columns
The `columns` property is used to retrieve a [doubly linked list](../Common/Utils/Linked-List.md) of previously defined columns for a table. All contributors are executed in order to prepare the final column list. This is normally called by the modules to show the columns in the table. However, you can use it if you are building your own extensible UIs.
### abp.ui.extensions.tableColumns.get(entityName).addContributor(contributeCallback [, order])
The `addContributor` method covers all scenarios, e.g. you want to add your column in a different position in the list, change or remove an existing column. `addContributor` has the following parameters:
* **contributeCallback**: A callback function that is called whenever the column list should be created. You can freely modify the column list inside this callback method.
* **order** (optional): The order of the callback in the callback list. Your callback is added to the end of the list (so, you have opportunity to modify columns added by the previous contributors). You can set it `0` to add your contributor as the first item.
#### Example
```js
var myColumnDefinition = {
title: 'Custom column',
data: {},
orderable: false,
render: function(data) {
if (data.phoneNumber) {
return "call: " + data.phoneNumber;
} else {
return '';
}
}
};
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
// Remove an item from actionList
columnList.dropHead();
// Add a new item to the actionList
columnList.addHead(myColumnDefinition);
});
```
> `columnList` is [linked list](../Common/Utils/Linked-List.md). You can use its methods to build a list of columns however you need.

108
docs/en/UI/AspNetCore/Entity-Action-Extensions.md

@ -0,0 +1,108 @@
# Entity Action Extensions for ASP.NET Core UI
## Introduction
Entity action extension system allows you to add a **new action** to the action menu for an entity. A **Click Me** action was added to the *User Management* page below:
![user-action-extension-click-me](../../images/user-action-extension-click-me.png)
You can take any action (open a modal, make an HTTP API call, redirect to another page... etc) by writing your custom code. You can access to the current entity in your code.
## How to Set Up
In this example, we will add a "Click Me!" action and execute a JavaScript code for the user management page of the [Identity Module](../../Modules/Identity.md).
### Create a JavaScript File
First, add a new JavaScript file to your solution. We added inside the `/Pages/Identity/Users` folder of the `.Web` project:
![user-action-extension-on-solution](../../images/user-action-extension-on-solution.png)
Here, the content of this JavaScript file:
```js
var clickMeAction = {
text: 'Click Me!',
action: function(data) {
//TODO: Write your custom code
alert(data.record.userName);
}
};
abp.ui.extensions.entityActions
.get('identity.user')
.addContributor(function(actionList) {
actionList.addTail(clickMeAction);
});
```
In the `action` function, you can do anything you need. See the API section for a detailed usage.
### Add the File to the User Management Page
Then you need to add this JavaScript file to the user management page. You can take the power of the [Bundling & Minification System](Bundling-Minification.md).
Write the following code inside the `ConfigureServices` of your module class:
```csharp
Configure<AbpBundlingOptions>(options =>
{
options.ScriptBundles.Configure(
typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName,
bundleConfiguration =>
{
bundleConfiguration.AddFiles(
"/Pages/Identity/Users/my-user-extensions.js"
);
});
});
```
This configuration adds `my-user-extensions.js` to the user management page of the Identity Module. `typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName` is the name of the bundle in the user management page. This is a common convention used for all the ABP Commercial modules.
That's all. Run your application to see the result.
## API
This section explains details of the `abp.ui.extensions.entityActions` JavaScript API.
### abp.ui.extensions.entityActions.get(entityName)
This method is used to access the entity actions of a specific module. It takes one parameter:
* **entityName**: The name of the entity defined by the related module.
### abp.ui.extensions.entityActions.get(entityName).actions
The `actions` property is used to retrieve a [doubly linked list](../Common/Utils/Linked-List.md) of previously defined actions for an entity. All contributors are executed in order to prepare the final actions list. This is normally called by the modules to show the actions in the grid. However, you can use it if you are building your own extensible UIs.
### abp.ui.extensions.entityActions.get(entityName).addContributor(contributeCallback)
The `addContributor` method covers all scenarios, e.g. you want to add your action in a different position in the list, change or remove an existing action item. `addContributor` with the following parameter:
* **contributeCallback**: A callback function that is called whenever the action list should be created. You can freely modify the action list inside this callback method.
#### Example
```js
var clickMe2Action = {
text: 'Click Me 2!',
icon: 'fas fa-hand-point-right',
action: function(data) {
//TODO: Write your custom code
alert(data.record.userName);
}
};
abp.ui.extensions.entityActions
.get('identity.user')
.addContributor(function(actionList) {
// Remove an item from actionList
actionList.dropHead();
// Add the new item to the actionList
actionList.addHead(clickMe2Action);
});
```
> `actionList` is [linked list](../Common/Utils/Linked-List.md). You can use its methods to build a list of columns however you need.

2
docs/en/UI/AspNetCore/Theming.md

@ -32,7 +32,7 @@ All the themes must depend on the [@abp/aspnetcore.mvc.ui.theme.shared](https://
* [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. * [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework.
* [JQuery](https://jquery.com/) for DOM manipulation. * [JQuery](https://jquery.com/) for DOM manipulation.
* [DataTables.Net](https://datatables.net/) for data grids. * [DataTables.Net](https://datatables.net/) for data grids.
* [JQuery Validation](https://jqueryvalidation.org/) for client side & [unobtrusive](https://github.com/aspnet/jquery-validation-unobtrusive) validation * [JQuery Validation](https://github.com/jquery-validation/jquery-validation) for client side & [unobtrusive](https://github.com/aspnet/jquery-validation-unobtrusive) validation
* [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. * [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library.
* [SweetAlert](https://sweetalert.js.org/) to show fancy alert message and confirmation dialogs. * [SweetAlert](https://sweetalert.js.org/) to show fancy alert message and confirmation dialogs.
* [Toastr](https://github.com/CodeSeven/toastr) to show toast notifications. * [Toastr](https://github.com/CodeSeven/toastr) to show toast notifications.

3
docs/en/UI/Blazor/Testing.md

@ -0,0 +1,3 @@
# Blazor: Testing
Coming soon.

BIN
docs/en/images/add-new-propert-to-user-database-extra-properties.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/en/images/add-new-propert-to-user-database-field.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
docs/en/images/add-new-property-enum.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/images/add-new-property-to-user-form-validation-error-custom.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
docs/en/images/add-new-property-to-user-form-validation-error.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/images/add-new-property-to-user-form.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
docs/en/images/add-new-property-to-user-table.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
docs/en/images/table-column-extension-example.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/en/images/user-action-extension-click-me.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
docs/en/images/user-action-extension-on-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs

@ -86,12 +86,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{ {
selectTagHelper.Items = GetSelectItems(context, output); selectTagHelper.Items = GetSelectItems(context, output);
} }
else else if(!TagHelper.AutocompleteSelectedItemName.IsNullOrEmpty())
{ {
selectTagHelper.Items = new SelectListItem[] selectTagHelper.Items = new[]
{ {
new SelectListItem(TagHelper.AutocompleteSelectedItemName,TagHelper.AutocompleteSelectedItemValue,true) new SelectListItem(TagHelper.AutocompleteSelectedItemName,
}; TagHelper.AutocompleteSelectedItemValue, false)
};
} }
var selectTagHelperOutput = await selectTagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag); var selectTagHelperOutput = await selectTagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "select", TagMode.StartTagAndEndTag);

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/tenant-switch.js

@ -9,7 +9,7 @@
}); });
tenantSwitchModal.onResult(function() { tenantSwitchModal.onResult(function() {
location.reload(); location.assign(location.href);
}); });
}); });

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/CmsKit/CmsKitScriptContributor.cs

@ -0,0 +1,11 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.StarRatingSvg;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.CmsKit
{
[DependsOn(typeof(StarRatingSvgScriptContributor))]
public class CmsKitScriptContributor : BundleContributor
{
}
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/CmsKit/CmsKitStyleContributor.cs

@ -0,0 +1,11 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.StarRatingSvg;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.CmsKit
{
[DependsOn(typeof(StarRatingSvgStyleContributor))]
public class CmsKitStyleContributor : BundleContributor
{
}
}

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NUglify" Version="1.6.3" /> <PackageReference Include="NUglify" Version="1.11.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/StandardLayouts.cs

@ -4,6 +4,7 @@
{ {
public const string Application = "Application"; public const string Application = "Application";
public const string Account = "Account"; public const string Account = "Account";
public const string Public = "Public";
public const string Empty = "Empty"; public const string Empty = "Empty";
} }
} }

7
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/ThemeExtensions.cs

@ -12,9 +12,14 @@
return theme.GetLayout(StandardLayouts.Account, fallbackToDefault); return theme.GetLayout(StandardLayouts.Account, fallbackToDefault);
} }
public static string GetPublicLayout(this ITheme theme, bool fallbackToDefault = true)
{
return theme.GetLayout(StandardLayouts.Public, fallbackToDefault);
}
public static string GetEmptyLayout(this ITheme theme, bool fallbackToDefault = true) public static string GetEmptyLayout(this ITheme theme, bool fallbackToDefault = true)
{ {
return theme.GetLayout(StandardLayouts.Empty, fallbackToDefault); return theme.GetLayout(StandardLayouts.Empty, fallbackToDefault);
} }
} }
} }

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

@ -29,7 +29,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.1.1" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.2.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

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

@ -21,7 +21,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="10.0.0" /> <PackageReference Include="AutoMapper" Version="10.1.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

3
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs

@ -27,6 +27,7 @@ using System;
using System.Reflection; using System.Reflection;
using Autofac.Builder; using Autofac.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Autofac.Extensions.DependencyInjection namespace Autofac.Extensions.DependencyInjection
@ -116,6 +117,7 @@ namespace Autofac.Extensions.DependencyInjection
.RegisterGeneric(service.ImplementationType) .RegisterGeneric(service.ImplementationType)
.As(service.ServiceType) .As(service.ServiceType)
.ConfigureLifecycle(service.Lifetime) .ConfigureLifecycle(service.Lifetime)
.FindConstructorsWith(new AbpAutofacConstructorFinder())
.ConfigureAbpConventions(moduleContainer, registrationActionList); .ConfigureAbpConventions(moduleContainer, registrationActionList);
} }
else else
@ -124,6 +126,7 @@ namespace Autofac.Extensions.DependencyInjection
.RegisterType(service.ImplementationType) .RegisterType(service.ImplementationType)
.As(service.ServiceType) .As(service.ServiceType)
.ConfigureLifecycle(service.Lifetime) .ConfigureLifecycle(service.Lifetime)
.FindConstructorsWith(new AbpAutofacConstructorFinder())
.ConfigureAbpConventions(moduleContainer, registrationActionList); .ConfigureAbpConventions(moduleContainer, registrationActionList);
} }
} }

4
framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj

@ -15,8 +15,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="5.0.0" /> <PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
<PackageReference Include="Autofac" Version="5.2.0" /> <PackageReference Include="Autofac" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(MicrosoftPackageVersion)" />
</ItemGroup> </ItemGroup>

43
framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpAutofacConstructorFinder.cs

@ -0,0 +1,43 @@
using System;
using System.Collections.Concurrent;
using System.Reflection;
using Autofac.Core.Activators.Reflection;
namespace Volo.Abp.Autofac
{
public class AbpAutofacConstructorFinder : IConstructorFinder
{
private const BindingFlags DeclaredOnlyPublicFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; //Remove static constructor, BindingFlags.Static
private readonly Func<Type, ConstructorInfo[]> _finder;
private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> DefaultPublicConstructorsCache = new ConcurrentDictionary<Type, ConstructorInfo[]>();
public AbpAutofacConstructorFinder()
: this(GetDefaultPublicConstructors)
{
}
public AbpAutofacConstructorFinder(Func<Type, ConstructorInfo[]> finder)
{
_finder = finder ?? throw new ArgumentNullException(nameof(finder));
}
public ConstructorInfo[] FindConstructors(Type targetType)
{
return _finder(targetType);
}
private static ConstructorInfo[] GetDefaultPublicConstructors(Type type)
{
var retval = DefaultPublicConstructorsCache.GetOrAdd(type, t => t.GetConstructors(DeclaredOnlyPublicFlags));
if (retval.Length == 0)
{
throw new NoConstructorsFoundException(type);
}
return retval;
}
}
}

15
framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs

@ -176,7 +176,7 @@ namespace Volo.Abp.BlazoriseUI
protected virtual int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount; protected virtual int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount;
protected int CurrentPage; protected int CurrentPage = 1;
protected string CurrentSorting; protected string CurrentSorting;
protected int? TotalCount; protected int? TotalCount;
protected TGetListInput GetListInput = new TGetListInput(); protected TGetListInput GetListInput = new TGetListInput();
@ -259,7 +259,7 @@ namespace Volo.Abp.BlazoriseUI
if (GetListInput is IPagedResultRequest pagedResultRequestInput) if (GetListInput is IPagedResultRequest pagedResultRequestInput)
{ {
pagedResultRequestInput.SkipCount = CurrentPage * PageSize; pagedResultRequestInput.SkipCount = (CurrentPage - 1) * PageSize;
} }
if (GetListInput is ILimitedResultRequest limitedResultRequestInput) if (GetListInput is ILimitedResultRequest limitedResultRequestInput)
@ -270,13 +270,22 @@ namespace Volo.Abp.BlazoriseUI
return Task.CompletedTask; return Task.CompletedTask;
} }
protected virtual async Task SearchEntitiesAsync()
{
CurrentPage = 1;
await GetEntitiesAsync();
StateHasChanged();
}
protected virtual async Task OnDataGridReadAsync(DataGridReadDataEventArgs<TListViewModel> e) protected virtual async Task OnDataGridReadAsync(DataGridReadDataEventArgs<TListViewModel> e)
{ {
CurrentSorting = e.Columns CurrentSorting = e.Columns
.Where(c => c.Direction != SortDirection.None) .Where(c => c.Direction != SortDirection.None)
.Select(c => c.Field + (c.Direction == SortDirection.Descending ? " DESC" : "")) .Select(c => c.Field + (c.Direction == SortDirection.Descending ? " DESC" : ""))
.JoinAsString(","); .JoinAsString(",");
CurrentPage = e.Page - 1; CurrentPage = e.Page;
await GetEntitiesAsync(); await GetEntitiesAsync();

10
framework/src/Volo.Abp.BlazoriseUI/Components/SubmitButton.razor

@ -0,0 +1,10 @@
<Button form="@Form" Type="@Type" Color="@Color" Block="@Block" PreventDefaultOnSubmit="@PreventDefaultOnSubmit" Disabled="@IsDisabled" Loading="@IsLoading" Clicked="@OnClickedHandler">
@if ( ChildContent != null )
{
@ChildContent
}
else
{
@SaveString
}
</Button>

73
framework/src/Volo.Abp.BlazoriseUI/Components/SubmitButton.razor.cs

@ -0,0 +1,73 @@
using System;
using System.Threading.Tasks;
using Blazorise;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
namespace Volo.Abp.BlazoriseUI.Components
{
public partial class SubmitButton : ComponentBase
{
protected bool Submiting { get; set; }
[Parameter]
public string Form { get; set; }
[Parameter]
public ButtonType Type { get; set; } = ButtonType.Submit;
[Parameter]
public Color Color { get; set; } = Color.Primary;
[Parameter]
public bool PreventDefaultOnSubmit { get; set; } = true;
[Parameter]
public bool Block { get; set; }
[Parameter]
public bool? Disabled { get; set; }
[Parameter]
public string SaveResourceKey { get; set; } = "Save";
[Parameter]
public EventCallback Clicked { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Inject]
protected IStringLocalizer<AbpUiResource> StringLocalizer { get; set; }
protected bool IsDisabled
=> Disabled == true || Submiting;
protected bool IsLoading
=> Submiting;
protected string SaveString
=> StringLocalizer[SaveResourceKey];
protected virtual async Task OnClickedHandler()
{
try
{
Submiting = true;
await Clicked.InvokeAsync(null);
}
catch (Exception)
{
throw;
}
finally
{
Submiting = false;
await InvokeAsync(StateHasChanged);
}
}
}
}

2
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.csproj

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="aliyun-net-sdk-sts" Version="3.0.4" /> <PackageReference Include="aliyun-net-sdk-sts" Version="3.0.4" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.10.0" /> <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.12.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

4
framework/src/Volo.Abp.BlobStoring.Aws/Volo.Abp.BlobStoring.Aws.csproj

@ -17,8 +17,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AWSSDK.S3" Version="3.3.111.27" /> <PackageReference Include="AWSSDK.S3" Version="3.5.6.1" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.3.105.30" /> <PackageReference Include="AWSSDK.SecurityToken" Version="3.5.1.25" />
</ItemGroup> </ItemGroup>
</Project> </Project>

2
framework/src/Volo.Abp.BlobStoring.Azure/Volo.Abp.BlobStoring.Azure.csproj

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" /> <ProjectReference Include="..\Volo.Abp.BlobStoring\Volo.Abp.BlobStoring.csproj" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.4.4" /> <PackageReference Include="Azure.Storage.Blobs" Version="12.7.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

8
framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj

@ -15,10 +15,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.2.0" /> <PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="NuGet.Versioning" Version="5.6.0" /> <PackageReference Include="NuGet.Versioning" Version="5.8.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="System.Security.Permissions" Version="4.7.0" /> <PackageReference Include="System.Security.Permissions" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
<PackageReference Include="Polly" Version="7.2.1" /> <PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="Polly.Extensions.Http" Version="3.0.0" /> <PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageReference Include="LibGit2Sharp" Version="0.26.2" /> <PackageReference Include="LibGit2Sharp" Version="0.26.2" />

5
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Module/ModuleTemplateBase.cs

@ -39,6 +39,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Module
"MyCompanyName.MyProjectName.Blazor" "MyCompanyName.MyProjectName.Blazor"
)); ));
steps.Add(new RemoveProjectFromSolutionStep(
"MyCompanyName.MyProjectName.Blazor.Host",
projectFolderPath: "/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Host"
));
steps.Add(new RemoveProjectFromSolutionStep( steps.Add(new RemoveProjectFromSolutionStep(
"MyCompanyName.MyProjectName.Web.Host", "MyCompanyName.MyProjectName.Web.Host",
projectFolderPath: "/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host" projectFolderPath: "/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host"

28
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs

@ -7,6 +7,8 @@ using System.Threading.Tasks;
using System.Xml; using System.Xml;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http; using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.Cli.Utils; using Volo.Abp.Cli.Utils;
@ -25,19 +27,22 @@ namespace Volo.Abp.Cli.ProjectModification
protected DerivedClassFinder ModuleClassFinder { get; } protected DerivedClassFinder ModuleClassFinder { get; }
protected ModuleClassDependcyAdder ModuleClassDependcyAdder { get; } protected ModuleClassDependcyAdder ModuleClassDependcyAdder { get; }
protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; }
public BundleCommand BundleCommand { get; }
public ProjectNugetPackageAdder( public ProjectNugetPackageAdder(
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
ProjectNpmPackageAdder npmPackageAdder, ProjectNpmPackageAdder npmPackageAdder,
DerivedClassFinder moduleClassFinder, DerivedClassFinder moduleClassFinder,
ModuleClassDependcyAdder moduleClassDependcyAdder, ModuleClassDependcyAdder moduleClassDependcyAdder,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler) IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
BundleCommand bundleCommand)
{ {
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
NpmPackageAdder = npmPackageAdder; NpmPackageAdder = npmPackageAdder;
ModuleClassFinder = moduleClassFinder; ModuleClassFinder = moduleClassFinder;
ModuleClassDependcyAdder = moduleClassDependcyAdder; ModuleClassDependcyAdder = moduleClassDependcyAdder;
RemoteServiceExceptionHandler = remoteServiceExceptionHandler; RemoteServiceExceptionHandler = remoteServiceExceptionHandler;
BundleCommand = bundleCommand;
Logger = NullLogger<ProjectNugetPackageAdder>.Instance; Logger = NullLogger<ProjectNugetPackageAdder>.Instance;
} }
@ -50,14 +55,14 @@ namespace Volo.Abp.Cli.ProjectModification
); );
} }
public Task AddAsync(string projectFile, NugetPackageInfo package, string version = null, public async Task AddAsync(string projectFile, NugetPackageInfo package, string version = null,
bool useDotnetCliToInstall = true) bool useDotnetCliToInstall = true)
{ {
var projectFileContent = File.ReadAllText(projectFile); var projectFileContent = File.ReadAllText(projectFile);
if (projectFileContent.Contains($"\"{package.Name}\"")) if (projectFileContent.Contains($"\"{package.Name}\""))
{ {
return Task.CompletedTask; return;
} }
if (version == null) if (version == null)
@ -94,11 +99,14 @@ namespace Volo.Abp.Cli.ProjectModification
} }
ModuleClassDependcyAdder.Add(moduleFiles.First(), package.ModuleClass); ModuleClassDependcyAdder.Add(moduleFiles.First(), package.ModuleClass);
}
Logger.LogInformation("Successfully installed."); if (package.Target == NuGetPackageTarget.Blazor)
{
await RunBundleForBlazorAsync(projectFile);
} }
return Task.CompletedTask; Logger.LogInformation("Successfully installed.");
} }
private Task AddUsingDotnetCli(NugetPackageInfo package, string version = null) private Task AddUsingDotnetCli(NugetPackageInfo package, string version = null)
@ -185,5 +193,15 @@ namespace Volo.Abp.Cli.ProjectModification
return JsonSerializer.Deserialize<NugetPackageInfo>(responseContent); return JsonSerializer.Deserialize<NugetPackageInfo>(responseContent);
} }
} }
protected virtual async Task RunBundleForBlazorAsync(string projectFile)
{
var args = new CommandLineArgs("bundle");
args.Options.Add(BundleCommand.Options.WorkingDirectory.Short, Path.GetDirectoryName(projectFile));
args.Options.Add(BundleCommand.Options.ForceBuild.Short, string.Empty);
await BundleCommand.ExecuteAsync(args);
}
} }
} }

118
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -7,6 +7,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Bundling;
using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Commands.Services; using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.Http; using Volo.Abp.Cli.Http;
@ -35,6 +36,7 @@ namespace Volo.Abp.Cli.ProjectModification
public NugetPackageToLocalReferenceConverter NugetPackageToLocalReferenceConverter { get; } public NugetPackageToLocalReferenceConverter NugetPackageToLocalReferenceConverter { get; }
public AngularModuleSourceCodeAdder AngularModuleSourceCodeAdder { get; } public AngularModuleSourceCodeAdder AngularModuleSourceCodeAdder { get; }
public NewCommand NewCommand { get; } public NewCommand NewCommand { get; }
public BundleCommand BundleCommand { get; }
public SolutionModuleAdder( public SolutionModuleAdder(
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
@ -49,7 +51,8 @@ namespace Volo.Abp.Cli.ProjectModification
SolutionFileModifier solutionFileModifier, SolutionFileModifier solutionFileModifier,
NugetPackageToLocalReferenceConverter nugetPackageToLocalReferenceConverter, NugetPackageToLocalReferenceConverter nugetPackageToLocalReferenceConverter,
AngularModuleSourceCodeAdder angularModuleSourceCodeAdder, AngularModuleSourceCodeAdder angularModuleSourceCodeAdder,
NewCommand newCommand) NewCommand newCommand,
BundleCommand bundleCommand)
{ {
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
ProjectNugetPackageAdder = projectNugetPackageAdder; ProjectNugetPackageAdder = projectNugetPackageAdder;
@ -64,6 +67,7 @@ namespace Volo.Abp.Cli.ProjectModification
NugetPackageToLocalReferenceConverter = nugetPackageToLocalReferenceConverter; NugetPackageToLocalReferenceConverter = nugetPackageToLocalReferenceConverter;
AngularModuleSourceCodeAdder = angularModuleSourceCodeAdder; AngularModuleSourceCodeAdder = angularModuleSourceCodeAdder;
NewCommand = newCommand; NewCommand = newCommand;
BundleCommand = bundleCommand;
Logger = NullLogger<SolutionModuleAdder>.Instance; Logger = NullLogger<SolutionModuleAdder>.Instance;
} }
@ -118,15 +122,33 @@ namespace Volo.Abp.Cli.ProjectModification
await AddAngularPackages(solutionFile, module); await AddAngularPackages(solutionFile, module);
} }
await RunBundleForBlazorAsync(projectFiles, module);
ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations); ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations);
} }
private async Task RunBundleForBlazorAsync(string[] projectFiles, ModuleWithMastersInfo module)
{
var blazorProject = projectFiles.FirstOrDefault(f => f.EndsWith(".Blazor.csproj"));
if (blazorProject == null || !module.NugetPackages.Any(np=> np.Target == NuGetPackageTarget.Blazor))
{
return;
}
var args = new CommandLineArgs("bundle");
args.Options.Add(BundleCommand.Options.WorkingDirectory.Short, Path.GetDirectoryName(blazorProject));
args.Options.Add(BundleCommand.Options.ForceBuild.Short, string.Empty);
await BundleCommand.ExecuteAsync(args);
}
private async Task RemoveUnnecessaryProjectsAsync(string solutionDirectory, ModuleWithMastersInfo module, private async Task RemoveUnnecessaryProjectsAsync(string solutionDirectory, ModuleWithMastersInfo module,
string[] projectFiles) string[] projectFiles)
{ {
var moduleDirectory = Path.Combine(solutionDirectory, "modules", module.Name); var moduleDirectory = Path.Combine(solutionDirectory, "modules", module.Name);
var moduleSolutionFile = var moduleSolutionFile = Directory.GetFiles(moduleDirectory, "*.sln", SearchOption.TopDirectoryOnly).First();
Directory.GetFiles(moduleDirectory, "*.sln", SearchOption.TopDirectoryOnly).First();
var isProjectTiered = await IsProjectTiered(projectFiles); var isProjectTiered = await IsProjectTiered(projectFiles);
if (!projectFiles.Any(p => p.EndsWith(".Blazor.csproj"))) if (!projectFiles.Any(p => p.EndsWith(".Blazor.csproj")))
@ -149,6 +171,7 @@ namespace Volo.Abp.Cli.ProjectModification
{ {
await RemoveProjectByTarget(module, moduleSolutionFile, NuGetPackageTarget.EntityFrameworkCore, isProjectTiered); await RemoveProjectByTarget(module, moduleSolutionFile, NuGetPackageTarget.EntityFrameworkCore, isProjectTiered);
await RemoveProjectByPostFix(module, moduleSolutionFile, "test", ".EntityFrameworkCore.Tests"); await RemoveProjectByPostFix(module, moduleSolutionFile, "test", ".EntityFrameworkCore.Tests");
await ChangeDomainTestReferenceToMongoDB(module, moduleSolutionFile);
} }
} }
@ -163,6 +186,11 @@ namespace Volo.Abp.Cli.ProjectModification
foreach (var package in packages) foreach (var package in packages)
{ {
if (target == NuGetPackageTarget.Web && package.Name.StartsWith("Volo.Abp.Account"))
{
continue;
}
await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, package.Name); await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, package.Name);
var projectPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), "src", package.Name); var projectPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), "src", package.Name);
@ -178,12 +206,27 @@ namespace Volo.Abp.Cli.ProjectModification
{ {
var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), targetFolder); var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), targetFolder);
var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith(postFix)); var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith(postFix));
await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, Path.GetDirectoryName(projectFolderPath)); await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, new DirectoryInfo(projectFolderPath).Name);
if (Directory.Exists(projectFolderPath)) if (Directory.Exists(projectFolderPath))
{ {
Directory.Delete(projectFolderPath, true); Directory.Delete(projectFolderPath, true);
} }
}
private async Task ChangeDomainTestReferenceToMongoDB(ModuleWithMastersInfo module, string moduleSolutionFile)
{
var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), "test");
var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith("Domain.Tests"));
var csprojFile = Directory.GetFiles(projectFolderPath).First(p => p.EndsWith(".csproj"));
var moduleFile = Directory.GetFiles(projectFolderPath).First(p => p.EndsWith("DomainTestModule.cs"));
File.WriteAllText(csprojFile, File.ReadAllText(csprojFile).Replace("EntityFrameworkCore","MongoDB"));
File.WriteAllText(moduleFile, File.ReadAllText(moduleFile)
.Replace(".EntityFrameworkCore;",".MongoDB;")
.Replace("EntityFrameworkCoreTestModule","MongoDbTestModule"));
} }
private async Task AddAngularPackages(string solutionFilePath, ModuleWithMastersInfo module) private async Task AddAngularPackages(string solutionFilePath, ModuleWithMastersInfo module)
@ -256,7 +299,9 @@ namespace Volo.Abp.Cli.ProjectModification
); );
} }
await DeleteAppAndDemoFolderAsync(targetModuleFolder); await DeleteRedundantHostProjects(targetModuleFolder,"app");
await DeleteRedundantHostProjects(targetModuleFolder,"demo");
await DeleteRedundantHostProjects(targetModuleFolder,"host");
if (module.MasterModuleInfos == null) if (module.MasterModuleInfos == null)
{ {
@ -281,24 +326,22 @@ namespace Volo.Abp.Cli.ProjectModification
await NewCommand.ExecuteAsync(args); await NewCommand.ExecuteAsync(args);
} }
private async Task DeleteAppAndDemoFolderAsync(string targetModuleFolder) private async Task DeleteRedundantHostProjects(string targetModuleFolder, string folderName)
{ {
var appFolder = Path.Combine(targetModuleFolder, "app"); var moduleSolutionFile = Directory.GetFiles(targetModuleFolder, "*.sln", SearchOption.TopDirectoryOnly).First();
if (Directory.Exists(appFolder))
{
Directory.Delete(appFolder, true);
}
var demoFolder = Path.Combine(targetModuleFolder, "demo"); var folder = Path.Combine(targetModuleFolder, folderName);
if (Directory.Exists(demoFolder)) if (Directory.Exists(folder))
{ {
Directory.Delete(demoFolder, true); var projects = Directory.GetDirectories(folder);
}
var hostFolder = Path.Combine(targetModuleFolder, "host"); foreach (var project in projects)
if (Directory.Exists(hostFolder)) {
{ await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile,
Directory.Delete(hostFolder, true); new DirectoryInfo(project).Name);
}
Directory.Delete(folder, true);
} }
} }
@ -444,73 +487,76 @@ namespace Volo.Abp.Cli.ProjectModification
private async Task<ModuleWithMastersInfo> GetEmptyModuleProjectInfoAsync(string moduleName, private async Task<ModuleWithMastersInfo> GetEmptyModuleProjectInfoAsync(string moduleName,
bool newProTemplate = false) bool newProTemplate = false)
{ {
var module = new ModuleWithMastersInfo(); var module = new ModuleWithMastersInfo
{
Name = moduleName,
DisplayName = moduleName,
MasterModuleInfos = new List<ModuleWithMastersInfo>()
};
module.Name = moduleName; var moduleProjectName = module.Name.Split('.').Last();
module.DisplayName = moduleName; module.EfCoreConfigureMethodName = $"{module.Name}.EntityFrameworkCore:Configure{moduleProjectName}";
module.EfCoreConfigureMethodName = $"{module.Name}.EntityFrameworkCore:Configure{module.Name}";
module.MasterModuleInfos = new List<ModuleWithMastersInfo>();
module.NugetPackages = new List<NugetPackageInfo> module.NugetPackages = new List<NugetPackageInfo>
{ {
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.Application", Name = $"{module.Name}.Application",
ModuleClass = $"{module.Name}.{module.Name}ApplicationModule", ModuleClass = $"{module.Name}.{moduleProjectName}ApplicationModule",
Target = NuGetPackageTarget.Application Target = NuGetPackageTarget.Application
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.Application.Contracts", Name = $"{module.Name}.Application.Contracts",
ModuleClass = $"{module.Name}.{module.Name}ApplicationContractsModule", ModuleClass = $"{module.Name}.{moduleProjectName}ApplicationContractsModule",
Target = NuGetPackageTarget.ApplicationContracts Target = NuGetPackageTarget.ApplicationContracts
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.Blazor", Name = $"{module.Name}.Blazor",
ModuleClass = $"{module.Name}.Blazor.{module.Name}BlazorModule", ModuleClass = $"{module.Name}.Blazor.{moduleProjectName}BlazorModule",
Target = NuGetPackageTarget.Blazor Target = NuGetPackageTarget.Blazor
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.Domain", Name = $"{module.Name}.Domain",
ModuleClass = $"{module.Name}.{module.Name}DomainModule", ModuleClass = $"{module.Name}.{moduleProjectName}DomainModule",
Target = NuGetPackageTarget.Domain Target = NuGetPackageTarget.Domain
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.Domain.Shared", Name = $"{module.Name}.Domain.Shared",
ModuleClass = $"{module.Name}.{module.Name}DomainSharedModule", ModuleClass = $"{module.Name}.{moduleProjectName}DomainSharedModule",
Target = NuGetPackageTarget.DomainShared Target = NuGetPackageTarget.DomainShared
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.EntityFrameworkCore", Name = $"{module.Name}.EntityFrameworkCore",
ModuleClass = $"{module.Name}.EntityFrameworkCore.{module.Name}EntityFrameworkCoreModule", ModuleClass = $"{module.Name}.EntityFrameworkCore.{moduleProjectName}EntityFrameworkCoreModule",
Target = NuGetPackageTarget.EntityFrameworkCore Target = NuGetPackageTarget.EntityFrameworkCore
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.HttpApi", Name = $"{module.Name}.HttpApi",
ModuleClass = $"{module.Name}.{module.Name}HttpApiModule", ModuleClass = $"{module.Name}.{moduleProjectName}HttpApiModule",
Target = NuGetPackageTarget.HttpApi Target = NuGetPackageTarget.HttpApi
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.HttpApi.Client", Name = $"{module.Name}.HttpApi.Client",
ModuleClass = $"{module.Name}.{module.Name}HttpApiClientModule", ModuleClass = $"{module.Name}.{moduleProjectName}HttpApiClientModule",
Target = NuGetPackageTarget.HttpApiClient Target = NuGetPackageTarget.HttpApiClient
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.MongoDB", Name = $"{module.Name}.MongoDB",
ModuleClass = $"{module.Name}.MongoDB.{module.Name}MongoDbModule", ModuleClass = $"{module.Name}.MongoDB.{moduleProjectName}MongoDbModule",
Target = NuGetPackageTarget.MongoDB Target = NuGetPackageTarget.MongoDB
}, },
new NugetPackageInfo new NugetPackageInfo
{ {
Name = $"{module.Name}.Web", Name = $"{module.Name}.Web",
ModuleClass = $"{module.Name}.Web.{module.Name}WebModule", ModuleClass = $"{module.Name}.Web.{moduleProjectName}WebModule",
Target = NuGetPackageTarget.Web Target = NuGetPackageTarget.Web
}, },
}; };
@ -523,7 +569,9 @@ namespace Volo.Abp.Cli.ProjectModification
protected virtual async Task<bool> IsProjectTiered(string[] projectFiles) protected virtual async Task<bool> IsProjectTiered(string[] projectFiles)
{ {
return projectFiles.Select(ProjectFileNameHelper.GetAssemblyNameFromProjectPath) return projectFiles.Select(ProjectFileNameHelper.GetAssemblyNameFromProjectPath)
.Any(p => p.EndsWith(".IdentityServer") || p.EndsWith(".HttpApi.Host")); .Any(p =>p.EndsWith(".HttpApi.Host"))
&& projectFiles.Select(ProjectFileNameHelper.GetAssemblyNameFromProjectPath)
.Any(p => p.EndsWith(".IdentityServer"));
} }
} }
} }

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

@ -26,10 +26,10 @@
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.1.5" /> <PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.6" />
<PackageReference Include="System.Linq.Queryable" Version="4.3.0" /> <PackageReference Include="System.Linq.Queryable" Version="4.3.0" />
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
<PackageReference Include="Nito.AsyncEx.Coordination" Version="5.0.0" /> <PackageReference Include="Nito.AsyncEx.Coordination" Version="5.1.0" />
<PackageReference Include="Nito.AsyncEx.Context" Version="5.0.0" /> <PackageReference Include="Nito.AsyncEx.Context" Version="5.1.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

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

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="2.0.35" /> <PackageReference Include="Dapper" Version="2.0.78" />
</ItemGroup> </ItemGroup>
</Project> </Project>

2
framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql/Volo.Abp.EntityFrameworkCore.PostgreSql.csproj

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.0-rc1" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

2
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs

@ -30,7 +30,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore
private readonly IDbContextProvider<TDbContext> _dbContextProvider; private readonly IDbContextProvider<TDbContext> _dbContextProvider;
private readonly Lazy<AbpEntityOptions<TEntity>> _entityOptionsLazy; private readonly Lazy<AbpEntityOptions<TEntity>> _entityOptionsLazy;
protected virtual IGuidGenerator GuidGenerator { get; set; } public virtual IGuidGenerator GuidGenerator { get; set; }
public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider) public EfCoreRepository(IDbContextProvider<TDbContext> dbContextProvider)
{ {

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.6.2" /> <PackageReference Include="FluentValidation" Version="9.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

5
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs

@ -26,7 +26,10 @@ namespace Volo.Abp.FluentValidation
return; return;
} }
var result = validator.Validate(context.ValidatingObject); var result = validator.Validate((IValidationContext) Activator.CreateInstance(
typeof(ValidationContext<>).MakeGenericType(context.ValidatingObject.GetType()),
context.ValidatingObject));
if (!result.IsValid) if (!result.IsValid)
{ {
context.Errors.AddRange( context.Errors.AddRange(

2
framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeature.cs

@ -1,4 +1,4 @@
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Volo.Abp.GlobalFeatures namespace Volo.Abp.GlobalFeatures
{ {

2
framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalModuleFeaturesDictionary.cs

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Volo.Abp.GlobalFeatures namespace Volo.Abp.GlobalFeatures

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.11" /> <PackageReference Include="Hangfire.AspNetCore" Version="1.7.*" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityModel" Version="4.3.0" /> <PackageReference Include="IdentityModel" Version="4.5.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.Extensions.Http" Version="$(MicrosoftPackageVersion)" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" /> <ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> <ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />

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

@ -9,7 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Confluent.Kafka" Version="1.5.0" /> <PackageReference Include="Confluent.Kafka" Version="1.5.2" />
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" /> <ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" /> <ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
</ItemGroup> </ItemGroup>

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MailKit" Version="2.7.0" /> <PackageReference Include="MailKit" Version="2.10.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NUglify" Version="1.6.3" /> <PackageReference Include="NUglify" Version="1.11.4" />
</ItemGroup> </ItemGroup>
</Project> </Project>

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.11.1" /> <PackageReference Include="MongoDB.Driver" Version="2.11.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

1
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/EntityExtensionConfiguration.cs

@ -56,7 +56,6 @@ namespace Volo.Abp.ObjectExtending.Modularity
{ {
AddLookupTextProperty(propertyInfo); AddLookupTextProperty(propertyInfo);
propertyInfo.UI.OnTable.IsVisible = false; propertyInfo.UI.OnTable.IsVisible = false;
propertyInfo.Api.OnGet.IsAvailable = false;
} }
return this; return this;
} }

6
framework/src/Volo.Abp.Quartz/Volo.Abp.Quartz.csproj

@ -15,9 +15,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Quartz" Version="3.1.0" /> <PackageReference Include="Quartz" Version="3.2.3" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.1.0" /> <PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.2.3" />
<PackageReference Include="Quartz.Plugins.TimeZoneConverter" Version="3.1.0" /> <PackageReference Include="Quartz.Plugins.TimeZoneConverter" Version="3.2.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RabbitMQ.Client" Version="6.1.0" /> <PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" /> <ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" /> <ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
</ItemGroup> </ItemGroup>

4
framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj

@ -2,7 +2,7 @@
<Import Project="..\..\..\configureawait.props" /> <Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.Swashbuckle</AssemblyName> <AssemblyName>Volo.Abp.Swashbuckle</AssemblyName>
@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Scriban" Version="2.1.3" /> <PackageReference Include="Scriban" Version="3.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

15
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateLocalizer.cs

@ -46,5 +46,20 @@ namespace Volo.Abp.TextTemplating
var args = arguments.Skip(1).Where(x => x != null && !x.ToString().IsNullOrWhiteSpace()).ToArray(); var args = arguments.Skip(1).Where(x => x != null && !x.ToString().IsNullOrWhiteSpace()).ToArray();
return args.Any() ? _localizer[name.ToString(), args] : _localizer[name.ToString()]; return args.Any() ? _localizer[name.ToString(), args] : _localizer[name.ToString()];
} }
public int RequiredParameterCount => 1;
public int ParameterCount => ScriptFunctionCall.MaximumParameterCount - 1;
public ScriptVarParamKind VarParamKind => ScriptVarParamKind.Direct;
public Type ReturnType => typeof(object);
public ScriptParameterInfo GetParameterInfo(int index)
{
return index == 0
? new ScriptParameterInfo(typeof(string), "template_name")
: new ScriptParameterInfo(typeof(object), "value");
}
} }
} }

11
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory.cs

@ -1,4 +1,5 @@
using System.Collections.Concurrent; using System;
using System.Collections.Concurrent;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -52,7 +53,13 @@ namespace Volo.Abp.TextTemplating.VirtualFiles
var fileInfo = VirtualFileProvider.GetFileInfo(virtualPath); var fileInfo = VirtualFileProvider.GetFileInfo(virtualPath);
if (!fileInfo.Exists) if (!fileInfo.Exists)
{ {
throw new AbpException("Could not find a file/folder at the location: " + virtualPath); 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) if (fileInfo.IsDirectory)

12
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs

@ -11,18 +11,18 @@ namespace Volo.Abp.TextTemplating.VirtualFiles
private Dictionary<string, string> _dictionary; private Dictionary<string, string> _dictionary;
public async Task ReadContentsAsync( public async Task ReadContentsAsync(
IVirtualFileProvider virtualFileProvider, IVirtualFileProvider virtualFileProvider,
string virtualPath) string virtualPath)
{ {
_dictionary = new Dictionary<string, string>(); _dictionary = new Dictionary<string, string>();
var directoryInfo = virtualFileProvider.GetFileInfo(virtualPath); var directoryContents = virtualFileProvider.GetDirectoryContents(virtualPath);
if (!directoryInfo.IsDirectory) if (!directoryContents.Exists)
{ {
throw new AbpException("Given virtual path is not a folder: " + virtualPath); throw new AbpException("Could not find a folder at the location: " + virtualPath);
} }
foreach (var file in virtualFileProvider.GetDirectoryContents(virtualPath)) foreach (var file in directoryContents)
{ {
if (file.IsDirectory) if (file.IsDirectory)
{ {
@ -43,4 +43,4 @@ namespace Volo.Abp.TextTemplating.VirtualFiles
return _dictionary.GetOrDefault(cultureName); return _dictionary.GetOrDefault(cultureName);
} }
} }
} }

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

@ -26,7 +26,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="TimeZoneConverter" Version="3.2.0" /> <PackageReference Include="TimeZoneConverter" Version="3.3.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

2
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj

@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
</ItemGroup> </ItemGroup>

2
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json

@ -3,7 +3,7 @@
"name": "asp.net", "name": "asp.net",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.shared": "^4.0.0", "@abp/aspnetcore.mvc.ui.theme.shared": "^4.0.1",
"highlight.js": "^9.13.1" "highlight.js": "^9.13.1"
}, },
"devDependencies": {} "devDependencies": {}

224
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock

@ -2,30 +2,30 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/aspnetcore.mvc.ui.theme.shared@^4.0.0": "@abp/aspnetcore.mvc.ui.theme.shared@^4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-4.0.0.tgz#ba896056e9df5ac58e108df96996fbb2ca7a1a15" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-4.0.1.tgz#cd9d0eb11309c597dffd26277cd1bd7c5b1e0e2f"
integrity sha512-3RNn6VrNA+cqnPBoSbiCazN05cC2rhcRFMMxkEte+LImGbGOsxc4MflzHg5On1ExCGdqko8Axbw/ydy44Ak4Hw== integrity sha512-QGoCN/my0eAfa4tx5ytDxArIoz2i58jFFVUGso1Lekn54JvSt+WLz2p3uyTGatZ03Bp9836elhFnIopn12WvBw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui" "~4.0.0" "@abp/aspnetcore.mvc.ui" "~4.0.1"
"@abp/bootstrap" "~4.0.0" "@abp/bootstrap" "~4.0.1"
"@abp/bootstrap-datepicker" "~4.0.0" "@abp/bootstrap-datepicker" "~4.0.1"
"@abp/datatables.net-bs4" "~4.0.0" "@abp/datatables.net-bs4" "~4.0.1"
"@abp/font-awesome" "~4.0.0" "@abp/font-awesome" "~4.0.1"
"@abp/jquery-form" "~4.0.0" "@abp/jquery-form" "~4.0.1"
"@abp/jquery-validation-unobtrusive" "~4.0.0" "@abp/jquery-validation-unobtrusive" "~4.0.1"
"@abp/lodash" "~4.0.0" "@abp/lodash" "~4.0.1"
"@abp/luxon" "~4.0.0" "@abp/luxon" "~4.0.1"
"@abp/malihu-custom-scrollbar-plugin" "~4.0.0" "@abp/malihu-custom-scrollbar-plugin" "~4.0.1"
"@abp/select2" "~4.0.0" "@abp/select2" "~4.0.1"
"@abp/sweetalert" "~4.0.0" "@abp/sweetalert" "~4.0.1"
"@abp/timeago" "~4.0.0" "@abp/timeago" "~4.0.1"
"@abp/toastr" "~4.0.0" "@abp/toastr" "~4.0.1"
"@abp/aspnetcore.mvc.ui@~4.0.0": "@abp/aspnetcore.mvc.ui@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-4.0.0.tgz#68502177a05f6ce7191a09b06a18c5b5dfab425d" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-4.0.1.tgz#6490c147a56e4f7055d2ca77f20baf1f60f56867"
integrity sha512-tYHUWMwnwInrGSzC/OdN6bH/VHZEz5DP3rx2U6fcb0I5GvvRdQZxVgUvmWn6DeMA3PG10Gra4SfkhZqRQq9rjQ== integrity sha512-4B3icJrlpuZgMaX52ninyaenH7zLwepePEscDrLaFY9wyonKpZ2zh+xplnyM6vjNd+PhErWuA2+ssCswFhrJ3A==
dependencies: dependencies:
ansi-colors "^4.1.1" ansi-colors "^4.1.1"
extend-object "^1.0.0" extend-object "^1.0.0"
@ -36,145 +36,145 @@
micromatch "^4.0.2" micromatch "^4.0.2"
path "^0.12.7" path "^0.12.7"
"@abp/bootstrap-datepicker@~4.0.0": "@abp/bootstrap-datepicker@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-4.0.0.tgz#cdbd2c388c6d7ce8c6d72443038975063e6c6d02" resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-4.0.1.tgz#aad891263edff66f816e003ba4fa7f8acfe8e0b6"
integrity sha512-hauH8VhpC8cxv1wCR6bVBcNqZepftdBXxEVID7TSAqgNyWjm/CrJqWLI+A0nnkG3IHoIm9D22iF47BamuYHptw== integrity sha512-S0oaVZmXsDcOJLAyoGY0TvP/7bZx0GHIbU9BIhIL2Wl74HYaokjkTr6/IleIek9YeiF2vm9FkrUP1dKH/4f7Gg==
dependencies: dependencies:
bootstrap-datepicker "^1.9.0" bootstrap-datepicker "^1.9.0"
"@abp/bootstrap@~4.0.0": "@abp/bootstrap@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-4.0.0.tgz#04174f18055f76f936e6fb73e5ff71ffa08a8528" resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-4.0.1.tgz#3e41bdf9b3e9f8c497b9fafe22a4851d0401b31b"
integrity sha512-Tmr0yoSWg7XHl02X5wv04CvYcL8KCpX8u6YGJj31jRZxUTeCvs5ETXlepOWcdxPQqi/4olXv5B9GEz5S9l5nZA== integrity sha512-GoSaNWvswRHVoUrq7xClFQYtwqIlyS/vp/TdY+j5FFZP7ud89+ZGpdNqYqq5l9/6aaYa7v4b9mNTZ/1JRzAOYg==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
bootstrap "^4.5.0" bootstrap "^4.5.0"
bootstrap-v4-rtl "4.4.1-2" bootstrap-v4-rtl "4.4.1-2"
"@abp/core@~4.0.0": "@abp/core@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/core/-/core-4.0.0.tgz#65e76c697e62162717e0edabf7edacc4228e682a" resolved "https://registry.yarnpkg.com/@abp/core/-/core-4.0.1.tgz#1df32bc058f45571605670ca81c226a1bd87400c"
integrity sha512-xcTTBFjLFZ9Trv2x9Y/c3XKezIx+x3MTXUD98QJPf1aR7T43TE/tLHRxdRfW3R8ka0O1wmlYshpkaw5pYNsj5w== integrity sha512-8UT5lwqV/luVG/SxePSTD2FRbZXwXv3cZJKjw+gpBjhD0slWrh51XEOHsM8ciTuhcvV/tsqVU9nXckDMdO58fw==
dependencies: dependencies:
"@abp/utils" "^4.0.0" "@abp/utils" "^4.0.1"
"@abp/datatables.net-bs4@~4.0.0": "@abp/datatables.net-bs4@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs4/-/datatables.net-bs4-4.0.0.tgz#fe737e054f6ba35e787a1cda185af2788ef86d39" resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs4/-/datatables.net-bs4-4.0.1.tgz#7538baad0eff24eca7f4246d020852f83139f645"
integrity sha512-mz7xZdzX1nlFyX7vNzB5w3RkqZ0IHrPgsXGOB7OCTKMRshDFVH2O51Oy4qoLDOXoTVeahHtR9v8thEWFR1SnZg== integrity sha512-S52jNPF4if68V+P/33NrtGPJXf6xrqgyZzz9b7qBR7HuUm3Nsn7bAslh3JNduNec/sFuE4Utl/xsFHZNjBWEog==
dependencies: dependencies:
"@abp/datatables.net" "~4.0.0" "@abp/datatables.net" "~4.0.1"
datatables.net-bs4 "^1.10.21" datatables.net-bs4 "^1.10.21"
"@abp/datatables.net@~4.0.0": "@abp/datatables.net@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-4.0.0.tgz#88ae5f1a6068fba55927e59f113686508e9553cb" resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-4.0.1.tgz#eb89716a37351c41b5bccfc2db88fc7ceb991a26"
integrity sha512-JYTfMA1zlBNGiQHAiZiTj5ka6B6vq5k2jqsoLHup4pD9jpKwKRBGtltVsWoEnetd9eEbp4SaV/FCuh3RzmV6Pw== integrity sha512-APFLui0w8MqsBWqP/K0QkT5cBq5SsWiqMaIGTXQKinMVLV597sUszrlhe1ISU2PqeD7iX6pCZNNOTI1NEUn9/Q==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
datatables.net "^1.10.21" datatables.net "^1.10.21"
"@abp/font-awesome@~4.0.0": "@abp/font-awesome@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-4.0.0.tgz#6e1e4bd1175a0b8d3b095e215c07e66ad0e42e19" resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-4.0.1.tgz#8a9d83b2c2adfcd5abcbd9c31c315460d44a321e"
integrity sha512-kHfZ45UMDWSRk1gTV/BwVfSoXksJ9UlnD3SelTGeAkvbDqtDllqlp9y6c3qQcmZUE348Xl4hDTkU8upZwswCFQ== integrity sha512-+6+m/DKMnfkeQiWUsMlB6Da8u6yREyN2oQYGYhSRAK8419ym8RHHrqKJv2AClI4iLq2ppHZj8WF84+SeoCekRg==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
"@fortawesome/fontawesome-free" "^5.13.0" "@fortawesome/fontawesome-free" "^5.13.0"
"@abp/jquery-form@~4.0.0": "@abp/jquery-form@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-4.0.0.tgz#3afb41eb16d62e32c31a29c6a866f634a5a20cd8" resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-4.0.1.tgz#6dc1922b2800dd635f20881a82e08104a1dd1bb5"
integrity sha512-cQq8PgzHfpK9/LxmjlnMsDn85wWvEOqjyLaepHFpTTt0341auSgXNwhp7rk71AUHD1lP3c9ALctmqu+gYmh9ag== integrity sha512-JMBZYu/MI/GjaLTBOMB5iv8cagnLpReDULNC3r6tLNNqB1R8f3Cg1T7nF4YCuU9SYMqis1P/AuE4oEh+4rQdAQ==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
jquery-form "^4.3.0" jquery-form "^4.3.0"
"@abp/jquery-validation-unobtrusive@~4.0.0": "@abp/jquery-validation-unobtrusive@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-4.0.0.tgz#c3674d2b01b3c524de4c3fac1c6ae3657857ee7b" resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-4.0.1.tgz#4142ca31c0830fe24a1467e8cf13b55ba9d7c1dd"
integrity sha512-OGibIdw0ogjp6VQIebHM7OtMT36pjLKRrOHyCVpTmQ7NzDODV5ptG83vOnt5nFG0y9XFrOt8cnHrrd+K1Bpo/Q== integrity sha512-rdSRTcdKCHmarbrVgmPYdTiJ0G/aFKd+dr0krO7fALPTuQKChbDnHOO4/JvQSc+cd9faxa8c6ZWvlHdsof23tQ==
dependencies: dependencies:
"@abp/jquery-validation" "~4.0.0" "@abp/jquery-validation" "~4.0.1"
jquery-validation-unobtrusive "^3.2.11" jquery-validation-unobtrusive "^3.2.11"
"@abp/jquery-validation@~4.0.0": "@abp/jquery-validation@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-4.0.0.tgz#0a101937f89ff398317142b5271fa9a1de6571c2" resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-4.0.1.tgz#74e7d795468c6986f2db15662631fcd4f67c679e"
integrity sha512-4nzvhAktEINpQ2H+Hy7TOxxojTmTEm5dBTbHs1vbCWUuF0OTpouZWbMZDESdP0ZbjXcQ+vhwuM4e/pm/PeaHyQ== integrity sha512-FX26aQCsMBdVWAJb7S37Lt7KoHAEHoYguh/qfZIARCpOYOOWvxfDz1wTrmADUkqdillqEiCeD/Imj8bYH9Faaw==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
jquery-validation "^1.19.2" jquery-validation "^1.19.2"
"@abp/jquery@~4.0.0": "@abp/jquery@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-4.0.0.tgz#00d24678b573bcc2fb14d8337ccdbf697b59d43b" resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-4.0.1.tgz#aa554accb16600fd586c3a4f088040cd26d0bde8"
integrity sha512-gXLK97IvAZriNlG8e0qJcd7MvnpshJQURb4lg8VYibD7Fs/OBeHSAWM2Adgi3H9DnQL8XEUlWf487FSz4RC/Yg== integrity sha512-MtiRKOLyjEWux+whPP3+zwPbpj8or756JtgjnwOTDB9tp9HLCYUaskt+oalYPvob24nDZcNu2RnMALYdCVhZAQ==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
jquery "~3.5.1" jquery "~3.5.1"
"@abp/lodash@~4.0.0": "@abp/lodash@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-4.0.0.tgz#fe76d09517f6b1adf18edde94a31e13b003329dc" resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-4.0.1.tgz#ec261ccaab8a70d5b32a8a7c22387e48936d38d4"
integrity sha512-uitn5uYlb9xShRtV4AFOgp3lu2kADGMD4+a4fy5r4umlPM2uuMo0wMhzyYdBIG64JC5oNaqAzOwZyhhnn+HGJg== integrity sha512-Dav1QKbBeGR4VVbHHe1s3OEzN7wnb9K/vwzHrWmtO8D1Q5Z3433xjNmgL5VQ9gfxXqooSfEO4gAovZklMDHDew==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
lodash "^4.17.15" lodash "^4.17.15"
"@abp/luxon@~4.0.0": "@abp/luxon@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-4.0.0.tgz#d9357e4fb422b6e18ebe897a86a4c4bc6fbe6858" resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-4.0.1.tgz#a540750b1605dbac856ce9c2e776c2fecf6392f9"
integrity sha512-tiE6NiSa4El88SVotxfmmpceINLz8MruaO/e/U3QjJEHjRoqlv0UBrM/x5Xz92c7ZIvL0Y4QvWNISeDg6/oqIQ== integrity sha512-eRumVB7UIf2XH6OZVUTvcKw0A/OSAfYV59fM+Wc4dAkNcmsNZI0gD1o0AigSGNCxTV6v+W2bFrsuooSqK99Y0Q==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
luxon "^1.24.1" luxon "^1.24.1"
"@abp/malihu-custom-scrollbar-plugin@~4.0.0": "@abp/malihu-custom-scrollbar-plugin@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-4.0.0.tgz#972acf26f5eaa4bf9b8991cbe7c19fd0005d94e2" resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-4.0.1.tgz#0a556423a67b6c949e32ffcacd72256dea6c31ee"
integrity sha512-SpUo1CfppKzkE6Rb880pgB7oQ83Mkjsi0o6eE4r4gkF5hfzkuCXOmNjTYKfQIkE4n3G9QQd+8AAN/4xj4DiDrA== integrity sha512-YTwYpnQ1ZrON70gvJcnNZRwB3Ze4olGcXxiPvmRgSHbGJkSnHYJiP6PvsN1F3HDFukAJ/iUu+WwEe8OBwlyLXA==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
malihu-custom-scrollbar-plugin "^3.1.5" malihu-custom-scrollbar-plugin "^3.1.5"
"@abp/select2@~4.0.0": "@abp/select2@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-4.0.0.tgz#8fdf4c5e18f4093ee4e073dab950cf7aa9b2a540" resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-4.0.1.tgz#8983e7b5c3afb862f08b2730b70e59d726e9b5d5"
integrity sha512-XeXahcDMczdkZdP07yhQriIvbi1N5meeSGTnFyZX+bNTGzUOarPcuNYZ6Mcl3351HcyESHzuJbKbsk3RB1kGeg== integrity sha512-WdzY2hvsS/4vz/VXpxq2muSzzE8ggchiIrICy/WKchJxL9L08DM796t6aE6rEl9wucY8XEzzWrPOVqAjJmnXFA==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
select2 "^4.0.13" select2 "^4.0.13"
"@abp/sweetalert@~4.0.0": "@abp/sweetalert@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/sweetalert/-/sweetalert-4.0.0.tgz#0d93e92e95c6855aef7e19532a7513a078ece216" resolved "https://registry.yarnpkg.com/@abp/sweetalert/-/sweetalert-4.0.1.tgz#0088610915ad6db0a140b77832a37c10066eb4ee"
integrity sha512-y3XtZqnUVZuQohpRO1ImyBZXhtrm4H+typIL/9VgcnlvQjBTyIaiwDmU8j07Bb2rKJKe0prVkkVARO7OnjOS5A== integrity sha512-t4/44oQCMngSjVqmeRWXwrXa/pRKc3CEpyyTiGIXki4dWJ21j0ePCw2l3rvOJWnpoCznhxa/UGxLfRfK1NEzRg==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
sweetalert "^2.1.2" sweetalert "^2.1.2"
"@abp/timeago@~4.0.0": "@abp/timeago@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-4.0.0.tgz#509cd8a84cd94c2644824b0c3af10c8fff6de2dc" resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-4.0.1.tgz#8c161645534eb1f62fe4607450acf7345729e711"
integrity sha512-90jzLYJusYTPwMbak1+XkXE85OPOXPpysRbL28KQwl7WLNBm8wx6IEoVZOHvOrpYscYdyeWhZCgILSJ8DR3a2Q== integrity sha512-PsPobV79U2qzVY+WBsmJM1ohSF4jqcLnL4/7qyJvxlb1WwbCl1F5D4cpiJP4zsM4clPW4mbSsiauMNp+HTNKEA==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
timeago "^1.6.7" timeago "^1.6.7"
"@abp/toastr@~4.0.0": "@abp/toastr@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-4.0.0.tgz#06e28665cb7f6eefee3f69c985dd2b3f86cd7f1d" resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-4.0.1.tgz#ecb6f6193b7edc3150d0614ab9457472baf1cce3"
integrity sha512-YL1fahVpDszhwpnRTN87GCP523Mkaw42ApT2A/hZuBdwRzP/u5GwRfng0i/uhdYXCMkTKuHmaHnRyqhGiv7nfQ== integrity sha512-bTTz0O8zj7fMhdoummP2Ed5Z8SJTmR6svzNchBXNDrnRAcDQvTihPTcg0UpH8BEDFczbLowq09CG2A/RMSJoug==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
toastr "^2.1.4" toastr "^2.1.4"
"@abp/utils@^4.0.0": "@abp/utils@^4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-4.0.0.tgz#6c2b5f5c20821028fe6cdbffb5e2f6088956b9d5" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-4.0.1.tgz#9a4cb420266c49d8084776bd31c86681d4d4d125"
integrity sha512-Yj2yCObvS6X/P8rdRMQBo7940k5P/dZhgCUSo9C6P9GNmJY8wNdJFFyhRtaHuAyU5IBBBIY7+mMKOk5eQcbjWQ== integrity sha512-nI2ZyaNpvohr75p8jeMPWze+hX+mV47EHI+Zloa4GgGmJqrULdG71kYh45R+jGmMTbQL6huaXGnpz4gNF9TGyQ==
dependencies: dependencies:
just-compare "^1.3.0" just-compare "^1.3.0"

2
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="$(MicrosoftPackageVersion)" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
</ItemGroup> </ItemGroup>

4
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json

@ -3,8 +3,8 @@
"name": "asp.net", "name": "asp.net",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^4.0.0", "@abp/aspnetcore.mvc.ui.theme.basic": "^4.0.1",
"@abp/prismjs": "^4.0.0" "@abp/prismjs": "^4.0.1"
}, },
"devDependencies": {} "devDependencies": {}
} }

256
framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock

@ -2,37 +2,37 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/aspnetcore.mvc.ui.theme.basic@^4.0.0": "@abp/aspnetcore.mvc.ui.theme.basic@^4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-4.0.0.tgz#b1822cf5bbc0f6eeb414ebd0877f6d1115a81fe7" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-4.0.1.tgz#ce8e3eb830a8e8f9eecb1a3b3bd70c2832fdf15e"
integrity sha512-yYXQkEnNhftzm+ZI8d3VFMlV5UuLNTMQQwV2eZ8tJfstUQrKV9bVd3+NdDOr3AkvcD8D7mvMFeBuoMYteL5kLQ== integrity sha512-w+ZG8Ewx9wWfbvRC2MAjJl+rXuXSHLhhGOiJTk68unWLNziDtNQzcSXG/Z5c1hA+acJSGqDoJGEGs4FVM136og==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui.theme.shared" "~4.0.0" "@abp/aspnetcore.mvc.ui.theme.shared" "~4.0.1"
"@abp/aspnetcore.mvc.ui.theme.shared@~4.0.0": "@abp/aspnetcore.mvc.ui.theme.shared@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-4.0.0.tgz#ba896056e9df5ac58e108df96996fbb2ca7a1a15" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-4.0.1.tgz#cd9d0eb11309c597dffd26277cd1bd7c5b1e0e2f"
integrity sha512-3RNn6VrNA+cqnPBoSbiCazN05cC2rhcRFMMxkEte+LImGbGOsxc4MflzHg5On1ExCGdqko8Axbw/ydy44Ak4Hw== integrity sha512-QGoCN/my0eAfa4tx5ytDxArIoz2i58jFFVUGso1Lekn54JvSt+WLz2p3uyTGatZ03Bp9836elhFnIopn12WvBw==
dependencies: dependencies:
"@abp/aspnetcore.mvc.ui" "~4.0.0" "@abp/aspnetcore.mvc.ui" "~4.0.1"
"@abp/bootstrap" "~4.0.0" "@abp/bootstrap" "~4.0.1"
"@abp/bootstrap-datepicker" "~4.0.0" "@abp/bootstrap-datepicker" "~4.0.1"
"@abp/datatables.net-bs4" "~4.0.0" "@abp/datatables.net-bs4" "~4.0.1"
"@abp/font-awesome" "~4.0.0" "@abp/font-awesome" "~4.0.1"
"@abp/jquery-form" "~4.0.0" "@abp/jquery-form" "~4.0.1"
"@abp/jquery-validation-unobtrusive" "~4.0.0" "@abp/jquery-validation-unobtrusive" "~4.0.1"
"@abp/lodash" "~4.0.0" "@abp/lodash" "~4.0.1"
"@abp/luxon" "~4.0.0" "@abp/luxon" "~4.0.1"
"@abp/malihu-custom-scrollbar-plugin" "~4.0.0" "@abp/malihu-custom-scrollbar-plugin" "~4.0.1"
"@abp/select2" "~4.0.0" "@abp/select2" "~4.0.1"
"@abp/sweetalert" "~4.0.0" "@abp/sweetalert" "~4.0.1"
"@abp/timeago" "~4.0.0" "@abp/timeago" "~4.0.1"
"@abp/toastr" "~4.0.0" "@abp/toastr" "~4.0.1"
"@abp/aspnetcore.mvc.ui@~4.0.0": "@abp/aspnetcore.mvc.ui@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-4.0.0.tgz#68502177a05f6ce7191a09b06a18c5b5dfab425d" resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-4.0.1.tgz#6490c147a56e4f7055d2ca77f20baf1f60f56867"
integrity sha512-tYHUWMwnwInrGSzC/OdN6bH/VHZEz5DP3rx2U6fcb0I5GvvRdQZxVgUvmWn6DeMA3PG10Gra4SfkhZqRQq9rjQ== integrity sha512-4B3icJrlpuZgMaX52ninyaenH7zLwepePEscDrLaFY9wyonKpZ2zh+xplnyM6vjNd+PhErWuA2+ssCswFhrJ3A==
dependencies: dependencies:
ansi-colors "^4.1.1" ansi-colors "^4.1.1"
extend-object "^1.0.0" extend-object "^1.0.0"
@ -43,162 +43,162 @@
micromatch "^4.0.2" micromatch "^4.0.2"
path "^0.12.7" path "^0.12.7"
"@abp/bootstrap-datepicker@~4.0.0": "@abp/bootstrap-datepicker@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-4.0.0.tgz#cdbd2c388c6d7ce8c6d72443038975063e6c6d02" resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-4.0.1.tgz#aad891263edff66f816e003ba4fa7f8acfe8e0b6"
integrity sha512-hauH8VhpC8cxv1wCR6bVBcNqZepftdBXxEVID7TSAqgNyWjm/CrJqWLI+A0nnkG3IHoIm9D22iF47BamuYHptw== integrity sha512-S0oaVZmXsDcOJLAyoGY0TvP/7bZx0GHIbU9BIhIL2Wl74HYaokjkTr6/IleIek9YeiF2vm9FkrUP1dKH/4f7Gg==
dependencies: dependencies:
bootstrap-datepicker "^1.9.0" bootstrap-datepicker "^1.9.0"
"@abp/bootstrap@~4.0.0": "@abp/bootstrap@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-4.0.0.tgz#04174f18055f76f936e6fb73e5ff71ffa08a8528" resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-4.0.1.tgz#3e41bdf9b3e9f8c497b9fafe22a4851d0401b31b"
integrity sha512-Tmr0yoSWg7XHl02X5wv04CvYcL8KCpX8u6YGJj31jRZxUTeCvs5ETXlepOWcdxPQqi/4olXv5B9GEz5S9l5nZA== integrity sha512-GoSaNWvswRHVoUrq7xClFQYtwqIlyS/vp/TdY+j5FFZP7ud89+ZGpdNqYqq5l9/6aaYa7v4b9mNTZ/1JRzAOYg==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
bootstrap "^4.5.0" bootstrap "^4.5.0"
bootstrap-v4-rtl "4.4.1-2" bootstrap-v4-rtl "4.4.1-2"
"@abp/clipboard@~4.0.0": "@abp/clipboard@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-4.0.0.tgz#4b01bead2e404c38a3ae9955dac5522d3c30c78b" resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-4.0.1.tgz#aacbd02b6ce991ca20550ad7afc40e0cea247b5e"
integrity sha512-39CZuF6lxUx1fluclzMl1uG0qIUX82S2wNbyJu2WGfuMMaaIgzSp9du/bB89Ik6rR5BFUU/3p8uvzOgy4sc2sQ== integrity sha512-Q7Fe167pBJ/9Vp5RyVc/JejaIzNCdTgXcnZLNC7AEtaeBVCmLwsdnCYP3i32sdvX1AIgt3exhAAsHBt0deij/g==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
clipboard "^2.0.6" clipboard "^2.0.6"
"@abp/core@~4.0.0": "@abp/core@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/core/-/core-4.0.0.tgz#65e76c697e62162717e0edabf7edacc4228e682a" resolved "https://registry.yarnpkg.com/@abp/core/-/core-4.0.1.tgz#1df32bc058f45571605670ca81c226a1bd87400c"
integrity sha512-xcTTBFjLFZ9Trv2x9Y/c3XKezIx+x3MTXUD98QJPf1aR7T43TE/tLHRxdRfW3R8ka0O1wmlYshpkaw5pYNsj5w== integrity sha512-8UT5lwqV/luVG/SxePSTD2FRbZXwXv3cZJKjw+gpBjhD0slWrh51XEOHsM8ciTuhcvV/tsqVU9nXckDMdO58fw==
dependencies: dependencies:
"@abp/utils" "^4.0.0" "@abp/utils" "^4.0.1"
"@abp/datatables.net-bs4@~4.0.0": "@abp/datatables.net-bs4@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs4/-/datatables.net-bs4-4.0.0.tgz#fe737e054f6ba35e787a1cda185af2788ef86d39" resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs4/-/datatables.net-bs4-4.0.1.tgz#7538baad0eff24eca7f4246d020852f83139f645"
integrity sha512-mz7xZdzX1nlFyX7vNzB5w3RkqZ0IHrPgsXGOB7OCTKMRshDFVH2O51Oy4qoLDOXoTVeahHtR9v8thEWFR1SnZg== integrity sha512-S52jNPF4if68V+P/33NrtGPJXf6xrqgyZzz9b7qBR7HuUm3Nsn7bAslh3JNduNec/sFuE4Utl/xsFHZNjBWEog==
dependencies: dependencies:
"@abp/datatables.net" "~4.0.0" "@abp/datatables.net" "~4.0.1"
datatables.net-bs4 "^1.10.21" datatables.net-bs4 "^1.10.21"
"@abp/datatables.net@~4.0.0": "@abp/datatables.net@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-4.0.0.tgz#88ae5f1a6068fba55927e59f113686508e9553cb" resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-4.0.1.tgz#eb89716a37351c41b5bccfc2db88fc7ceb991a26"
integrity sha512-JYTfMA1zlBNGiQHAiZiTj5ka6B6vq5k2jqsoLHup4pD9jpKwKRBGtltVsWoEnetd9eEbp4SaV/FCuh3RzmV6Pw== integrity sha512-APFLui0w8MqsBWqP/K0QkT5cBq5SsWiqMaIGTXQKinMVLV597sUszrlhe1ISU2PqeD7iX6pCZNNOTI1NEUn9/Q==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
datatables.net "^1.10.21" datatables.net "^1.10.21"
"@abp/font-awesome@~4.0.0": "@abp/font-awesome@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-4.0.0.tgz#6e1e4bd1175a0b8d3b095e215c07e66ad0e42e19" resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-4.0.1.tgz#8a9d83b2c2adfcd5abcbd9c31c315460d44a321e"
integrity sha512-kHfZ45UMDWSRk1gTV/BwVfSoXksJ9UlnD3SelTGeAkvbDqtDllqlp9y6c3qQcmZUE348Xl4hDTkU8upZwswCFQ== integrity sha512-+6+m/DKMnfkeQiWUsMlB6Da8u6yREyN2oQYGYhSRAK8419ym8RHHrqKJv2AClI4iLq2ppHZj8WF84+SeoCekRg==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
"@fortawesome/fontawesome-free" "^5.13.0" "@fortawesome/fontawesome-free" "^5.13.0"
"@abp/jquery-form@~4.0.0": "@abp/jquery-form@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-4.0.0.tgz#3afb41eb16d62e32c31a29c6a866f634a5a20cd8" resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-4.0.1.tgz#6dc1922b2800dd635f20881a82e08104a1dd1bb5"
integrity sha512-cQq8PgzHfpK9/LxmjlnMsDn85wWvEOqjyLaepHFpTTt0341auSgXNwhp7rk71AUHD1lP3c9ALctmqu+gYmh9ag== integrity sha512-JMBZYu/MI/GjaLTBOMB5iv8cagnLpReDULNC3r6tLNNqB1R8f3Cg1T7nF4YCuU9SYMqis1P/AuE4oEh+4rQdAQ==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
jquery-form "^4.3.0" jquery-form "^4.3.0"
"@abp/jquery-validation-unobtrusive@~4.0.0": "@abp/jquery-validation-unobtrusive@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-4.0.0.tgz#c3674d2b01b3c524de4c3fac1c6ae3657857ee7b" resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-4.0.1.tgz#4142ca31c0830fe24a1467e8cf13b55ba9d7c1dd"
integrity sha512-OGibIdw0ogjp6VQIebHM7OtMT36pjLKRrOHyCVpTmQ7NzDODV5ptG83vOnt5nFG0y9XFrOt8cnHrrd+K1Bpo/Q== integrity sha512-rdSRTcdKCHmarbrVgmPYdTiJ0G/aFKd+dr0krO7fALPTuQKChbDnHOO4/JvQSc+cd9faxa8c6ZWvlHdsof23tQ==
dependencies: dependencies:
"@abp/jquery-validation" "~4.0.0" "@abp/jquery-validation" "~4.0.1"
jquery-validation-unobtrusive "^3.2.11" jquery-validation-unobtrusive "^3.2.11"
"@abp/jquery-validation@~4.0.0": "@abp/jquery-validation@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-4.0.0.tgz#0a101937f89ff398317142b5271fa9a1de6571c2" resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-4.0.1.tgz#74e7d795468c6986f2db15662631fcd4f67c679e"
integrity sha512-4nzvhAktEINpQ2H+Hy7TOxxojTmTEm5dBTbHs1vbCWUuF0OTpouZWbMZDESdP0ZbjXcQ+vhwuM4e/pm/PeaHyQ== integrity sha512-FX26aQCsMBdVWAJb7S37Lt7KoHAEHoYguh/qfZIARCpOYOOWvxfDz1wTrmADUkqdillqEiCeD/Imj8bYH9Faaw==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
jquery-validation "^1.19.2" jquery-validation "^1.19.2"
"@abp/jquery@~4.0.0": "@abp/jquery@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-4.0.0.tgz#00d24678b573bcc2fb14d8337ccdbf697b59d43b" resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-4.0.1.tgz#aa554accb16600fd586c3a4f088040cd26d0bde8"
integrity sha512-gXLK97IvAZriNlG8e0qJcd7MvnpshJQURb4lg8VYibD7Fs/OBeHSAWM2Adgi3H9DnQL8XEUlWf487FSz4RC/Yg== integrity sha512-MtiRKOLyjEWux+whPP3+zwPbpj8or756JtgjnwOTDB9tp9HLCYUaskt+oalYPvob24nDZcNu2RnMALYdCVhZAQ==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
jquery "~3.5.1" jquery "~3.5.1"
"@abp/lodash@~4.0.0": "@abp/lodash@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-4.0.0.tgz#fe76d09517f6b1adf18edde94a31e13b003329dc" resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-4.0.1.tgz#ec261ccaab8a70d5b32a8a7c22387e48936d38d4"
integrity sha512-uitn5uYlb9xShRtV4AFOgp3lu2kADGMD4+a4fy5r4umlPM2uuMo0wMhzyYdBIG64JC5oNaqAzOwZyhhnn+HGJg== integrity sha512-Dav1QKbBeGR4VVbHHe1s3OEzN7wnb9K/vwzHrWmtO8D1Q5Z3433xjNmgL5VQ9gfxXqooSfEO4gAovZklMDHDew==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
lodash "^4.17.15" lodash "^4.17.15"
"@abp/luxon@~4.0.0": "@abp/luxon@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-4.0.0.tgz#d9357e4fb422b6e18ebe897a86a4c4bc6fbe6858" resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-4.0.1.tgz#a540750b1605dbac856ce9c2e776c2fecf6392f9"
integrity sha512-tiE6NiSa4El88SVotxfmmpceINLz8MruaO/e/U3QjJEHjRoqlv0UBrM/x5Xz92c7ZIvL0Y4QvWNISeDg6/oqIQ== integrity sha512-eRumVB7UIf2XH6OZVUTvcKw0A/OSAfYV59fM+Wc4dAkNcmsNZI0gD1o0AigSGNCxTV6v+W2bFrsuooSqK99Y0Q==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
luxon "^1.24.1" luxon "^1.24.1"
"@abp/malihu-custom-scrollbar-plugin@~4.0.0": "@abp/malihu-custom-scrollbar-plugin@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-4.0.0.tgz#972acf26f5eaa4bf9b8991cbe7c19fd0005d94e2" resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-4.0.1.tgz#0a556423a67b6c949e32ffcacd72256dea6c31ee"
integrity sha512-SpUo1CfppKzkE6Rb880pgB7oQ83Mkjsi0o6eE4r4gkF5hfzkuCXOmNjTYKfQIkE4n3G9QQd+8AAN/4xj4DiDrA== integrity sha512-YTwYpnQ1ZrON70gvJcnNZRwB3Ze4olGcXxiPvmRgSHbGJkSnHYJiP6PvsN1F3HDFukAJ/iUu+WwEe8OBwlyLXA==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
malihu-custom-scrollbar-plugin "^3.1.5" malihu-custom-scrollbar-plugin "^3.1.5"
"@abp/prismjs@^4.0.0": "@abp/prismjs@^4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-4.0.0.tgz#7b98c233ac1f0025c14b27c1ba62910bd9022442" resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-4.0.1.tgz#8e614878a9d1d63504fe7ba6b7d44093947d862b"
integrity sha512-Eh63EUe2wnl8P1iyPo9Glt9BD6yFdrAjIbvBeFheJnSWgvij3mayOtCAq9P2ksKWo1Gq3hv1lm/p9vdYFRHoKw== integrity sha512-qZP4TlQDiXaAIrDmpzQJeL/9mtTCxQCIbELDnBHMZFDrYNENOKZeBmvD9WAhgzL7FJcnPtOomJgZ5x2rqpBW/w==
dependencies: dependencies:
"@abp/clipboard" "~4.0.0" "@abp/clipboard" "~4.0.1"
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
prismjs "^1.20.0" prismjs "^1.20.0"
"@abp/select2@~4.0.0": "@abp/select2@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-4.0.0.tgz#8fdf4c5e18f4093ee4e073dab950cf7aa9b2a540" resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-4.0.1.tgz#8983e7b5c3afb862f08b2730b70e59d726e9b5d5"
integrity sha512-XeXahcDMczdkZdP07yhQriIvbi1N5meeSGTnFyZX+bNTGzUOarPcuNYZ6Mcl3351HcyESHzuJbKbsk3RB1kGeg== integrity sha512-WdzY2hvsS/4vz/VXpxq2muSzzE8ggchiIrICy/WKchJxL9L08DM796t6aE6rEl9wucY8XEzzWrPOVqAjJmnXFA==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
select2 "^4.0.13" select2 "^4.0.13"
"@abp/sweetalert@~4.0.0": "@abp/sweetalert@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/sweetalert/-/sweetalert-4.0.0.tgz#0d93e92e95c6855aef7e19532a7513a078ece216" resolved "https://registry.yarnpkg.com/@abp/sweetalert/-/sweetalert-4.0.1.tgz#0088610915ad6db0a140b77832a37c10066eb4ee"
integrity sha512-y3XtZqnUVZuQohpRO1ImyBZXhtrm4H+typIL/9VgcnlvQjBTyIaiwDmU8j07Bb2rKJKe0prVkkVARO7OnjOS5A== integrity sha512-t4/44oQCMngSjVqmeRWXwrXa/pRKc3CEpyyTiGIXki4dWJ21j0ePCw2l3rvOJWnpoCznhxa/UGxLfRfK1NEzRg==
dependencies: dependencies:
"@abp/core" "~4.0.0" "@abp/core" "~4.0.1"
sweetalert "^2.1.2" sweetalert "^2.1.2"
"@abp/timeago@~4.0.0": "@abp/timeago@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-4.0.0.tgz#509cd8a84cd94c2644824b0c3af10c8fff6de2dc" resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-4.0.1.tgz#8c161645534eb1f62fe4607450acf7345729e711"
integrity sha512-90jzLYJusYTPwMbak1+XkXE85OPOXPpysRbL28KQwl7WLNBm8wx6IEoVZOHvOrpYscYdyeWhZCgILSJ8DR3a2Q== integrity sha512-PsPobV79U2qzVY+WBsmJM1ohSF4jqcLnL4/7qyJvxlb1WwbCl1F5D4cpiJP4zsM4clPW4mbSsiauMNp+HTNKEA==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
timeago "^1.6.7" timeago "^1.6.7"
"@abp/toastr@~4.0.0": "@abp/toastr@~4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-4.0.0.tgz#06e28665cb7f6eefee3f69c985dd2b3f86cd7f1d" resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-4.0.1.tgz#ecb6f6193b7edc3150d0614ab9457472baf1cce3"
integrity sha512-YL1fahVpDszhwpnRTN87GCP523Mkaw42ApT2A/hZuBdwRzP/u5GwRfng0i/uhdYXCMkTKuHmaHnRyqhGiv7nfQ== integrity sha512-bTTz0O8zj7fMhdoummP2Ed5Z8SJTmR6svzNchBXNDrnRAcDQvTihPTcg0UpH8BEDFczbLowq09CG2A/RMSJoug==
dependencies: dependencies:
"@abp/jquery" "~4.0.0" "@abp/jquery" "~4.0.1"
toastr "^2.1.4" toastr "^2.1.4"
"@abp/utils@^4.0.0": "@abp/utils@^4.0.1":
version "4.0.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-4.0.0.tgz#6c2b5f5c20821028fe6cdbffb5e2f6088956b9d5" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-4.0.1.tgz#9a4cb420266c49d8084776bd31c86681d4d4d125"
integrity sha512-Yj2yCObvS6X/P8rdRMQBo7940k5P/dZhgCUSo9C6P9GNmJY8wNdJFFyhRtaHuAyU5IBBBIY7+mMKOk5eQcbjWQ== integrity sha512-nI2ZyaNpvohr75p8jeMPWze+hX+mV47EHI+Zloa4GgGmJqrULdG71kYh45R+jGmMTbQL6huaXGnpz4gNF9TGyQ==
dependencies: dependencies:
just-compare "^1.3.0" just-compare "^1.3.0"

2
framework/test/Volo.Abp.AspNetCore.Serilog.Tests/Volo.Abp.AspNetCore.Serilog.Tests.csproj

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup> </ItemGroup>

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

@ -88,10 +88,10 @@ namespace Volo.Abp.AspNetCore.Serilog
executedLogEvent.ShouldNotBeNull(); executedLogEvent.ShouldNotBeNull();
executedLogEvent.Properties.ContainsKey(_serilogOptions.EnricherPropertyNames.CorrelationId) executedLogEvent.Properties.ContainsKey(_serilogOptions.EnricherPropertyNames.CorrelationId)
.ShouldNotBeNull(); .ShouldBeTrue();
((ScalarValue) executedLogEvent.Properties[_serilogOptions.EnricherPropertyNames.CorrelationId]).Value ((ScalarValue) executedLogEvent.Properties[_serilogOptions.EnricherPropertyNames.CorrelationId]).Value
.ShouldBe(result); .ShouldBe(result);
} }
} }
} }

5
framework/test/Volo.Abp.TextTemplating.Tests/Volo.Abp.TextTemplating.Tests.csproj

@ -10,8 +10,9 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Volo\Abp\TextTemplating\Localization\**\*.json" /> <EmbeddedResource Include="Volo\Abp\TextTemplating\Localization\**\*.json" />
<None Remove="Volo\Abp\TextTemplating\Localization\**\*.json" /> <None Remove="Volo\Abp\TextTemplating\Localization\**\*.json" />
<EmbeddedResource Include="Volo\Abp\TextTemplating\SampleTemplates\**\*.tpl" /> <EmbeddedResource Include="Volo\Abp\TextTemplating\SampleTemplates\**\*.tpl">
<None Remove="Volo\Abp\TextTemplating\SampleTemplates\**\*.tpl" /> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

Loading…
Cancel
Save