Browse Source

Merge branch 'dev' into ShouldChangePasswordOnNextLogin

pull/15708/head
maliming 4 years ago
parent
commit
5f50946758
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  2. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  3. 36
      docs/en/Background-Jobs.md
  4. 44
      docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/POST.md
  5. BIN
      docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part1.gif
  6. BIN
      docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part2.gif
  7. BIN
      docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part3.gif
  8. 2
      docs/en/Distributed-Event-Bus.md
  9. 230
      docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md
  10. 4
      docs/en/Modules/Database-Tables.md
  11. 6
      docs/en/Modules/IdentityServer.md
  12. 2
      docs/en/UI/Angular/Quick-Start.md
  13. 6
      docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md
  14. 20
      docs/en/docs-nav.json
  15. 5
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyOptions.cs
  16. 16
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  17. 4
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs
  18. 5
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs
  19. 3
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs
  20. 19
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs
  21. 3
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs
  22. 4
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs
  23. 10
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs
  24. 8
      framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs
  25. 9
      framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs
  26. 2
      framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs
  27. 3
      framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs
  28. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  29. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs
  30. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlerBase.cs
  31. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliConsts.cs
  32. 55
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs
  33. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliUrls.cs
  34. 12
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CliCommand.cs
  35. 12
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs
  36. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClientFactory.cs
  37. 38
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs
  38. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/CommercialPackages.cs
  39. 16
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/LatestVersionInfo.cs
  40. 84
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/PackageVersionCheckerService.cs
  41. 1
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs
  42. 28
      framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs
  43. 14
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/StaticProxying/AbpHttpClientStaticProxyingOptions.cs
  44. 4
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
  45. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json
  46. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json
  47. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json
  48. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json
  49. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json
  50. 5
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json
  51. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json
  52. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json
  53. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json
  54. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json
  55. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json
  56. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json
  57. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json
  58. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json
  59. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json
  60. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json
  61. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json
  62. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json
  63. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json
  64. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json
  65. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json
  66. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json
  67. 5
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json
  68. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json
  69. 5
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json
  70. 3
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json
  71. 26
      framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests.cs
  72. 49
      framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs
  73. 19
      framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs
  74. 19
      framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs
  75. 8
      latest-versions.json
  76. 9
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs
  77. 31
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs
  78. 26
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs
  79. 9
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs
  80. 49
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs
  81. 8
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs
  82. 1
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs
  83. 1
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs
  84. 11
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs
  85. 10
      modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs
  86. 2
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json
  87. 2703
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock
  88. 4
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json
  89. 2759
      modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock
  90. 4
      modules/blogging/app/Volo.BloggingTestApp/package.json
  91. 2889
      modules/blogging/app/Volo.BloggingTestApp/yarn.lock
  92. 4
      modules/blogging/src/Volo.Blogging.Admin.Web/Navigation/BloggingAdminMenuContributor.cs
  93. 8
      modules/blogging/src/Volo.Blogging.Admin.Web/Navigation/BloggingAdminMenuNames.cs
  94. 6
      modules/blogging/src/Volo.Blogging.Admin.Web/Pages/Blogging/Admin/Blogs/Index.cshtml
  95. 3
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml.cs
  96. 2
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs
  97. 2
      modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json
  98. 2674
      modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock
  99. 10
      modules/cms-kit/angular/package.json
  100. 4
      modules/cms-kit/angular/projects/cms-kit/package.json

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

@ -27,6 +27,7 @@
"Volo.AbpIo.Domain:030010": "To purchase the trial license, you first need to activate your trial license!",
"Volo.AbpIo.Domain:030011": "You cannot delete a trial license when it is purchased!",
"Volo.AbpIo.Domain:030012": "A user is entitled to have only 1 free trial period. You already used your trial license.",
"Volo.AbpIo.Domain:030013": "A user with an active license cannot start a trial license.",
"Volo.AbpIo.Domain:070000": "The organization name can only contain latin letters, numbers, dots and hyphens!",
"Volo.AbpIo.Domain:070001": "The company name can only contain latin letters, numbers, dots, space and hyphens!",
"WantToLearn?": "Want to learn?",
@ -205,6 +206,8 @@
"Icons": "Icons",
"Url": "Url",
"Icon": "Icon",
"RecentActivities": "Recent Activities"
"RecentActivities": "Recent Activities",
"SpringCampaign": "Welcome <br>Spring Sale!",
"SpringCampaign2": "<span>Limited <br> Time Offer!</span>"
}
}

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

@ -196,7 +196,7 @@
"ChangingDevelopers": "Can I change the registered developers of my organization in the future?",
"ChangingDevelopersExplanation": "In addition to adding new developers to your license, you can also change the existing developers (you can remove a developer and add a new one to the same seat) without any additional cost.",
"WhatHappensWhenLicenseEnds": "What happens when my license period ends?",
"WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a <a href=\"{0}\" target=\"_blank\">perpetual license</a>. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires, you will not get the following benefits:",
"WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a <a href=\"{0}\" target=\"_blank\">perpetual license</a>. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires;",
"WhatHappensWhenLicenseEndsExplanation2": "You can not create new solutions using the ABP Commercial, but you can continue developing your existing applications forever.",
"WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MINOR version (except RC or Preview versions). For example: if you are using v3.2.0 of a module, you can still get updates for v3.2.x (v3.2.1, v3.2.5... etc.) of that module. But you cannot get updates for the next major or minor version (like v3.3.0, v3.3.3, 4.x.x.. etc.). For example, when your license expired, the latest release was v4.4.3, and later, it published both 4.4.4 version and 4.5.0 version, you would be able to access the v4.4.X but you wouldn't be access the v4.5.X.",
"WhatHappensWhenLicenseEndsExplanation4": "You can not install new modules and themes added to the ABP Commercial platform after your license ends.",
@ -818,6 +818,7 @@
"DeletingMemberWarningMessage": "\"{0}\" will be removed from the developer list. If you want, you can assign this empty seat to another developer later.",
"AdditionalInfo": "If the developer seats are above your requirements, you can reduce them. You can email at <a href=\"mailto:info@abp.io\">info@abp.io</a> to remove some of your developer seats. Clearing unused developer seats will reduce the license renewal cost. If you want, you can re-purchase additional developer seats within your active license period. Note that, since there are {0} developers in this license package, you cannot reduce this number.",
"LinkExpiredErrorMessage": "The link you are trying to access is expired.",
"ExpirationDate": "Expiration Date"
"ExpirationDate": "Expiration Date",
"SpringCampaignDiscount": "Spring Campaign Discount"
}
}

36
docs/en/Background-Jobs.md

@ -75,6 +75,42 @@ This job simply uses `IEmailSender` to send emails (see [email sending document]
A background job should not hide exceptions. If it throws an exception, the background job is automatically re-tried after a calculated waiting time. Hide exceptions only if you don't want to re-run the background job for the current argument.
#### Cancelling Background Jobs
If your background task is cancellable, then you can use the standard [Cancellation Token](Cancellation-Token-Provider.md) system to obtain a `CancellationToken` to cancel your job when requested. See the following example that uses the `ICancellationTokenProvider` to obtain the cancellation token:
```csharp
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace MyProject
{
public class LongRunningJob : AsyncBackgroundJob<LongRunningJobArgs>, ITransientDependency
{
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public LongRunningJob(ICancellationTokenProvider cancellationTokenProvider)
{
_cancellationTokenProvider = cancellationTokenProvider;
}
public override async Task ExecuteAsync(LongRunningJobArgs args)
{
foreach (var id in args.Ids)
{
_cancellationTokenProvider.Token.ThrowIfCancellationRequested();
await ProcessAsync(id); // code omitted for brevity
}
}
}
}
```
> A cancellation operation might be needed if the application is shutting down and we don't want to block the application in the background job. This example throws an exception if the cancellation is requested. So, the job will be retried the next time the application starts. If you don't want that, just return from the `ExecuteAsync` method without throwing any exception (you can simply check the `_cancellationTokenProvider.Token.IsCancellationRequested` property).
#### Job Name
Each background job has a name. Job names are used in several places. For example, RabbitMQ provider uses job names to determine the RabbitMQ Queue names.

44
docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/POST.md

@ -0,0 +1,44 @@
## Streamline Localization in Your ABP Project
Making localization changes to an ABP project can be a daunting task, especially if you're dealing with multiple languages and translations. During development, it's easy to overlook some changes and that leads to inconsistencies across different languages. Fortunately, I have developed a tool that can help streamline the localization process and ensure consistency across different languages.
The tool is a console application that uses JSON files to manage localization keys and their translations. It addresses three common scenarios that can arise during localization:
1. When the argument count of a key changes, it can be difficult to update the translations for all languages. My tool solves this problem by scanning all JSON files in the project folder and identifying any keys that have mismatched argument counts. It then offers two options to the user: delete the mismatched translations or export them as a JSON file for manual editing.
2. When a new key is added to the project, forgetting to add its translations to all the other languages is easy. My tool helps to avoid this issue by scanning the default language's JSON file and identifying any keys that don't have translations in other languages. It then exports these keys as a JSON file that can be used to add missing translations.
3. When a key's name is changed, it's important to update its translations in all the other languages. My tool makes this task simple by scanning all the JSON files in the project folder and updating any translations of the old key name with the new one.
The tool also includes an export feature that allows users to modify translations outside of the application and import them back into the JSON files.
## How it Helps
With my Localization Key Synchronizer tool, you can perform complex localization changes more quickly and easily than by manually sifting through files and making changes one-by-one. This can save you significant time and effort, especially if you're working with a large number of languages or translations.
## How it Works
When you run the Localization Key Synchronizer tool, it presents you with three options:
1. Find Asynchronous Keys
2. Apply Changes in the Exported File
3. Replace Keys
If you select "Find Asynchronous Keys," the tool prompts you to enter the default language path. Once you've entered the path, the tool displays all of the JSON files in the same folder as a multi-select list. After selecting one or more files, you are asked whether you want to find keys that do not match the number of arguments, missing keys, or both. If you select "Missing Keys," the tool prompts you to enter the absolute path to export the missing keys. After you've entered the path, the export process starts, and the tool closes.
![](./images/Part1.gif)
If you select "Apply Changes in the Exported File" at the main menu, the tool prompts you to enter the path to the exported file. After you've entered the path, the import process starts, and the tool closes.
![](./images/Part2.gif)
If you select "Replace Keys," the tool prompts you to enter the localization folder path, the old key, the new key, and the JSON files to apply the changes to. Once you've entered all the required information and made your selections, the tool performs the replacements and closes.
![](./images/Part3.gif)
## Conclusion
If you're struggling to manage localization changes in an ABP project, give my Localization Key Synchronizer tool a try. It can help streamline your workflow and make the process much more manageable. You can find the tool on [GitHub](https://github.com/abpframework/abp/tree/dev/tools/localization-key-synchronizer).
To use the tool, simply run the console application and follow the prompts. It's a user-friendly solution that helps to ensure localization consistency in your ABP project. Give it a try and let me know what you think!

BIN
docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part1.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

BIN
docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part2.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part3.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

2
docs/en/Distributed-Event-Bus.md

@ -306,7 +306,7 @@ Assume that there is a `Product` entity (probably an aggregate root entity) in a
The first step to establish the synchronization is to define an ETO (Event Transfer Object) class in the Catalog microservice that is used to transfer the event data. Assuming the `Product` entity has a `Guid` key, your ETO can be as shown below:
````
````csharp
[EventName("product")]
public class ProductEto : EntityEto<Guid>
{

230
docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md

@ -0,0 +1,230 @@
# Migrating from OpenIddict to IdentityServer4 Step by Step Guide
ABP startup templates use `OpenIddict` OpenID provider from v6.0.0 by default and `IdentityServer` projects are renamed to `AuthServer` in tiered/separated solutions. Since OpenIddict is the default OpenID provider library for ABP templates since v6.0, you may want to keep using [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) library, even it is **archived and no longer maintained by the owners**. ABP doesn't provide support for newer versions of IdentityServer. This guide provides layer-by-layer guidance for migrating your existing [OpenIddict](https://github.com/openiddict/openiddict-core) application to IdentityServer4.
## IdentityServer4 Migration Steps
Use the `abp update` command to update your existing application. See [Upgrading docs](../Upgrading.md) for more info. Apply required migrations by following the [Migration Guides](Index.md) based on your application version.
### Domain.Shared Layer
- In **MyApplication.Domain.Shared.csproj** replace **project reference**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.Domain.Shared" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.Domain.Shared" Version="6.0.*" />
```
- In **MyApplicationDomainSharedModule.cs** replace usings and **module dependencies:**
```csharp
using Volo.Abp.OpenIddict;
...
typeof(AbpOpenIddictDomainSharedModule)
```
with
```csharp
using Volo.Abp.IdentityServer;
...
typeof(AbpIdentityServerDomainSharedModule)
```
### Domain Layer
- In **MyApplication.Domain.csproj** replace **project references**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.Domain" Version="6.0.*" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.OpenIddict" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.Domain" Version="6.0.*" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.IdentityServer" Version="6.0.*" />
```
- In **MyApplicationDomainModule.cs** replace usings and **module dependencies**:
```csharp
using Volo.Abp.OpenIddict;
using Volo.Abp.PermissionManagement.OpenIddict;
...
typeof(AbpOpenIddictDomainModule),
typeof(AbpPermissionManagementDomainOpenIddictModule),
```
with
```csharp
using Volo.Abp.IdentityServer;
using Volo.Abp.PermissionManagement.IdentityServer;
...
typeof(AbpIdentityServerDomainModule),
typeof(AbpPermissionManagementDomainIdentityServerModule),
```
#### OpenIddictDataSeedContributor
DataSeeder is the most important part for starting the application since it seeds the initial data for both OpenID providers.
- Create a folder named *IdentityServer* under the Domain project and copy the [IdentityServerDataSeedContributor.cs](https://github.com/abpframework/abp-samples/blob/master/Ids2OpenId/src/Ids2OpenId.Domain/IdentityServer/IdentityServerDataSeedContributor.cs) under this folder. **Rename** all the `OpenId2Ids` with your project name.
- Delete *OpenIddict* folder that contains `OpenIddictDataSeedContributor.cs` which is no longer needed.
### EntityFrameworkCore Layer
If you are using MongoDB, skip this step and check the *MongoDB* layer section.
- In **MyApplication.EntityFrameworkCore.csproj** replace **project reference**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.EntityFrameworkCore" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.EntityFrameworkCore" Version="6.0.*" />
```
- In **MyApplicationEntityFrameworkCoreModule.cs** replace usings and **module dependencies**:
```csharp
using Volo.Abp.OpenIddict.EntityFrameworkCore;
...
typeof(AbpOpenIddictEntityFrameworkCoreModule),
```
with
```csharp
using Volo.Abp.IdentityServer.EntityFrameworkCore;
...
typeof(AbpIdentityServerEntityFrameworkCoreModule),
```
- In **MyApplicationDbContext.cs** replace usings and **fluent api configurations**:
```csharp
using Volo.Abp.OpenIddict.EntityFrameworkCore;
...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
...
builder.ConfigureOpenIddict();
```
with
```csharp
using Volo.Abp.IdentityServer.EntityFrameworkCore;
...
using Volo.Abp.OpenIddict.EntityFrameworkCore;
...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
...
builder.ConfigureIdentityServer();
```
> Not: You need to create new migration after updating the fluent api. Navigate to *EntityFrameworkCore* folder and add a new migration. Ex, `dotnet ef migrations add Updated_To_IdentityServer `
### MongoDB Layer
If you are using EntityFrameworkCore, skip this step and check the *EntityFrameworkCore* layer section.
- In **MyApplication.MongoDB.csproj** replace **project reference**:
```csharp
<PackageReference Include="Volo.Abp.OpenIddict.MongoDB" Version="6.0.*" />
```
with
```csharp
<PackageReference Include="Volo.Abp.IdentityServer.MongoDB" Version="6.0.*" />
```
- In **MyApplicationMongoDbModule.cs** replace usings and **module dependencies**:
```csharp
using Volo.Abp.OpenIddict.MongoDB;
...
typeof(AbpOpenIddictMongoDbModule),
```
with
```csharp
using Volo.Abp.IdentityServer.MongoDB;
...
typeof(AbpIdentityServerMongoDbModule),
```
### DbMigrator Project
- In `appsettings.json` **replace OpenIddict section with IdentityServer** since IdentityServerDataSeeder will be using these information for initial data seeding:
```json
"IdentityServer": { // Rename OpenIddict to IdentityServer
"Clients ": { // Rename Applications to Clients
...
}
}
```
### Test Project
- In **MyApplicationTestBaseModule.cs** **add** the IdentityServer related using and PreConfigurations:
```csharp
using Volo.Abp.IdentityServer;
```
and
```csharp
PreConfigure<AbpIdentityServerBuilderOptions>(options =>
{
options.AddDeveloperSigningCredential = false;
});
PreConfigure<IIdentityServerBuilder>(identityServerBuilder =>
{
identityServerBuilder.AddDeveloperSigningCredential(false, System.Guid.NewGuid().ToString());
});
```
to `PreConfigureServices` to run authentication related unit tests.
### UI Layer
You can follow the migrations guides from IdentityServer to OpenIddict in **reverse order** to update your UIs. You can also check the source-code for [Index.cshtml.cs](https://github.com/abpframework/abp-samples/blob/master/OpenId2Ids/src/OpenId2Ids.AuthServer/Pages/Index.cshtml) and [Index.cshtml](https://github.com/abpframework/abp-samples/blob/master/OpenId2Ids/src/OpenId2Ids.AuthServer/Pages/Index.cshtml.cs) files for **AuthServer** project.
- [Angular UI Migration](OpenIddict-Angular.md)
- [MVC/Razor UI Migration](OpenIddict-Mvc.md)
- [Blazor-Server UI Migration](OpenIddict-Blazor-Server.md)
- [Blazor-Wasm UI Migration](OpenIddict-Blazor.md)
## Source code of samples and module
* [Open source tiered & separate auth server application migrate OpenIddict to Identity Server](https://github.com/abpframework/abp-samples/tree/master/OpenId2Ids)
* [IdentityServer module document](https://docs.abp.io/en/abp/6.0/Modules/IdentityServer)
* [IdentityServer module source code](https://github.com/abpframework/abp/tree/rel-6.0/modules/identityserver)

4
docs/en/Modules/Database-Tables.md

@ -32,7 +32,7 @@ This table stores information about entity changes in the application, which are
This table stores information about property changes to entities in the application, which are logged for auditing purposes.
## Uses
#### Foreign Keys
| Table | Column | Description |
| --- | --- | --- |
@ -54,7 +54,7 @@ This table stores information about the tenants. Each record represents a tenant
This table stores information about the tenant database connection strings. When you define a connection string for a tenant, a new record will be added to this table. You can query this database to get connection strings by tenants.
## Uses
#### Foreign Keys
| Table | Column | Description |
| --- | --- | --- |

6
docs/en/Modules/IdentityServer.md

@ -1,10 +1,12 @@
# IdentityServer Module
IdentityServer module provides a full integration with the [IdentityServer](https://github.com/IdentityServer/IdentityServer4) (IDS) framework, which provides advanced authentication features like single sign-on and API access control. This module persists clients, resources and other IDS-related objects to database.
IdentityServer module provides a full integration with the [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) (IDS) framework, which provides advanced authentication features like single sign-on and API access control. This module persists clients, resources and other IDS-related objects to database. **This module is replaced by** [OpenIddict module](https://docs.abp.io/en/abp/latest/Modules/OpenIddict) after ABP v6.0 in the startup templates.
> Note: You can not use IdentityServer and OpenIddict modules together. They are separate OpenID provider libraries for the same job.
## How to Install
This module comes as pre-installed (as NuGet/NPM packages). You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module.
You don't need this module when you are using OpenIddict module. However, if you want to keep using IdentityServer4 for your applications, you can install this module and remove the OpenIddict module. You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module.
### The Source Code

2
docs/en/UI/Angular/Quick-Start.md

@ -179,7 +179,7 @@ This command will download and start a simple static server, a browser window at
Of course, you need your application to run on an optimized web server and become available to everyone. This is quite straight-forward:
1. Create a new static web server instance. You can use a service like [Azure App Service](https://azure.microsoft.com/tr-tr/services/app-service/web/), [Firebase](https://firebase.google.com/docs/hosting), [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), or even [GitHub Pages](https://angular.io/guide/deployment#deploy-to-github-pages). Another option is maintaining own web server with [NGINX](https://www.nginx.com/), [IIS](https://www.iis.net/), [Apache HTTP Server](https://httpd.apache.org/), or equivalent.
1. Create a new static web server instance. You can use a service like [Azure App Service](https://azure.microsoft.com/en-us/services/app-service/web/), [Firebase](https://firebase.google.com/docs/hosting), [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), or even [GitHub Pages](https://angular.io/guide/deployment#deploy-to-github-pages). Another option is maintaining own web server with [NGINX](https://www.nginx.com/), [IIS](https://www.iis.net/), [Apache HTTP Server](https://httpd.apache.org/), or equivalent.
2. Copy the files from `dist/MyProjectName` <sup id="a-dist-folder-name">[1](#f-dist-folder-name)</sup> to a publicly served destination on the server via CLI of the service provider, SSH, or FTP (whichever is available). This step would be defined as a job if you have a CI/CD flow.
3. [Configure the server](https://angular.io/guide/deployment#server-configuration) to redirect all requests to the _index.html_ file. Some services do that automatically. Others require you [to add a file to the bundle via assets](https://angular.io/guide/workspace-config#assets-configuration) which describes the server how to do the redirections. Occasionally, you may need to do manual configuration.

6
docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md

@ -10,7 +10,7 @@ See the [form elements demo page](https://bootstrap-taghelpers.abp.io/Components
## abp-input
`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`.
`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`.
Usage:
@ -88,7 +88,7 @@ You can set some of the attributes on your c# property, or directly on html tag.
* `label`: Sets the label for input.
* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`.
`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) are also valid for `abp-input` tag helper.
`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) are also valid for `abp-input` tag helper.
### Label & Localization
@ -100,7 +100,7 @@ You can set label of your input in different ways:
## abp-select
`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`.
`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`.
`abp-select` tag needs a list of `Microsoft.AspNetCore.Mvc.Rendering.SelectListItem ` to work. It can be provided by `asp-items` attriube on the tag or `[SelectItems()]` attribute on c# property. (if you are using [abp-dynamic-form](Dynamic-forms.md), c# attribute is the only way.)

20
docs/en/docs-nav.json

@ -1370,16 +1370,22 @@
},
{
"text": "IdentityServer",
"path": "Modules/IdentityServer.md"
"path": "Modules/IdentityServer.md",
"items": [
{
"text": "IdentityServer Migration Guide",
"path": "Migration-Guides/IdentityServer4-Step-by-Step.md"
}
]
},
{
"text": "OpenIddict",
"items": [
{
"text": "OpenIddict Migration Guide",
"path": "Migration-Guides/OpenIddict-Step-by-Step.md"
}
],
"items": [
{
"text": "OpenIddict Migration Guide",
"path": "Migration-Guides/OpenIddict-Step-by-Step.md"
}
],
"path": "Modules/OpenIddict.md"
},
{

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

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Net;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
@ -42,8 +43,8 @@ public class AbpAspNetCoreMultiTenancyOptions
var message = exception.Message;
var details = exception is BusinessException businessException ? businessException.Details : string.Empty;
await context.Response.WriteAsync($"<html lang=\"{CultureInfo.CurrentCulture.Name}\"><body>\r\n");
await context.Response.WriteAsync($"<h3>{message}</h3>{details}<br>\r\n");
await context.Response.WriteAsync($"<html lang=\"{HtmlEncoder.Default.Encode(CultureInfo.CurrentCulture.Name)}\"><body>\r\n");
await context.Response.WriteAsync($"<h3>{HtmlEncoder.Default.Encode(message)}</h3>{HtmlEncoder.Default.Encode(details)}<br>\r\n");
await context.Response.WriteAsync("</body></html>\r\n");
// Note the 500 spaces are to work around an IE 'feature'

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

@ -43,6 +43,7 @@ using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Validation.Localization;
namespace Volo.Abp.AspNetCore.Mvc;
@ -174,10 +175,17 @@ public class AbpAspNetCoreMvcModule : AbpModule
context.Services.Replace(ServiceDescriptor.Singleton<IValidationAttributeAdapterProvider, AbpValidationAttributeAdapterProvider>());
context.Services.AddSingleton<ValidationAttributeAdapterProvider>();
Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(context.Services);
});
context.Services.AddOptions<MvcOptions>()
.Configure<IServiceProvider>((mvcOptions, serviceProvider) =>
{
mvcOptions.AddAbp(context.Services);
// serviceProvider is root service provider.
var stringLocalizer = serviceProvider.GetRequiredService<IStringLocalizer<AbpValidationResource>>();
mvcOptions.ModelBindingMessageProvider.SetValueIsInvalidAccessor(_ => stringLocalizer["The value '{0}' is invalid."]);
mvcOptions.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(() => stringLocalizer["The field must be a number."]);
mvcOptions.ModelBindingMessageProvider.SetValueMustBeANumberAccessor(value => stringLocalizer["The field {0} must be a number.", value]);
});
Configure<AbpEndpointRouterOptions>(options =>
{

4
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.Auditing;
@ -76,7 +77,8 @@ public class AbpAuditingOptions
IgnoredTypes = new List<Type>
{
typeof(Stream),
typeof(Expression)
typeof(Expression),
typeof(CancellationToken)
};
EntityHistorySelectors = new EntityHistorySelectorList();

5
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -6,7 +7,7 @@ namespace Volo.Abp.BackgroundJobs;
public abstract class AsyncBackgroundJob<TArgs> : IAsyncBackgroundJob<TArgs>
{
//TODO: Add UOW, Localization and other useful properties..?
//TODO: Add UOW, Localization, CancellationTokenProvider and other useful properties..?
public ILogger<AsyncBackgroundJob<TArgs>> Logger { get; set; }

3
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs

@ -1,3 +1,4 @@
using System.Threading;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -5,7 +6,7 @@ namespace Volo.Abp.BackgroundJobs;
public abstract class BackgroundJob<TArgs> : IBackgroundJob<TArgs>
{
//TODO: Add UOW, Localization and other useful properties..?
//TODO: Add UOW, Localization, CancellationTokenProvider and other useful properties..?
public ILogger<BackgroundJob<TArgs>> Logger { get; set; }

19
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs;
@ -46,13 +47,19 @@ public class BackgroundJobExecuter : IBackgroundJobExecuter, ITransientDependenc
{
using(CurrentTenant.Change(GetJobArgsTenantId(context.JobArgs)))
{
if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob<object>.ExecuteAsync))
{
await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs }));
}
else
var cancellationTokenProvider =
context.ServiceProvider.GetRequiredService<ICancellationTokenProvider>();
using (cancellationTokenProvider.Use(context.CancellationToken))
{
jobExecuteMethod.Invoke(job, new[] { context.JobArgs });
if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob<object>.ExecuteAsync))
{
await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs }));
}
else
{
jobExecuteMethod.Invoke(job, new[] { context.JobArgs });
}
}
}

3
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundJobs;

4
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs

@ -1,4 +1,6 @@
namespace Volo.Abp.BackgroundJobs;
using System.Threading;
namespace Volo.Abp.BackgroundJobs;
/// <summary>
/// Defines interface of a background job.

10
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs;
@ -11,10 +12,17 @@ public class JobExecutionContext : IServiceProviderAccessor
public object JobArgs { get; }
public JobExecutionContext(IServiceProvider serviceProvider, Type jobType, object jobArgs)
public CancellationToken CancellationToken { get; }
public JobExecutionContext(
IServiceProvider serviceProvider,
Type jobType,
object jobArgs,
CancellationToken cancellationToken = default)
{
ServiceProvider = serviceProvider;
JobType = jobType;
JobArgs = jobArgs;
CancellationToken = cancellationToken;
}
}

8
framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs

@ -12,22 +12,22 @@ namespace Volo.Abp.BackgroundJobs.Hangfire;
public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency
{
protected AbpBackgroundJobOptions Options { get; }
public HangfireBackgroundJobManager(IOptions<AbpBackgroundJobOptions> options)
{
Options = options.Value;
}
public virtual Task<string> EnqueueAsync<TArgs>(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal,
TimeSpan? delay = null)
{
return Task.FromResult(delay.HasValue
? BackgroundJob.Schedule<HangfireJobExecutionAdapter<TArgs>>(
adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)),args),
adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default),
delay.Value
)
: BackgroundJob.Enqueue<HangfireJobExecutionAdapter<TArgs>>(
adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)) ,args)
adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default)
));
}

9
framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Threading;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@ -21,8 +22,8 @@ public class HangfireJobExecutionAdapter<TArgs>
Options = options.Value;
}
[Queue("{0}")]
public async Task ExecuteAsync(string queue, TArgs args)
[Queue("{0}")]
public async Task ExecuteAsync(string queue, TArgs args, CancellationToken cancellationToken = default)
{
if (!Options.IsJobExecutionEnabled)
{
@ -38,7 +39,7 @@ public class HangfireJobExecutionAdapter<TArgs>
using (var scope = ServiceScopeFactory.CreateScope())
{
var jobType = Options.GetJob(typeof(TArgs)).JobType;
var context = new JobExecutionContext(scope.ServiceProvider, jobType, args);
var context = new JobExecutionContext(scope.ServiceProvider, jobType, args, cancellationToken: cancellationToken);
await JobExecuter.ExecuteAsync(context);
}
}

2
framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs

@ -40,7 +40,7 @@ public class QuartzJobExecutionAdapter<TArgs> : IJob
{
var args = JsonSerializer.Deserialize<TArgs>(context.JobDetail.JobDataMap.GetString(nameof(TArgs)));
var jobType = Options.GetJob(typeof(TArgs)).JobType;
var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args);
var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args, cancellationToken: context.CancellationToken);
try
{
await JobExecuter.ExecuteAsync(jobContext);

3
framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs

@ -68,7 +68,8 @@ public class BackgroundJobWorker : AsyncPeriodicBackgroundWorkerBase, IBackgroun
var context = new JobExecutionContext(
workerContext.ServiceProvider,
jobConfiguration.JobType,
jobArgs);
jobArgs,
workerContext.CancellationToken);
try
{

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

@ -29,6 +29,11 @@ public class AbpCliCoreModule : AbpModule
context.Services.AddHttpClient(CliConsts.HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => new CliHttpClientHandler());
context.Services.AddHttpClient(CliConsts.GithubHttpClientName, client =>
{
client.DefaultRequestHeaders.UserAgent.ParseAdd("MyAgent/1.0");
});
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Configure<AbpCliOptions>(options =>

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs

@ -58,7 +58,7 @@ public class AuthService : IAuthService, ITransientDependency
{
if (!response.IsSuccessStatusCode)
{
Logger.LogError("Remote server returns '{response.StatusCode}'");
Logger.LogError($"Remote server returns '{response.StatusCode}'");
return null;
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlerBase.cs

@ -109,12 +109,13 @@ public abstract class BundlerBase : IBundler, ITransientDependency
content = GetFileContent(filePath, options.Minify);
}
content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(options.Directory, "wwwroot"),
content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"),
content);
builder.AppendLine(content);
}
return builder.ToString();
}
}
@ -125,15 +126,15 @@ public abstract class BundlerBase : IBundler, ITransientDependency
foreach (var definition in bundleDefinitions)
{
var filePath = Path.Combine(definition.Source.Split('/'));
var fileFullPath = Directory.GetFiles(options.Directory, string.Empty, SearchOption.AllDirectories).FirstOrDefault(x => x.EndsWith(filePath));
if(fileFullPath == null)
{
throw new AbpException("Not found: " + definition.Source);
}
var content = GetFileContent(fileFullPath, options.Minify);
content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(options.Directory, "wwwroot"),
content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"),
content);
builder.AppendLine(content);

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

@ -10,6 +10,8 @@ public static class CliConsts
public const string HttpClientName = "AbpHttpClient";
public const string GithubHttpClientName = "GithubHttpClient";
public const string LogoutUrl = CliUrls.WwwAbpIo + "api/license/logout";
public const string LicenseCodePlaceHolder = @"<LICENSE_CODE/>";

55
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs

@ -13,7 +13,7 @@ using System.Threading.Tasks;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Memory;
using Volo.Abp.Cli.NuGet;
using Volo.Abp.Cli.Version;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IO;
@ -27,14 +27,14 @@ public class CliService : ITransientDependency
protected ICommandLineArgumentParser CommandLineArgumentParser { get; }
protected ICommandSelector CommandSelector { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected NuGetService NuGetService { get; }
protected PackageVersionCheckerService PackageVersionCheckerService { get; }
public ICmdHelper CmdHelper { get; }
public CliService(
ICommandLineArgumentParser commandLineArgumentParser,
ICommandSelector commandSelector,
IServiceScopeFactory serviceScopeFactory,
NuGetService nugetService,
PackageVersionCheckerService nugetService,
ICmdHelper cmdHelper,
MemoryService memoryService)
{
@ -42,7 +42,7 @@ public class CliService : ITransientDependency
CommandLineArgumentParser = commandLineArgumentParser;
CommandSelector = commandSelector;
ServiceScopeFactory = serviceScopeFactory;
NuGetService = nugetService;
PackageVersionCheckerService = nugetService;
CmdHelper = cmdHelper;
Logger = NullLogger<CliService>.Instance;
@ -61,6 +61,7 @@ public class CliService : ITransientDependency
await CheckCliVersionAsync(currentCliVersion);
}
#endif
try
{
if (commandLineArgs.IsCommand("prompt"))
@ -175,24 +176,22 @@ public class CliService : ITransientDependency
{
return;
}
var assembly = typeof(CliService).Assembly;
var toolPath = GetToolPath(assembly);
var updateChannel = GetUpdateChannel(currentCliVersion);
try
{
var latestVersion = await GetLatestVersion(updateChannel);
var assembly = typeof(CliService).Assembly;
var toolPath = GetToolPath(assembly);
var updateChannel = GetUpdateChannel(currentCliVersion);
if (latestVersion != null && latestVersion > currentCliVersion)
var latestVersionInfo = await GetLatestVersion(updateChannel);
if (latestVersionInfo != null && latestVersionInfo.Version > currentCliVersion)
{
LogNewVersionInfo(updateChannel, latestVersion, toolPath);
LogNewVersionInfo(updateChannel, latestVersionInfo.Version, toolPath, latestVersionInfo.Message);
}
}
catch (Exception e)
{
Logger.LogWarning("Unable to retrieve the latest version");
Logger.LogWarning(e.Message);
Logger.LogWarning("Unable to retrieve the latest version: " + e.Message);
}
}
@ -200,13 +199,17 @@ public class CliService : ITransientDependency
{
try
{
var latestTime = await _memoryService.GetAsync(CliConsts.MemoryKeys.LatestCliVersionCheckDate);
if (latestTime != null && DateTime.Now - DateTime.Parse(latestTime, CultureInfo.InvariantCulture) < TimeSpan.FromDays(1))
var latestTimeAsString = await _memoryService.GetAsync(CliConsts.MemoryKeys.LatestCliVersionCheckDate);
if (DateTime.TryParse(latestTimeAsString,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out var latestTimeParsed))
{
return false;
if (DateTime.Now.Subtract(latestTimeParsed).TotalDays < 1)
{
return false;
}
}
await _memoryService.SetAsync(CliConsts.MemoryKeys.LatestCliVersionCheckDate, DateTime.Now.ToString(CultureInfo.InvariantCulture));
return true;
@ -282,18 +285,18 @@ public class CliService : ITransientDependency
return UpdateChannel.Prerelease;
}
private async Task<SemanticVersion> GetLatestVersion(UpdateChannel updateChannel)
private async Task<LatestVersionInfo> GetLatestVersion(UpdateChannel updateChannel)
{
switch (updateChannel)
{
case UpdateChannel.Stable:
return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli");
return await PackageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Cli");
case UpdateChannel.Prerelease:
return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeReleaseCandidates: true);
return await PackageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeReleaseCandidates: true);
case UpdateChannel.Nightly:
return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true);
return await PackageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true);
default:
return default;
@ -306,11 +309,17 @@ public class CliService : ITransientDependency
return globalPaths.Select(Environment.ExpandEnvironmentVariables).Contains(toolPath);
}
private void LogNewVersionInfo(UpdateChannel updateChannel, SemanticVersion latestVersion, string toolPath)
private void LogNewVersionInfo(UpdateChannel updateChannel, SemanticVersion latestVersion, string toolPath, string message = null)
{
var toolPathArg = IsGlobalTool(toolPath) ? "-g" : $"--tool-path {toolPath}";
Logger.LogWarning($"ABP CLI has a newer {updateChannel.ToString().ToLowerInvariant()} version {latestVersion}, please update to get the latest features and fixes.");
if (!string.IsNullOrWhiteSpace(message))
{
Logger.LogWarning(message);
}
Logger.LogWarning(string.Empty);
Logger.LogWarning("Update Command: ");

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

@ -8,6 +8,8 @@ public static class CliUrls
public const string WwwAbpIo = WwwAbpIoProduction;
public const string AccountAbpIo = AccountAbpIoProduction;
public const string NuGetRootPath = NuGetRootPathProduction;
public const string LatestVersionCheckFullPath =
"https://raw.githubusercontent.com/abpframework/abp/dev/latest-versions.json";
public const string WwwAbpIoProduction = "https://abp.io/";
public const string AccountAbpIoProduction = "https://account.abp.io/";

12
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CliCommand.cs

@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.NuGet;
using Volo.Abp.Cli.Version;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
@ -18,14 +18,14 @@ public class CliCommand : IConsoleCommand, ITransientDependency
private const string CliPackageName = "Volo.Abp.Cli";
private readonly ICmdHelper _cmdHelper;
private readonly NuGetService _nuGetService;
private readonly PackageVersionCheckerService _packageVersionCheckerService;
private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService;
public ILogger<CliCommand> Logger { get; set; }
public CliCommand(ICmdHelper cmdHelper, NuGetService nuGetService, AbpNuGetIndexUrlService nuGetIndexUrlService)
public CliCommand(ICmdHelper cmdHelper, PackageVersionCheckerService packageVersionCheckerService, AbpNuGetIndexUrlService nuGetIndexUrlService)
{
_cmdHelper = cmdHelper;
_nuGetService = nuGetService;
_packageVersionCheckerService = packageVersionCheckerService;
_nuGetIndexUrlService = nuGetIndexUrlService;
Logger = NullLogger<CliCommand>.Instance;
@ -104,13 +104,13 @@ public class CliCommand : IConsoleCommand, ITransientDependency
private async Task<string> GetLatestPreviewVersion()
{
var latestPreviewVersion = await _nuGetService
var latestPreviewVersionInfo = await _packageVersionCheckerService
.GetLatestVersionOrNullAsync(
packageId: CliPackageName,
includeReleaseCandidates: true
);
return latestPreviewVersion.IsPrerelease ? latestPreviewVersion.ToString() : null;
return latestPreviewVersionInfo.Version.IsPrerelease ? latestPreviewVersionInfo.Version.ToString() : null;
}
private void ShowCliManualUpdateCommand()

12
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs

@ -17,7 +17,7 @@ using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Auth;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.NuGet;
using Volo.Abp.Cli.Version;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
@ -32,7 +32,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
public ICmdHelper CmdHelper { get; }
private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService;
private readonly NuGetService _nuGetService;
private readonly PackageVersionCheckerService _packageVersionCheckerService;
private readonly AuthService _authService;
private readonly CliHttpClientFactory _cliHttpClientFactory;
private readonly SuiteAppSettingsService _suiteAppSettingsService;
@ -43,7 +43,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
public SuiteCommand(
AbpNuGetIndexUrlService nuGetIndexUrlService,
NuGetService nuGetService,
PackageVersionCheckerService packageVersionCheckerService,
ICmdHelper cmdHelper,
AuthService authService,
CliHttpClientFactory cliHttpClientFactory,
@ -51,7 +51,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
{
CmdHelper = cmdHelper;
_nuGetIndexUrlService = nuGetIndexUrlService;
_nuGetService = nuGetService;
_packageVersionCheckerService = packageVersionCheckerService;
_authService = authService;
_cliHttpClientFactory = cliHttpClientFactory;
_suiteAppSettingsService = suiteAppSettingsService;
@ -397,13 +397,13 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
private async Task<string> GetLatestPreviewVersion()
{
var latestPreviewVersion = await _nuGetService
var latestPreviewVersionInfo = await _packageVersionCheckerService
.GetLatestVersionOrNullAsync(
packageId: SuitePackageName,
includeReleaseCandidates: true
);
return latestPreviewVersion.IsPrerelease ? latestPreviewVersion.ToString() : null;
return latestPreviewVersionInfo.Version.IsPrerelease ? latestPreviewVersionInfo.Version.ToString() : null;
}
private void ShowSuiteManualUpdateCommand()

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClientFactory.cs

@ -20,9 +20,9 @@ public class CliHttpClientFactory : ISingletonDependency
_cancellationTokenProvider = cancellationTokenProvider;
}
public HttpClient CreateClient(bool needsAuthentication = true, TimeSpan? timeout = null)
public HttpClient CreateClient(bool needsAuthentication = true, TimeSpan? timeout = null, string clientName = null)
{
var httpClient = _clientFactory.CreateClient(CliConsts.HttpClientName);
var httpClient = _clientFactory.CreateClient(clientName ?? CliConsts.HttpClientName);
httpClient.Timeout = timeout ?? DefaultTimeout;
if (needsAuthentication)

38
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs

@ -5,7 +5,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using Volo.Abp.Cli.NuGet;
using Volo.Abp.Cli.Version;
using Volo.Abp.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -15,14 +15,14 @@ namespace Volo.Abp.Cli.ProjectModification;
public class VoloNugetPackagesVersionUpdater : ITransientDependency
{
private readonly NuGetService _nuGetService;
private readonly PackageVersionCheckerService _packageVersionCheckerService;
private readonly MyGetPackageListFinder _myGetPackageListFinder;
public ILogger<VoloNugetPackagesVersionUpdater> Logger { get; set; }
public static Encoding DefaultEncoding = Encoding.UTF8;
public VoloNugetPackagesVersionUpdater(NuGetService nuGetService, MyGetPackageListFinder myGetPackageListFinder)
public VoloNugetPackagesVersionUpdater(PackageVersionCheckerService packageVersionCheckerService, MyGetPackageListFinder myGetPackageListFinder)
{
_nuGetService = nuGetService;
_packageVersionCheckerService = packageVersionCheckerService;
_myGetPackageListFinder = myGetPackageListFinder;
Logger = NullLogger<VoloNugetPackagesVersionUpdater>.Instance;
}
@ -37,8 +37,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
}
else
{
var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: includeReleaseCandidates);
var latestReleaseCandidateVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true);
var latestVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: includeReleaseCandidates);
var latestReleaseCandidateVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true);
var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core");
async Task UpdateAsync(string filePath)
@ -53,8 +53,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
includePreviews,
includeReleaseCandidates,
switchToStable,
latestVersionFromNuget,
latestReleaseCandidateVersionFromNuget,
latestVersionInfo.Version,
latestReleaseCandidateVersionInfo.Version,
latestVersionFromMyGet,
version);
@ -81,8 +81,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
}
else
{
var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core");
var latestReleaseCandidateVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true);
var latestVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core");
var latestReleaseCandidateVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true);
var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core");
using (var fs = File.Open(projectPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
@ -95,8 +95,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
includeNightlyPreviews,
includeReleaseCandidates,
switchToStable,
latestVersionFromNuget,
latestReleaseCandidateVersionFromNuget,
latestVersionInfo.Version,
latestReleaseCandidateVersionInfo.Version,
latestVersionFromMyGet,
version);
@ -137,11 +137,11 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
protected virtual async Task<bool> SpecifiedVersionExists(string version, string packageId)
{
var versionList = await _nuGetService.GetPackageVersionListAsync(packageId);
var versionList = await _packageVersionCheckerService.GetPackageVersionListAsync(packageId);
if (versionList.All(v => !v.Equals(version, StringComparison.OrdinalIgnoreCase)))
{
versionList = await _nuGetService.GetPackageVersionListAsync(packageId, true);
versionList = await _packageVersionCheckerService.GetPackageVersionListAsync(packageId, true);
}
return versionList.Any(v => v.Equals(version, StringComparison.OrdinalIgnoreCase));
@ -240,13 +240,15 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
SemanticVersion latestVersion;
if (currentSemanticVersion.IsPrerelease && !switchToStable)
{
latestVersion = latestNugetReleaseCandidateVersion == null || isLeptonXPackage ?
await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: true) : latestNugetReleaseCandidateVersion;
latestVersion = latestNugetReleaseCandidateVersion == null || isLeptonXPackage
? (await _packageVersionCheckerService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: true))?.Version
: latestNugetReleaseCandidateVersion;
}
else
{
latestVersion = latestNugetVersion == null || isLeptonXPackage ?
await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates) : latestNugetVersion;
latestVersion = latestNugetVersion == null || isLeptonXPackage
? (await _packageVersionCheckerService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates))?.Version
: latestNugetVersion;
}
if (latestVersion != null && (currentSemanticVersion < latestVersion || (currentSemanticVersion.IsPrerelease && switchToStable)))

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/CommercialPackages.cs → framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/CommercialPackages.cs

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.Cli.NuGet;
namespace Volo.Abp.Cli.Version;
internal static class CommercialPackages
{

16
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/LatestVersionInfo.cs

@ -0,0 +1,16 @@
using NuGet.Versioning;
namespace Volo.Abp.Cli.Version;
public class LatestVersionInfo
{
public SemanticVersion Version { get; }
public string Message { get; }
public LatestVersionInfo(SemanticVersion version, string message = null)
{
Version = version;
Message = message;
}
}

84
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs → framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Version/PackageVersionCheckerService.cs

@ -3,6 +3,7 @@ using Newtonsoft.Json;
using NuGet.Versioning;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -14,9 +15,9 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
using Volo.Abp.Threading;
namespace Volo.Abp.Cli.NuGet;
namespace Volo.Abp.Cli.Version;
public class NuGetService : ITransientDependency
public class PackageVersionCheckerService : ITransientDependency
{
public ILogger<VoloNugetPackagesVersionUpdater> Logger { get; set; }
protected IJsonSerializer JsonSerializer { get; }
@ -26,7 +27,7 @@ public class NuGetService : ITransientDependency
private readonly CliHttpClientFactory _cliHttpClientFactory;
private DeveloperApiKeyResult _apiKeyResult;
public NuGetService(
public PackageVersionCheckerService(
IJsonSerializer jsonSerializer,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
ICancellationTokenProvider cancellationTokenProvider,
@ -58,26 +59,30 @@ public class NuGetService : ITransientDependency
return versionList.Contains(version);
}
public async Task<SemanticVersion> GetLatestVersionOrNullAsync(string packageId, bool includeNightly = false, bool includeReleaseCandidates = false)
public async Task<LatestVersionInfo> GetLatestVersionOrNullAsync(string packageId, bool includeNightly = false, bool includeReleaseCandidates = false)
{
var versionList = await GetPackageVersionListAsync(packageId, includeNightly);
if (!includeNightly && !includeReleaseCandidates)
{
var latestStableVersionResult = await GetLatestStableVersionOrNullAsync();
if (latestStableVersionResult == null)
{
return null;
}
return SemanticVersion.TryParse(latestStableVersionResult.Version, out var semanticVersion)
? new LatestVersionInfo(semanticVersion, latestStableVersionResult.Message)
: null;
}
var versionList = await GetPackageVersionListAsync(packageId, includeNightly);
if (versionList == null)
{
return null;
}
List<SemanticVersion> versions;
if (!includeNightly && !includeReleaseCandidates)
{
versions = versionList
.Select(SemanticVersion.Parse)
.OrderByDescending(v => v, new VersionComparer()).ToList();
versions = versions.Where(x => !x.IsPrerelease).ToList();
}
else if (!includeNightly && includeReleaseCandidates)
if (!includeNightly && includeReleaseCandidates)
{
versions = versionList
.Where(v => !v.Contains("-preview"))
@ -91,7 +96,9 @@ public class NuGetService : ITransientDependency
.OrderByDescending(v => v, new VersionComparer()).ToList();
}
return versions.Any() ? versions.Max() : null;
return versions.Any()
? new LatestVersionInfo(versions.Max())
: null;
}
@ -148,15 +155,13 @@ public class NuGetService : ITransientDependency
logger: Logger
))
{
if (responseMessage.StatusCode == System.Net.HttpStatusCode.NotFound)
if (responseMessage.StatusCode == HttpStatusCode.NotFound)
{
//the package doesn't exist...
return null;
}
else
{
await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage);
}
await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage);
var responseContent = await responseMessage.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<NuGetVersionResultDto>(responseContent).Versions;
@ -183,9 +188,46 @@ public class NuGetService : ITransientDependency
return CliUrls.GetNuGetPackageInfoUrl(_apiKeyResult.ApiKey, packageId);
}
private async Task<LatestStableVersionResult> GetLatestStableVersionOrNullAsync()
{
try
{
var client = _cliHttpClientFactory.CreateClient(clientName: CliConsts.GithubHttpClientName, needsAuthentication: false);
using (var responseMessage = await client.GetHttpResponseMessageWithRetryAsync(
CliUrls.LatestVersionCheckFullPath,
cancellationToken: CancellationTokenProvider.Token,
logger: Logger
))
{
await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage);
var content = await responseMessage.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<List<LatestStableVersionResult>>(content);
return result.FirstOrDefault(x => x.Type.ToLowerInvariant() == "stable");
}
}
catch
{
return null;
}
}
public class NuGetVersionResultDto
{
[JsonProperty("versions")]
public List<string> Versions { get; set; }
}
public class LatestStableVersionResult
{
public string Version { get; set; }
public DateTime? ReleaseDate { get; set; }
public string Type { get; set; }
public string Message { get; set; }
}
}

1
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;

28
framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs

@ -6,6 +6,7 @@ using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
@ -13,6 +14,7 @@ using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Client.StaticProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
@ -24,14 +26,17 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention
protected readonly IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder;
protected readonly List<ControllerModel> ControllerWithAttributeRoute;
protected readonly List<ActionModel> ActionWithAttributeRoute;
protected readonly AbpHttpClientStaticProxyingOptions StaticProxyingOptions;
public AbpHttpClientProxyServiceConvention(
IOptions<AbpAspNetCoreMvcOptions> options,
IConventionalRouteBuilder conventionalRouteBuilder,
IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder)
IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder,
IOptions<AbpHttpClientStaticProxyingOptions> staticProxyingOptions)
: base(options, conventionalRouteBuilder)
{
ClientProxyApiDescriptionFinder = clientProxyApiDescriptionFinder;
StaticProxyingOptions = staticProxyingOptions.Value;
ControllerWithAttributeRoute = new List<ControllerModel>();
ActionWithAttributeRoute = new List<ActionModel>();
}
@ -73,6 +78,27 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention
}
}
protected override void ConfigureParameters(ControllerModel controller)
{
foreach (var action in controller.Actions)
{
foreach (var prm in action.Parameters)
{
if (prm.BindingInfo != null)
{
continue;
}
if (StaticProxyingOptions.BindingFromQueryTypes.Contains(prm.ParameterInfo.ParameterType))
{
prm.BindingInfo = BindingInfo.GetBindingInfo(new[] { new FromQueryAttribute() });
}
}
}
base.ConfigureParameters(controller);
}
protected virtual bool ShouldBeRemove(ApplicationModel application, ControllerModel controllerModel)
{
return application.Controllers

14
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/StaticProxying/AbpHttpClientStaticProxyingOptions.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Http.Client.StaticProxying;
public class AbpHttpClientStaticProxyingOptions
{
public List<Type> BindingFromQueryTypes { get; }
public AbpHttpClientStaticProxyingOptions()
{
BindingFromQueryTypes = new List<Type>();
}
}

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

@ -193,7 +193,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
if (_databaseApis.ContainsKey(key))
{
throw new AbpException("There is already a database API in this unit of work with given key: " + key);
throw new AbpException("There is already a database API in this unit of work with given key.");
}
_databaseApis.Add(key, api);
@ -221,7 +221,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
if (_transactionApis.ContainsKey(key))
{
throw new AbpException("There is already a transaction API in this unit of work with given key: " + key);
throw new AbpException("There is already a transaction API in this unit of work with given key.");
}
_transactionApis.Add(key, api);

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "يجب أن يكون الحقل {0} سلسلة أحرف طولها {1} كحد أدنى و {2} كحد أقصى.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "الحقل {0} ليس عنوانا URL صالحًا مؤهلاً بالكامل سواء كان عنوان http أو https أو ftp",
"The field {0} is invalid.": "الحقل {0} غير صالح.",
"The value '{0}' is invalid.": "القيمة '{0}' غير صالحة.",
"The field {0} must be a number.": "يجب أن يكون الحقل {0} رقمًا.",
"The field must be a number.": "يجب أن يكون الحقل رقمًا.",
"ThisFieldIsNotAValidCreditCardNumber.": "هذا الحقل لا يمثل رقم بطاقة ائتمان صالح.",
"ThisFieldIsNotValid.": "هذا الحقل غير صالح.",
"ThisFieldIsNotAValidEmailAddress.": "هذا الحقل لا يمثل عنوان بريد إلكتروني صالح.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musí být řetězec o minimální délce {2} a maximální délce {1} znaků.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Pole {0} není platná plně kvalifikovaná adresa http, https, nebo ftp URL.",
"The field {0} is invalid.": "Pole {0} je neplatné.",
"The value '{0}' is invalid.": "Hodnota '{0}' je neplatná.",
"The field {0} must be a number.": "Pole {0} musí být číslo.",
"The field must be a number.": "Pole musí být číslo.",
"ThisFieldIsNotAValidCreditCardNumber.": "V poli {0} není platné číslo kreditní karty.",
"ThisFieldIsNotValid.": "{0} není platný.",
"ThisFieldIsNotAValidEmailAddress.": "V poli {0} není platný email.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Das Feld {0} muss eine Zeichenfolge mit einer Mindestlänge von {2} und einer Maximallänge von {1} sein.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Das Feld {0} ist keine gültige, vollqualifizierte http-, https- oder ftp-URL.",
"The field {0} is invalid.": "Das Feld {0} ist ungültig.",
"The value '{0}' is invalid.": "Der Wert '{0}' ist ungültig.",
"The field {0} must be a number.": "Das Feld {0} muss eine Zahl sein.",
"The field must be a number.": "Das Feld muss eine Zahl sein.",
"ThisFieldIsNotAValidCreditCardNumber.": "Dieses Feld ist keine gültige Kreditkartennummer.",
"ThisFieldIsNotValid.": "Dieses Feld ist ungültig.",
"ThisFieldIsNotAValidEmailAddress.": "Dieses Feld ist keine gültige E-Mail-Adresse.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Το πεδίο {0} πρέπει να είναι μια συμβολοσειρά με ελάχιστο μήκος {2} και μέγιστο μήκος {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Το πεδίο {0} δεν είναι έγκυρη πλήρως πιστοποιημένη διεύθυνση URL http, https ή ftp.",
"The field {0} is invalid.": "Το πεδίο {0} δεν είναι έγκυρο.",
"The value '{0}' is invalid.": "Η τιμή '{0}' δεν είναι έγκυρη.",
"The field {0} must be a number.": "Το πεδίο {0} πρέπει να είναι αριθμός.",
"The field must be a number.": "Το πεδίο πρέπει να είναι αριθμός.",
"ThisFieldIsNotAValidCreditCardNumber.": "Αυτό το πεδίο δεν περιέχει έγκυρο αριθμό πιστωτικής κάρτας.",
"ThisFieldIsNotValid.": "Αυτό το πεδίο δεν είναι έγκυρο.",
"ThisFieldIsNotAValidEmailAddress.": "Αυτό το πεδίο δεν περιέχει έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json

@ -17,6 +17,9 @@
"The field {0} is invalid.": "The field {0} is invalid.",
"ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.",
"ThisFieldIsNotValid.": "This field is not valid.",
"The value '{0}' is invalid.": "The value '{0}' is invalid.",
"The field {0} must be a number.": "The field {0} must be a number.",
"The field must be a number.": "The field must be a number.",
"ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.",
"ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "This field only accepts files with the following extensions: {0}",
"ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}": "This field must be a string or array type with a maximum length of '{0}'.",

5
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "The {0} field is not a valid fully-qualified http, https, or ftp URL.",
"The field {0} is invalid.": "The field {0} is invalid.",
"The value '{0}' is invalid.": "The value '{0}' is invalid.",
"The field {0} must be a number.": "The field {0} must be a number.",
"The field must be a number.": "The field must be a number.",
"ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.",
"ThisFieldIsNotValid.": "This field is not valid.",
"ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.",
@ -33,4 +36,4 @@
"ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "This field is not a valid fully-qualified http, https, or ftp URL.",
"ThisFieldIsInvalid.": "This field is invalid."
}
}
}

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "El campo {0} debe ser una cadena con una longitud mínima de {2} y máxima de {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "El campo {0} no es una URL (http, https o ftp) valida.",
"The field {0} is invalid.": "El campo {0} no es valido.",
"The value '{0}' is invalid.": "El valor '{0}' no es válido.",
"The field {0} must be a number.": "El campo {0} debe ser un número.",
"The field must be a number.": "El campo debe ser un número.",
"ThisFieldIsNotAValidCreditCardNumber.": "El campo no es un número de tarjeta de crédito valido.",
"ThisFieldIsNotValid.": "Este campo no es valido.",
"ThisFieldIsNotAValidEmailAddress.": "Este campo no es una dirección de e-mail valida.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "فیلد {0} باید رشته ای با حداقل طول {2} و حداکثر باشد طول {1}. ",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "فیلد {0} یک نشانی اینترنتی http ، https ، یا ftp کاملاً واجد شرایط نیست.",
"The field {0} is invalid.": "فیلد {0} نامعتبر است.",
"The value '{0}' is invalid.": "مقدار '{0}' نامعتبر است.",
"The field {0} must be a number.": "فیلد {0} باید یک عدد باشد.",
"The field must be a number.": "فیلد باید یک عدد باشد.",
"ThisFieldIsNotAValidCreditCardNumber.": "این قسمت شماره کارت اعتباری معتبری نیست.",
"ThisFieldIsNotValid.": "این قسمت معتبر نیست.",
"ThisFieldIsNotAValidEmailAddress.": "این قسمت آدرس ایمیل معتبری نیست.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Kentän {0} on oltava merkkijono, jonka vähimmäispituus on {2} ja enimmäispituus {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} -kenttä ei ole kelvollinen täysin hyväksytty http, https tai ftp URL.",
"The field {0} is invalid.": "Kenttä {0} on virheellinen.",
"The value '{0}' is invalid.": "Arvo '{0}' on virheellinen.",
"The field {0} must be a number.": "Kentän {0} on oltava numero.",
"The field must be a number.": "Kentän on oltava numero.",
"ThisFieldIsNotAValidCreditCardNumber.": "Tämä kenttä ei ole kelvollinen luottokortin numero.",
"ThisFieldIsNotValid.": "Tämä kenttä ei kelpaa.",
"ThisFieldIsNotAValidEmailAddress.": "Tämä kenttä ei ole kelvollinen sähköpostiosoite.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Le champ {0} doit être une chaîne d'une longueur minimale de {2} et d'une longueur maximale de {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Le champ {0} n'est pas une URL http, https ou ftp complète valide.",
"The field {0} is invalid.": "Le champ {0} n'est pas valide.",
"The value '{0}' is invalid.": "La valeur '{0}' n'est pas valide.",
"The field {0} must be a number.": "Le champ {0} doit être un nombre.",
"The field must be a number.": "Le champ doit être un nombre.",
"ThisFieldIsNotAValidCreditCardNumber.": "Ce champ n'est pas un numéro de carte de crédit valide.",
"ThisFieldIsNotValid.": "Ce champ n'est pas valide.",
"ThisFieldIsNotAValidEmailAddress.": "Ce champ n'est pas une adresse e-mail valide.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "फ़ील्ड {0} की लंबाई न्यूनतम {2} और अधिकतम लंबाई {1} होनी चाहिए।",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} फ़ील्ड मान्य पूर्णत: योग्य http, https, या ftp URL नहीं है।",
"The field {0} is invalid.": "फ़ील्ड {0} अमान्य है।",
"The value '{0}' is invalid.": "मान '{0}' अमान्य है।",
"The field {0} must be a number.": "फ़ील्ड {0} एक संख्या होनी चाहिए।",
"The field must be a number.": "फ़ील्ड एक संख्या होनी चाहिए।",
"ThisFieldIsNotAValidCreditCardNumber.": "यह फ़ील्ड मान्य क्रेडिट कार्ड नंबर नहीं है।",
"ThisFieldIsNotValid.": "यह फ़ील्ड मान्य नहीं है।",
"ThisFieldIsNotAValidEmailAddress.": "यह फ़ील्ड मान्य ई-मेल पता नहीं है।",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Polje {0} mora biti text sa minimalnom du�inom od {2} i maksimalnom dužinom od {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} nije valjan potpuno kvalificirani http, https, ili ftp URL.",
"The field {0} is invalid.": "Polje {0} nije važeće.",
"The value '{0}' is invalid.": "Vrijednost '{0}' nije važeća.",
"The field {0} must be a number.": "Polje {0} mora biti broj.",
"The field must be a number.": "Polje mora biti broj.",
"ThisFieldIsNotAValidCreditCardNumber.": "Ovo polje nije važeći broj kreditne kartice.",
"ThisFieldIsNotValid.": "Ovo polje nije valjano.",
"ThisFieldIsNotAValidEmailAddress.": "Ovo polje nije valjana e-mail adresa.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "A {0} mezőnek szöveget kell tartalmaznia minimum {2} és maximum {1} hosszan.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "A {0} mező nem érvényes fully-qualified http, https, vagy ftp URL cím.",
"The field {0} is invalid.": "A {0} mező nem érvényes.",
"The value '{0}' is invalid.": "A(z) '{0}' érték érvénytelen.",
"The field {0} must be a number.": "A(z) {0} mezőnek számnak kell lennie.",
"The field must be a number.": "A mezőnek számnak kell lennie.",
"ThisFieldIsNotAValidCreditCardNumber.": "A mező nem érvényes bankkártya számot tartalmaz.",
"ThisFieldIsNotValid.": "A mező nem érvényes.",
"ThisFieldIsNotAValidEmailAddress.": "A mező nem érvényes email cím.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Reiturinn {0} verður að vera strengur með lágmarkslengd {2} og hámarkslengd {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Reiturinn {0} er ekki fullgild http, https, eða ftp slóð.",
"The field {0} is invalid.": "Reiturinn {0} er ekki rétt útfylltur.",
"The value '{0}' is invalid.": "Gildið '{0}' er ógilt.",
"The field {0} must be a number.": "Reiturinn {0} verður að vera númer.",
"The field must be a number.": "Reiturinn verður að vera númer.",
"ThisFieldIsNotAValidCreditCardNumber.": "Þessi reitur hefur ekki gilt kreditkortanúmer.",
"ThisFieldIsNotValid.": "Reiturinn er ekki rétt útfylltur.",
"ThisFieldIsNotAValidEmailAddress.": "Þessi reitur hefur ekki gilt netfang.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Il campo {0} deve essere una stringa con una lunghezza minima di {2} e una lunghezza massima di {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Il campo {0} non è un URL http, https o ftp completo e valido.",
"The field {0} is invalid.": "Il campo {0} non è valido.",
"The value '{0}' is invalid.": "Il valore '{0}' non è valido.",
"The field {0} must be a number.": "Il campo {0} deve essere un numero.",
"The field must be a number.": "Il campo deve essere un numero.",
"ThisFieldIsNotAValidCreditCardNumber.": "Questo campo non è un numero di carta di credito valido.",
"ThisFieldIsNotValid.": "Questo campo non è valido.",
"ThisFieldIsNotAValidEmailAddress.": "Questo campo non è un indirizzo e-mail valido.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Het veld {0} moet een tekenreeks zijn met een minimale lengte van {2} en een maximale lengte van {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Het veld {0} is geen geldige, volledig gekwalificeerde http-, https- of ftp-URL.",
"The field {0} is invalid.": "Het veld {0} is ongeldig.",
"The value '{0}' is invalid.": "De waarde '{0}' is ongeldig.",
"The field {0} must be a number.": "Het veld {0} moet een getal zijn.",
"The field must be a number.": "Het veld moet een getal zijn.",
"ThisFieldIsNotAValidCreditCardNumber.": "Dit veld is geen geldig krediet kaartnummer.",
"ThisFieldIsNotValid.": "Dir veld is ongeldig.",
"ThisFieldIsNotAValidEmailAddress.": "Dit veld is geen geldig e-mail adres.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musi być łańcuchem znaków o minimalnej długości {2} i maksymalnej długości {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Pole {0} nie jest prawidłowym, w pełni kwalifikowanym adresem URL http, https lub ftp.",
"The field {0} is invalid.": "Pole {0} jest niepoprawne.",
"The value '{0}' is invalid.": "Wartość '{0}' jest nieprawidłowa.",
"The field {0} must be a number.": "Pole {0} musi być liczbą.",
"The field must be a number.": "Pole musi być liczbą.",
"ThisFieldIsNotAValidCreditCardNumber.": "To pole nie jest prawidłowym numerem karty kredytowej.",
"ThisFieldIsNotValid.": "To pole jest nieprawidłowe.",
"ThisFieldIsNotAValidEmailAddress.": "To pole nie jest prawidłowym adresem e-mail.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "O campo {0} deve ser uma palavra com o tamanho mínimo de {2} e tamanho máximo de {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "O campo {0} não é um http, https, ou FTP válido.",
"The field {0} is invalid.": "O campo {0} é inválido.",
"The value '{0}' is invalid.": "O valor '{0}' é inválido.",
"The field {0} must be a number.": "O campo {0} deve ser um número.",
"The field must be a number.": "O campo deve ser um número.",
"ThisFieldIsNotAValidCreditCardNumber.": "Não é um cartão de crédito válido.",
"ThisFieldIsNotValid.": "Campo inválido.",
"ThisFieldIsNotAValidEmailAddress.": "E-mail inválido.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Câmpul {0} trebuie să fie un string cu lungimea minimă de {2} şi lungimea maximă de {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Câmpul {0} nu este o adresă validă complet http, https sau ftp.",
"The field {0} is invalid.": "Câmpul {0} este invalid.",
"The value '{0}' is invalid.": "Valoarea '{0}' este nevalidă.",
"The field {0} must be a number.": "Câmpul {0} trebuie să fie un număr.",
"The field must be a number.": "Câmpul trebuie să fie un număr.",
"ThisFieldIsNotAValidCreditCardNumber.": "Acest câmp nu este un număr de card de credit valid.",
"ThisFieldIsNotValid.": "Acest câmp nu este valid.",
"ThisFieldIsNotAValidEmailAddress.": "Acest câmp nu este o adresă de e-mail validă.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Поле {0} должно быть строкой с минимальной длиной {2} и максимальной длиной {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Поле {0} не является действительным полным http, https или ftp адресом.",
"The field {0} is invalid.": "Значение в поле {0} недопустимо.",
"The value '{0}' is invalid.": "Значение '{0}' недопустимо.",
"The field {0} must be a number.": "Поле {0} должно быть числом.",
"The field must be a number.": "Поле должно быть числом.",
"ThisFieldIsNotAValidCreditCardNumber.": "Это поле не содержит действительный номер кредитной карты.",
"ThisFieldIsNotValid.": "Значение в этом поле недействительно.",
"ThisFieldIsNotAValidEmailAddress.": "Это поле не содержит действительный адрес электронной почты.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musí byť reťazec s minimálnou dĺžkou {2} a maximálnou dĺžkou {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "V poli {0} nie je platná plne kvalifikovaná adresa http, https alebo ftp URL.",
"The field {0} is invalid.": "Pole {0} je neplatné.",
"The value '{0}' is invalid.": "Hodnota '{0}' je neplatná.",
"The field {0} must be a number.": "Pole {0} musí byť číslo.",
"The field must be a number.": "Pole musí byť číslo.",
"ThisFieldIsNotAValidCreditCardNumber.": "V tomto poli nie je platné číslo kreditnej karty.",
"ThisFieldIsNotValid.": "Toto pole nie je platné.",
"ThisFieldIsNotAValidEmailAddress.": "V tomto poli nie je platná e-mailová adresa.",

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Polje {0} mora biti niz z najmanjšo dolžino {2} in največjo dolžino {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Polje {0} ni veljaven popolnoma kvalificiran URL http, https ali ftp.",
"The field {0} is invalid.": "Polje {0} ni veljavno.",
"The value '{0}' is invalid.": "Vrednost '{0}' ni veljavna.",
"The field {0} must be a number.": "Polje {0} mora biti številka.",
"The field must be a number.": "Polje mora biti številka.",
"ThisFieldIsNotAValidCreditCardNumber.": "To polje ni veljavna številka kreditne kartice.",
"ThisFieldIsNotValid.": "To polje ni veljavno.",
"ThisFieldIsNotAValidEmailAddress.": "To polje ni veljaven e-poštni naslov.",

5
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "{0} alanı en az {2}, en fazla {1} uzunluğunda bir metin olmalıdır.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} alanı geçerli bir http, https, ya da ftp adresi olmalıdır.",
"The field {0} is invalid.": "{0} alanı geçerli değil.",
"The value '{0}' is invalid.": "{0} değeri geçerli değil.",
"The field {0} must be a number.": "{0} alanı bir sayı olmalıdır.",
"The field must be a number.": "Bu alan bir sayı olmalıdır.",
"ThisFieldIsNotAValidCreditCardNumber.": "Bu alan geçerli bir kredi kartı numarası olmalıdır.",
"ThisFieldIsNotValid.": "Bu alan geçerli değil.",
"ThisFieldIsNotAValidEmailAddress.": "Bu alan geçerli bir e-posta adresi olmalıdır.",
@ -33,4 +36,4 @@
"ThisFieldMustBeGreaterThanOrEqual{0}": "Bu alan {0}'dan büyük veya eşit olmalıdır.",
"ThisFieldMustBeLessOrEqual{0}": "Bu alan {0}'dan küçük veya eşit olmalıdır."
}
}
}

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Trường {0} phải là một chuỗi với độ dài tối thiểu {2} và tối đa là {1}.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Trường {0} không phải là một http, https, hoặc ftp URL đủ điều kiện hợp lệ.",
"The field {0} is invalid.": "Trường {0} không có hiệu lực",
"The value '{0}' is invalid.": "Giá trị '{0}' không hợp lệ.",
"The field {0} must be a number.": "Trường {0} phải là một số.",
"The field must be a number.": "Trường phải là một số.",
"ThisFieldIsNotAValidCreditCardNumber.": "Trường này không phải là số thẻ tín dụng hợp lệ.",
"ThisFieldIsNotValid.": "Trường này không hợp lệ.",
"ThisFieldIsNotAValidEmailAddress.": "Trường này không phải là địa chỉ e-mail hợp lệ.",

5
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "字段{0}必须是最小长度为{2}并且最大长度{1}的字符串.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "字段{0}不是有效的完全限定的http,https或ftp URL.",
"The field {0} is invalid.": "字段{0}是无效值.",
"The value '{0}' is invalid.": "'{0}'是无效值",
"The field {0} must be a number.": "字段{0}必须是数字.",
"The field must be a number.": "该字段必须是数字.",
"ThisFieldIsNotAValidCreditCardNumber.": "字段不是有效的信用卡号码.",
"ThisFieldIsNotValid.": "验证未通过.",
"ThisFieldIsNotAValidEmailAddress.": "字段不是有效的邮箱地址.",
@ -33,4 +36,4 @@
"ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "字段{0}不是有效的完全限定的http,https或ftp URL.",
"ThisFieldIsInvalid.": "该字段无效."
}
}
}

3
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json

@ -16,6 +16,9 @@
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "欄位{0}必須是最小長度為{2}並且最大長度{1}的字串.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.": "欄位{0}不是有效的完全限定的http,https或ftp URL.",
"The field {0} is invalid.": "此欄位{0}是無效值.",
"The value '{0}' is invalid.": "'{0}'是無效值",
"The field {0} must be a number.": "欄位{0}必須是號碼.",
"The field must be a number.": "此欄位{0}必須是號碼.",
"ThisFieldIsNotAValidCreditCardNumber.": "此欄位不是有效的信用卡號碼.",
"ThisFieldIsNotValid.": "此驗證未通過.",
"ThisFieldIsNotAValidEmailAddress.": "此欄位不是有效的郵箱地址.",

26
framework/test/Volo.Abp.AspNetCore.MultiTenancy.Tests/Volo/Abp/AspNetCore/MultiTenancy/AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests.cs

@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Shouldly;
using Xunit;
namespace Volo.Abp.AspNetCore.MultiTenancy;
public class AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests : AspNetCoreMultiTenancyTestBase
{
private readonly AbpAspNetCoreMultiTenancyOptions _options;
public AspNetCoreMultiTenancy_MultiTenancyMiddlewareErrorPageBuilder_Tests()
{
_options = ServiceProvider.GetRequiredService<IOptions<AbpAspNetCoreMultiTenancyOptions>>().Value;
}
[Fact]
public async Task MultiTenancyMiddlewareErrorPageBuilder()
{
var result = await GetResponseAsStringAsync($"http://abp.io?{_options.TenantKey}=<script>alert(hi)</script>", HttpStatusCode.NotFound);
result.ShouldNotContain("<script>alert(hi)</script>");
}
}

49
framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
@ -59,7 +60,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase
jobObject.ExecutedValues.ShouldContain("42");
}
[Fact]
public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant()
{
@ -77,7 +78,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase
new MyJobArgs("42", tenantId)
)
);
await _backgroundJobExecuter.ExecuteAsync(
new JobExecutionContext(
ServiceProvider,
@ -91,4 +92,48 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase
jobObject.TenantId.ShouldBe(tenantId);
asyncJobObject.TenantId.ShouldBe(tenantId);
}
[Fact]
public async Task Should_Cancel_Job()
{
//Arrange
var cts = new CancellationTokenSource();
cts.Cancel();
var jobObject = GetRequiredService<MyJob>();
jobObject.ExecutedValues.ShouldBeEmpty();
//Act
await _backgroundJobExecuter.ExecuteAsync(
new JobExecutionContext(
ServiceProvider,
typeof(MyJob),
new MyJobArgs("42"),
cts.Token
)
);
//Assert
jobObject.Canceled.ShouldBeTrue();
//Arrange
var asyncCts = new CancellationTokenSource();
asyncCts.Cancel();
var asyncJobObject = GetRequiredService<MyAsyncJob>();
asyncJobObject.ExecutedValues.ShouldBeEmpty();
//Act
await _backgroundJobExecuter.ExecuteAsync(
new JobExecutionContext(
ServiceProvider,
typeof(MyAsyncJob),
new MyAsyncJobArgs("42"),
asyncCts.Token
)
);
//Assert
asyncJobObject.Canceled.ShouldBeTrue();
}
}

19
framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs

@ -1,26 +1,39 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs;
public class MyAsyncJob : AsyncBackgroundJob<MyAsyncJobArgs>, ISingletonDependency
{
public List<string> ExecutedValues { get; } = new List<string>();
public Guid? TenantId { get; set; }
private readonly ICurrentTenant _currentTenant;
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public MyAsyncJob(ICurrentTenant currentTenant)
public bool Canceled { get; set; }
public MyAsyncJob(
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider)
{
_currentTenant = currentTenant;
_cancellationTokenProvider = cancellationTokenProvider;
}
public override Task ExecuteAsync(MyAsyncJobArgs args)
{
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
Canceled = true;
}
ExecutedValues.Add(args.Value);
TenantId = _currentTenant.Id;
return Task.CompletedTask;

19
framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs

@ -1,25 +1,38 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs;
public class MyJob : BackgroundJob<MyJobArgs>, ISingletonDependency
{
public List<string> ExecutedValues { get; } = new List<string>();
public Guid? TenantId { get; set; }
private readonly ICurrentTenant _currentTenant;
public MyJob(ICurrentTenant currentTenant)
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public bool Canceled { get; set; }
public MyJob(
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider)
{
_currentTenant = currentTenant;
_cancellationTokenProvider = cancellationTokenProvider;
}
public override void Execute(MyJobArgs args)
{
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
Canceled = true;
}
ExecutedValues.Add(args.Value);
TenantId = _currentTenant.Id;
}

8
latest-versions.json

@ -0,0 +1,8 @@
[
{
"version": "7.0.2",
"releaseDate": "",
"type": "stable",
"message": ""
}
]

9
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs

@ -1,6 +1,8 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Account.Settings;
using Volo.Abp.Identity;
using Volo.Abp.Settings;
namespace Volo.Abp.Account.Web.Pages.Account;
@ -28,7 +30,12 @@ public class LogoutModel : AccountPageModel
return RedirectSafely(ReturnUrl, ReturnUrlHash);
}
return RedirectToPage("/Account/Login");
if (await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin))
{
return RedirectToPage("/Account/Login");
}
return RedirectToPage("/");
}
public virtual Task<IActionResult> OnPostAsync()

31
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs

@ -1,23 +1,40 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs.DemoApp.HangFire;
class Program
{
static void Main(string[] args)
async static Task Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<DemoAppHangfireModule>(options =>
using (var application = await AbpApplicationFactory.CreateAsync<DemoAppHangfireModule>(options =>
{
options.UseAutofac();
}))
{
options.UseAutofac();
}))
{
application.Initialize();
await application.InitializeAsync();
await CancelableBackgroundJobAsync(application.ServiceProvider);
Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine();
application.Shutdown();
await application.ShutdownAsync();
}
}
private async static Task CancelableBackgroundJobAsync(IServiceProvider serviceProvider)
{
var backgroundJobManager = serviceProvider.GetRequiredService<IBackgroundJobManager>();
var jobId = await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-1" });
await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-2" });
Thread.Sleep(1000);
BackgroundJob.Delete(jobId);
}
}

26
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs

@ -1,23 +1,41 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Quartz;
using Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs.DemoApp.Quartz;
class Program
{
static void Main(string[] args)
async static Task Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<DemoAppQuartzModule>(options =>
using (var application = await AbpApplicationFactory.CreateAsync<DemoAppQuartzModule>(options =>
{
options.UseAutofac();
}))
{
application.Initialize();
await application.InitializeAsync();
await CancelableBackgroundJobAsync(application.ServiceProvider);
Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine();
application.Shutdown();
await application.ShutdownAsync();
}
}
private async static Task CancelableBackgroundJobAsync(IServiceProvider serviceProvider)
{
var backgroundJobManager = serviceProvider.GetRequiredService<IBackgroundJobManager>();
var jobId = await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs {Value = "test-1"});
await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-2" });
Thread.Sleep(1000);
var scheduler = serviceProvider.GetRequiredService<IScheduler>();
await scheduler.Interrupt(new JobKey(jobId.Split('.')[1],jobId.Split('.')[0]));
}
}

9
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs

@ -1,23 +1,24 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundJobs.DemoApp.RabbitMq;
class Program
{
static void Main(string[] args)
async static Task Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<DemoAppRabbitMqModule>(options =>
using (var application = await AbpApplicationFactory.CreateAsync<DemoAppRabbitMqModule>(options =>
{
options.UseAutofac();
}))
{
application.Initialize();
await application.InitializeAsync();
Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine();
application.Shutdown();
await application.ShutdownAsync();
}
}
}

49
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs

@ -0,0 +1,49 @@
using System;
using System.Threading;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs
{
public class LongRunningJob : BackgroundJob<LongRunningJobArgs>, ITransientDependency
{
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public LongRunningJob(ICancellationTokenProvider cancellationTokenProvider)
{
_cancellationTokenProvider = cancellationTokenProvider;
}
public override void Execute(LongRunningJobArgs args)
{
lock (Console.Out)
{
var oldColor = Console.ForegroundColor;
try
{
Console.WriteLine($"Long running {args.Value} start: {DateTime.Now}");
for (var i = 1; i <= 10; i++)
{
_cancellationTokenProvider.Token.ThrowIfCancellationRequested();
Thread.Sleep(1000);
Console.WriteLine($"{args.Value} step-{i} done: {DateTime.Now}");
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Long running {args.Value} completed: {DateTime.Now}");
}
catch (OperationCanceledException)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Long running {args.Value} cancelled!!!");
}
finally
{
Console.ForegroundColor = oldColor;
}
}
}
}
}

8
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs
{
[BackgroundJobName("LongJob")]
public class LongRunningJobArgs
{
public string Value { get; set; }
}
}

1
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs

1
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs

11
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Autofac;
using System.Threading.Tasks;
using Volo.Abp.Autofac;
using Volo.Abp.BackgroundJobs.DemoApp.Shared;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
@ -27,19 +28,21 @@ public class DemoAppModule : AbpModule
Configure<AbpBackgroundJobWorkerOptions>(options =>
{
//Configure for fast running
options.JobPollPeriod = 1000;
//Configure for fast running
options.JobPollPeriod = 1000;
options.DefaultFirstWaitDuration = 1;
options.DefaultWaitFactor = 1;
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
{
//TODO: Configure console logging
//context
// .ServiceProvider
// .GetRequiredService<ILoggerFactory>()
// .AddConsole(LogLevel.Debug);
return Task.CompletedTask;
}
}

10
modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs

@ -1,23 +1,23 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundJobs.DemoApp;
class Program
{
static void Main(string[] args)
async static Task Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<DemoAppModule>(options =>
using (var application = await AbpApplicationFactory.CreateAsync<DemoAppModule>(options =>
{
options.UseAutofac();
}))
{
application.Initialize();
await application.InitializeAsync();
Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine();
application.Shutdown();
await application.ShutdownAsync();
}
}
}

2
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json

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

2703
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock

File diff suppressed because it is too large

4
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json

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

2759
modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock

File diff suppressed because it is too large

4
modules/blogging/app/Volo.BloggingTestApp/package.json

@ -3,7 +3,7 @@
"name": "volo.blogtestapp",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.1",
"@abp/blogging": "^7.1.0-rc.1"
"@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.2",
"@abp/blogging": "^7.1.0-rc.2"
}
}

2889
modules/blogging/app/Volo.BloggingTestApp/yarn.lock

File diff suppressed because it is too large

4
modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminMenuContributor.cs → modules/blogging/src/Volo.Blogging.Admin.Web/Navigation/BloggingAdminMenuContributor.cs

@ -19,9 +19,9 @@ namespace Volo.Blogging.Admin
{
var l = context.GetLocalizer<BloggingResource>();
var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"]).RequirePermissions(BloggingPermissions.Blogs.Management);
var managementRootMenuItem = new ApplicationMenuItem(BloggingAdminMenuNames.GroupName, l["Menu:BlogManagement"]).RequirePermissions(BloggingPermissions.Blogs.Management);
managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Blogging/Admin/Blogs").RequirePermissions(BloggingPermissions.Blogs.Management));
managementRootMenuItem.AddItem(new ApplicationMenuItem(BloggingAdminMenuNames.Blogs, l["Menu:Blogs"], "~/Blogging/Admin/Blogs").RequirePermissions(BloggingPermissions.Blogs.Management));
context.Menu.GetAdministration().AddItem(managementRootMenuItem);

8
modules/blogging/src/Volo.Blogging.Admin.Web/Navigation/BloggingAdminMenuNames.cs

@ -0,0 +1,8 @@
namespace Volo.Blogging.Admin;
public class BloggingAdminMenuNames
{
public const string GroupName = "BlogManagement";
public const string Blogs = GroupName + ".Blogs";
}

6
modules/blogging/src/Volo.Blogging.Admin.Web/Pages/Blogging/Admin/Blogs/Index.cshtml

@ -4,6 +4,7 @@
@using Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs
@using Volo.Blogging
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using Volo.Blogging.Localization
@inherits Volo.Blogging.Admin.Pages.Blogging.BloggingAdminPage
@model IndexModel
@ -12,6 +13,11 @@
@{
ViewBag.PageTitle = "Blogs";
}
@inject IPageLayout PageLayout
@{
PageLayout.Content.Title = L["Blogs"].Value;
PageLayout.Content.MenuItemName = BloggingAdminMenuNames.Blogs;
}
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">

3
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml.cs

@ -50,6 +50,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
var postDto = await _postAppService.GetAsync(new Guid(PostId));
Post = ObjectMapper.Map<PostWithDetailsDto, EditPostViewModel>(postDto);
Post.Tags = String.Join(", ", postDto.Tags.Select(p => p.Name).ToArray());
Post.Url = WebUtility.UrlDecode(Post.Url);
return Page();
}
@ -60,7 +61,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
BlogId = Post.BlogId,
Title = Post.Title,
Url = Post.Url,
Url = WebUtility.UrlEncode(Post.Url),
CoverImage = Post.CoverImage,
Content = Post.Content,
Tags = Post.Tags,

2
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs

@ -66,6 +66,8 @@ namespace Volo.Blogging.Pages.Blog.Posts
Post.Description = Post.Content.Truncate(PostConsts.MaxSeoFriendlyDescriptionLength);
}
Post.Url = WebUtility.UrlEncode(Post.Url);
var postWithDetailsDto = await _postAppService.CreateAsync(ObjectMapper.Map<CreatePostViewModel, CreatePostDto>(Post));
//TODO: Try Url.Page(...)

2
modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json

@ -3,6 +3,6 @@
"name": "client-simulation-web",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.1"
"@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.2"
}
}

2674
modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock

File diff suppressed because it is too large

10
modules/cms-kit/angular/package.json

@ -15,11 +15,11 @@
},
"private": true,
"dependencies": {
"@abp/ng.account": "~7.1.0-rc.1",
"@abp/ng.identity": "~7.1.0-rc.1",
"@abp/ng.setting-management": "~7.1.0-rc.1",
"@abp/ng.tenant-management": "~7.1.0-rc.1",
"@abp/ng.theme.basic": "~7.1.0-rc.1",
"@abp/ng.account": "~7.1.0-rc.2",
"@abp/ng.identity": "~7.1.0-rc.2",
"@abp/ng.setting-management": "~7.1.0-rc.2",
"@abp/ng.tenant-management": "~7.1.0-rc.2",
"@abp/ng.theme.basic": "~7.1.0-rc.2",
"@angular/animations": "~10.0.0",
"@angular/common": "~10.0.0",
"@angular/compiler": "~10.0.0",

4
modules/cms-kit/angular/projects/cms-kit/package.json

@ -4,8 +4,8 @@
"peerDependencies": {
"@angular/common": "^9.1.11",
"@angular/core": "^9.1.11",
"@abp/ng.core": ">=7.1.0-rc.1",
"@abp/ng.theme.shared": ">=7.1.0-rc.1"
"@abp/ng.core": ">=7.1.0-rc.2",
"@abp/ng.theme.shared": ">=7.1.0-rc.2"
},
"dependencies": {
"tslib": "^2.0.0"

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

Loading…
Cancel
Save