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: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: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: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: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!", "Volo.AbpIo.Domain:070001": "The company name can only contain latin letters, numbers, dots, space and hyphens!",
"WantToLearn?": "Want to learn?", "WantToLearn?": "Want to learn?",
@ -205,6 +206,8 @@
"Icons": "Icons", "Icons": "Icons",
"Url": "Url", "Url": "Url",
"Icon": "Icon", "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?", "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.", "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?", "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.", "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.", "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.", "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.", "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.", "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.", "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. 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 #### 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. 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: 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")] [EventName("product")]
public class ProductEto : EntityEto<Guid> 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. This table stores information about property changes to entities in the application, which are logged for auditing purposes.
## Uses #### Foreign Keys
| Table | Column | Description | | 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. 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 | | Table | Column | Description |
| --- | --- | --- | | --- | --- | --- |

6
docs/en/Modules/IdentityServer.md

@ -1,10 +1,12 @@
# IdentityServer Module # 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 ## 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 ### 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: 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. 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. 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
`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: 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. * `label`: Sets the label for input.
* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. * `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 ### Label & Localization
@ -100,7 +100,7 @@ You can set label of your input in different ways:
## abp-select ## 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.) `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", "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", "text": "OpenIddict",
"items": [ "items": [
{ {
"text": "OpenIddict Migration Guide", "text": "OpenIddict Migration Guide",
"path": "Migration-Guides/OpenIddict-Step-by-Step.md" "path": "Migration-Guides/OpenIddict-Step-by-Step.md"
} }
], ],
"path": "Modules/OpenIddict.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;
using System.Globalization; using System.Globalization;
using System.Net; using System.Net;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -42,8 +43,8 @@ public class AbpAspNetCoreMultiTenancyOptions
var message = exception.Message; var message = exception.Message;
var details = exception is BusinessException businessException ? businessException.Details : string.Empty; 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($"<html lang=\"{HtmlEncoder.Default.Encode(CultureInfo.CurrentCulture.Name)}\"><body>\r\n");
await context.Response.WriteAsync($"<h3>{message}</h3>{details}<br>\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"); await context.Response.WriteAsync("</body></html>\r\n");
// Note the 500 spaces are to work around an IE 'feature' // 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.Modularity;
using Volo.Abp.UI; using Volo.Abp.UI;
using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation;
using Volo.Abp.Validation.Localization;
namespace Volo.Abp.AspNetCore.Mvc; namespace Volo.Abp.AspNetCore.Mvc;
@ -174,10 +175,17 @@ public class AbpAspNetCoreMvcModule : AbpModule
context.Services.Replace(ServiceDescriptor.Singleton<IValidationAttributeAdapterProvider, AbpValidationAttributeAdapterProvider>()); context.Services.Replace(ServiceDescriptor.Singleton<IValidationAttributeAdapterProvider, AbpValidationAttributeAdapterProvider>());
context.Services.AddSingleton<ValidationAttributeAdapterProvider>(); context.Services.AddSingleton<ValidationAttributeAdapterProvider>();
Configure<MvcOptions>(mvcOptions => context.Services.AddOptions<MvcOptions>()
{ .Configure<IServiceProvider>((mvcOptions, serviceProvider) =>
mvcOptions.AddAbp(context.Services); {
}); 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 => Configure<AbpEndpointRouterOptions>(options =>
{ {

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

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Volo.Abp.Auditing; namespace Volo.Abp.Auditing;
@ -76,7 +77,8 @@ public class AbpAuditingOptions
IgnoredTypes = new List<Type> IgnoredTypes = new List<Type>
{ {
typeof(Stream), typeof(Stream),
typeof(Expression) typeof(Expression),
typeof(CancellationToken)
}; };
EntityHistorySelectors = new EntityHistorySelectorList(); 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;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
@ -6,7 +7,7 @@ namespace Volo.Abp.BackgroundJobs;
public abstract class AsyncBackgroundJob<TArgs> : IAsyncBackgroundJob<TArgs> 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; } 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;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
@ -5,7 +6,7 @@ namespace Volo.Abp.BackgroundJobs;
public abstract class BackgroundJob<TArgs> : IBackgroundJob<TArgs> 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; } 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.DependencyInjection;
using Volo.Abp.ExceptionHandling; using Volo.Abp.ExceptionHandling;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs; namespace Volo.Abp.BackgroundJobs;
@ -46,13 +47,19 @@ public class BackgroundJobExecuter : IBackgroundJobExecuter, ITransientDependenc
{ {
using(CurrentTenant.Change(GetJobArgsTenantId(context.JobArgs))) using(CurrentTenant.Change(GetJobArgsTenantId(context.JobArgs)))
{ {
if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob<object>.ExecuteAsync)) var cancellationTokenProvider =
{ context.ServiceProvider.GetRequiredService<ICancellationTokenProvider>();
await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs }));
} using (cancellationTokenProvider.Use(context.CancellationToken))
else
{ {
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; 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> /// <summary>
/// Defines interface of a background job. /// 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;
using System.Threading;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs; namespace Volo.Abp.BackgroundJobs;
@ -11,10 +12,17 @@ public class JobExecutionContext : IServiceProviderAccessor
public object JobArgs { get; } 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; ServiceProvider = serviceProvider;
JobType = jobType; JobType = jobType;
JobArgs = jobArgs; 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 public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency
{ {
protected AbpBackgroundJobOptions Options { get; } protected AbpBackgroundJobOptions Options { get; }
public HangfireBackgroundJobManager(IOptions<AbpBackgroundJobOptions> options) public HangfireBackgroundJobManager(IOptions<AbpBackgroundJobOptions> options)
{ {
Options = options.Value; Options = options.Value;
} }
public virtual Task<string> EnqueueAsync<TArgs>(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, public virtual Task<string> EnqueueAsync<TArgs>(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal,
TimeSpan? delay = null) TimeSpan? delay = null)
{ {
return Task.FromResult(delay.HasValue return Task.FromResult(delay.HasValue
? BackgroundJob.Schedule<HangfireJobExecutionAdapter<TArgs>>( ? BackgroundJob.Schedule<HangfireJobExecutionAdapter<TArgs>>(
adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)),args), adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default),
delay.Value delay.Value
) )
: BackgroundJob.Enqueue<HangfireJobExecutionAdapter<TArgs>>( : 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 Hangfire;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -21,8 +22,8 @@ public class HangfireJobExecutionAdapter<TArgs>
Options = options.Value; Options = options.Value;
} }
[Queue("{0}")] [Queue("{0}")]
public async Task ExecuteAsync(string queue, TArgs args) public async Task ExecuteAsync(string queue, TArgs args, CancellationToken cancellationToken = default)
{ {
if (!Options.IsJobExecutionEnabled) if (!Options.IsJobExecutionEnabled)
{ {
@ -38,7 +39,7 @@ public class HangfireJobExecutionAdapter<TArgs>
using (var scope = ServiceScopeFactory.CreateScope()) using (var scope = ServiceScopeFactory.CreateScope())
{ {
var jobType = Options.GetJob(typeof(TArgs)).JobType; 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); 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 args = JsonSerializer.Deserialize<TArgs>(context.JobDetail.JobDataMap.GetString(nameof(TArgs)));
var jobType = Options.GetJob(typeof(TArgs)).JobType; 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 try
{ {
await JobExecuter.ExecuteAsync(jobContext); 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( var context = new JobExecutionContext(
workerContext.ServiceProvider, workerContext.ServiceProvider,
jobConfiguration.JobType, jobConfiguration.JobType,
jobArgs); jobArgs,
workerContext.CancellationToken);
try 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) context.Services.AddHttpClient(CliConsts.HttpClientName)
.ConfigurePrimaryHttpMessageHandler(() => new CliHttpClientHandler()); .ConfigurePrimaryHttpMessageHandler(() => new CliHttpClientHandler());
context.Services.AddHttpClient(CliConsts.GithubHttpClientName, client =>
{
client.DefaultRequestHeaders.UserAgent.ParseAdd("MyAgent/1.0");
});
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Configure<AbpCliOptions>(options => 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) if (!response.IsSuccessStatusCode)
{ {
Logger.LogError("Remote server returns '{response.StatusCode}'"); Logger.LogError($"Remote server returns '{response.StatusCode}'");
return null; 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 = GetFileContent(filePath, options.Minify);
} }
content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(options.Directory, "wwwroot"), content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"),
content); content);
builder.AppendLine(content); builder.AppendLine(content);
} }
return builder.ToString(); return builder.ToString();
} }
} }
@ -125,15 +126,15 @@ public abstract class BundlerBase : IBundler, ITransientDependency
foreach (var definition in bundleDefinitions) foreach (var definition in bundleDefinitions)
{ {
var filePath = Path.Combine(definition.Source.Split('/')); var filePath = Path.Combine(definition.Source.Split('/'));
var fileFullPath = Directory.GetFiles(options.Directory, string.Empty, SearchOption.AllDirectories).FirstOrDefault(x => x.EndsWith(filePath)); var fileFullPath = Directory.GetFiles(options.Directory, string.Empty, SearchOption.AllDirectories).FirstOrDefault(x => x.EndsWith(filePath));
if(fileFullPath == null) if(fileFullPath == null)
{ {
throw new AbpException("Not found: " + definition.Source); throw new AbpException("Not found: " + definition.Source);
} }
var content = GetFileContent(fileFullPath, options.Minify); 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); content);
builder.AppendLine(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 HttpClientName = "AbpHttpClient";
public const string GithubHttpClientName = "GithubHttpClient";
public const string LogoutUrl = CliUrls.WwwAbpIo + "api/license/logout"; public const string LogoutUrl = CliUrls.WwwAbpIo + "api/license/logout";
public const string LicenseCodePlaceHolder = @"<LICENSE_CODE/>"; 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.Args;
using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Memory; using Volo.Abp.Cli.Memory;
using Volo.Abp.Cli.NuGet; using Volo.Abp.Cli.Version;
using Volo.Abp.Cli.Utils; using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.IO; using Volo.Abp.IO;
@ -27,14 +27,14 @@ public class CliService : ITransientDependency
protected ICommandLineArgumentParser CommandLineArgumentParser { get; } protected ICommandLineArgumentParser CommandLineArgumentParser { get; }
protected ICommandSelector CommandSelector { get; } protected ICommandSelector CommandSelector { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; } protected IServiceScopeFactory ServiceScopeFactory { get; }
protected NuGetService NuGetService { get; } protected PackageVersionCheckerService PackageVersionCheckerService { get; }
public ICmdHelper CmdHelper { get; } public ICmdHelper CmdHelper { get; }
public CliService( public CliService(
ICommandLineArgumentParser commandLineArgumentParser, ICommandLineArgumentParser commandLineArgumentParser,
ICommandSelector commandSelector, ICommandSelector commandSelector,
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
NuGetService nugetService, PackageVersionCheckerService nugetService,
ICmdHelper cmdHelper, ICmdHelper cmdHelper,
MemoryService memoryService) MemoryService memoryService)
{ {
@ -42,7 +42,7 @@ public class CliService : ITransientDependency
CommandLineArgumentParser = commandLineArgumentParser; CommandLineArgumentParser = commandLineArgumentParser;
CommandSelector = commandSelector; CommandSelector = commandSelector;
ServiceScopeFactory = serviceScopeFactory; ServiceScopeFactory = serviceScopeFactory;
NuGetService = nugetService; PackageVersionCheckerService = nugetService;
CmdHelper = cmdHelper; CmdHelper = cmdHelper;
Logger = NullLogger<CliService>.Instance; Logger = NullLogger<CliService>.Instance;
@ -61,6 +61,7 @@ public class CliService : ITransientDependency
await CheckCliVersionAsync(currentCliVersion); await CheckCliVersionAsync(currentCliVersion);
} }
#endif #endif
try try
{ {
if (commandLineArgs.IsCommand("prompt")) if (commandLineArgs.IsCommand("prompt"))
@ -175,24 +176,22 @@ public class CliService : ITransientDependency
{ {
return; return;
} }
var assembly = typeof(CliService).Assembly;
var toolPath = GetToolPath(assembly);
var updateChannel = GetUpdateChannel(currentCliVersion);
try 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) catch (Exception e)
{ {
Logger.LogWarning("Unable to retrieve the latest version"); Logger.LogWarning("Unable to retrieve the latest version: " + e.Message);
Logger.LogWarning(e.Message);
} }
} }
@ -200,13 +199,17 @@ public class CliService : ITransientDependency
{ {
try try
{ {
var latestTime = await _memoryService.GetAsync(CliConsts.MemoryKeys.LatestCliVersionCheckDate); var latestTimeAsString = await _memoryService.GetAsync(CliConsts.MemoryKeys.LatestCliVersionCheckDate);
if (DateTime.TryParse(latestTimeAsString,
if (latestTime != null && DateTime.Now - DateTime.Parse(latestTime, CultureInfo.InvariantCulture) < TimeSpan.FromDays(1)) 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)); await _memoryService.SetAsync(CliConsts.MemoryKeys.LatestCliVersionCheckDate, DateTime.Now.ToString(CultureInfo.InvariantCulture));
return true; return true;
@ -282,18 +285,18 @@ public class CliService : ITransientDependency
return UpdateChannel.Prerelease; return UpdateChannel.Prerelease;
} }
private async Task<SemanticVersion> GetLatestVersion(UpdateChannel updateChannel) private async Task<LatestVersionInfo> GetLatestVersion(UpdateChannel updateChannel)
{ {
switch (updateChannel) switch (updateChannel)
{ {
case UpdateChannel.Stable: case UpdateChannel.Stable:
return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli"); return await PackageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Cli");
case UpdateChannel.Prerelease: case UpdateChannel.Prerelease:
return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeReleaseCandidates: true); return await PackageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeReleaseCandidates: true);
case UpdateChannel.Nightly: case UpdateChannel.Nightly:
return await NuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true); return await PackageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Cli", includeNightly: true);
default: default:
return default; return default;
@ -306,11 +309,17 @@ public class CliService : ITransientDependency
return globalPaths.Select(Environment.ExpandEnvironmentVariables).Contains(toolPath); 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}"; 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."); 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(string.Empty);
Logger.LogWarning("Update Command: "); 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 WwwAbpIo = WwwAbpIoProduction;
public const string AccountAbpIo = AccountAbpIoProduction; public const string AccountAbpIo = AccountAbpIoProduction;
public const string NuGetRootPath = NuGetRootPathProduction; 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 WwwAbpIoProduction = "https://abp.io/";
public const string AccountAbpIoProduction = "https://account.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 Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands.Services; using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.NuGet; using Volo.Abp.Cli.Version;
using Volo.Abp.Cli.Utils; using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -18,14 +18,14 @@ public class CliCommand : IConsoleCommand, ITransientDependency
private const string CliPackageName = "Volo.Abp.Cli"; private const string CliPackageName = "Volo.Abp.Cli";
private readonly ICmdHelper _cmdHelper; private readonly ICmdHelper _cmdHelper;
private readonly NuGetService _nuGetService; private readonly PackageVersionCheckerService _packageVersionCheckerService;
private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService; private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService;
public ILogger<CliCommand> Logger { get; set; } public ILogger<CliCommand> Logger { get; set; }
public CliCommand(ICmdHelper cmdHelper, NuGetService nuGetService, AbpNuGetIndexUrlService nuGetIndexUrlService) public CliCommand(ICmdHelper cmdHelper, PackageVersionCheckerService packageVersionCheckerService, AbpNuGetIndexUrlService nuGetIndexUrlService)
{ {
_cmdHelper = cmdHelper; _cmdHelper = cmdHelper;
_nuGetService = nuGetService; _packageVersionCheckerService = packageVersionCheckerService;
_nuGetIndexUrlService = nuGetIndexUrlService; _nuGetIndexUrlService = nuGetIndexUrlService;
Logger = NullLogger<CliCommand>.Instance; Logger = NullLogger<CliCommand>.Instance;
@ -104,13 +104,13 @@ public class CliCommand : IConsoleCommand, ITransientDependency
private async Task<string> GetLatestPreviewVersion() private async Task<string> GetLatestPreviewVersion()
{ {
var latestPreviewVersion = await _nuGetService var latestPreviewVersionInfo = await _packageVersionCheckerService
.GetLatestVersionOrNullAsync( .GetLatestVersionOrNullAsync(
packageId: CliPackageName, packageId: CliPackageName,
includeReleaseCandidates: true includeReleaseCandidates: true
); );
return latestPreviewVersion.IsPrerelease ? latestPreviewVersion.ToString() : null; return latestPreviewVersionInfo.Version.IsPrerelease ? latestPreviewVersionInfo.Version.ToString() : null;
} }
private void ShowCliManualUpdateCommand() 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.Auth;
using Volo.Abp.Cli.Commands.Services; using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.Http; using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.NuGet; using Volo.Abp.Cli.Version;
using Volo.Abp.Cli.Utils; using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http; using Volo.Abp.Http;
@ -32,7 +32,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
public ICmdHelper CmdHelper { get; } public ICmdHelper CmdHelper { get; }
private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService; private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService;
private readonly NuGetService _nuGetService; private readonly PackageVersionCheckerService _packageVersionCheckerService;
private readonly AuthService _authService; private readonly AuthService _authService;
private readonly CliHttpClientFactory _cliHttpClientFactory; private readonly CliHttpClientFactory _cliHttpClientFactory;
private readonly SuiteAppSettingsService _suiteAppSettingsService; private readonly SuiteAppSettingsService _suiteAppSettingsService;
@ -43,7 +43,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
public SuiteCommand( public SuiteCommand(
AbpNuGetIndexUrlService nuGetIndexUrlService, AbpNuGetIndexUrlService nuGetIndexUrlService,
NuGetService nuGetService, PackageVersionCheckerService packageVersionCheckerService,
ICmdHelper cmdHelper, ICmdHelper cmdHelper,
AuthService authService, AuthService authService,
CliHttpClientFactory cliHttpClientFactory, CliHttpClientFactory cliHttpClientFactory,
@ -51,7 +51,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
{ {
CmdHelper = cmdHelper; CmdHelper = cmdHelper;
_nuGetIndexUrlService = nuGetIndexUrlService; _nuGetIndexUrlService = nuGetIndexUrlService;
_nuGetService = nuGetService; _packageVersionCheckerService = packageVersionCheckerService;
_authService = authService; _authService = authService;
_cliHttpClientFactory = cliHttpClientFactory; _cliHttpClientFactory = cliHttpClientFactory;
_suiteAppSettingsService = suiteAppSettingsService; _suiteAppSettingsService = suiteAppSettingsService;
@ -397,13 +397,13 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency
private async Task<string> GetLatestPreviewVersion() private async Task<string> GetLatestPreviewVersion()
{ {
var latestPreviewVersion = await _nuGetService var latestPreviewVersionInfo = await _packageVersionCheckerService
.GetLatestVersionOrNullAsync( .GetLatestVersionOrNullAsync(
packageId: SuitePackageName, packageId: SuitePackageName,
includeReleaseCandidates: true includeReleaseCandidates: true
); );
return latestPreviewVersion.IsPrerelease ? latestPreviewVersion.ToString() : null; return latestPreviewVersionInfo.Version.IsPrerelease ? latestPreviewVersionInfo.Version.ToString() : null;
} }
private void ShowSuiteManualUpdateCommand() 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; _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; httpClient.Timeout = timeout ?? DefaultTimeout;
if (needsAuthentication) 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.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml; using System.Xml;
using Volo.Abp.Cli.NuGet; using Volo.Abp.Cli.Version;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
@ -15,14 +15,14 @@ namespace Volo.Abp.Cli.ProjectModification;
public class VoloNugetPackagesVersionUpdater : ITransientDependency public class VoloNugetPackagesVersionUpdater : ITransientDependency
{ {
private readonly NuGetService _nuGetService; private readonly PackageVersionCheckerService _packageVersionCheckerService;
private readonly MyGetPackageListFinder _myGetPackageListFinder; private readonly MyGetPackageListFinder _myGetPackageListFinder;
public ILogger<VoloNugetPackagesVersionUpdater> Logger { get; set; } public ILogger<VoloNugetPackagesVersionUpdater> Logger { get; set; }
public static Encoding DefaultEncoding = Encoding.UTF8; public static Encoding DefaultEncoding = Encoding.UTF8;
public VoloNugetPackagesVersionUpdater(NuGetService nuGetService, MyGetPackageListFinder myGetPackageListFinder) public VoloNugetPackagesVersionUpdater(PackageVersionCheckerService packageVersionCheckerService, MyGetPackageListFinder myGetPackageListFinder)
{ {
_nuGetService = nuGetService; _packageVersionCheckerService = packageVersionCheckerService;
_myGetPackageListFinder = myGetPackageListFinder; _myGetPackageListFinder = myGetPackageListFinder;
Logger = NullLogger<VoloNugetPackagesVersionUpdater>.Instance; Logger = NullLogger<VoloNugetPackagesVersionUpdater>.Instance;
} }
@ -37,8 +37,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
} }
else else
{ {
var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: includeReleaseCandidates); var latestVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: includeReleaseCandidates);
var latestReleaseCandidateVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true); var latestReleaseCandidateVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true);
var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core"); var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core");
async Task UpdateAsync(string filePath) async Task UpdateAsync(string filePath)
@ -53,8 +53,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
includePreviews, includePreviews,
includeReleaseCandidates, includeReleaseCandidates,
switchToStable, switchToStable,
latestVersionFromNuget, latestVersionInfo.Version,
latestReleaseCandidateVersionFromNuget, latestReleaseCandidateVersionInfo.Version,
latestVersionFromMyGet, latestVersionFromMyGet,
version); version);
@ -81,8 +81,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
} }
else else
{ {
var latestVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core"); var latestVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core");
var latestReleaseCandidateVersionFromNuget = await _nuGetService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true); var latestReleaseCandidateVersionInfo = await _packageVersionCheckerService.GetLatestVersionOrNullAsync("Volo.Abp.Core", includeReleaseCandidates: true);
var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core"); var latestVersionFromMyGet = await GetLatestVersionFromMyGet("Volo.Abp.Core");
using (var fs = File.Open(projectPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) using (var fs = File.Open(projectPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
@ -95,8 +95,8 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
includeNightlyPreviews, includeNightlyPreviews,
includeReleaseCandidates, includeReleaseCandidates,
switchToStable, switchToStable,
latestVersionFromNuget, latestVersionInfo.Version,
latestReleaseCandidateVersionFromNuget, latestReleaseCandidateVersionInfo.Version,
latestVersionFromMyGet, latestVersionFromMyGet,
version); version);
@ -137,11 +137,11 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
protected virtual async Task<bool> SpecifiedVersionExists(string version, string packageId) 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))) 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)); return versionList.Any(v => v.Equals(version, StringComparison.OrdinalIgnoreCase));
@ -240,13 +240,15 @@ public class VoloNugetPackagesVersionUpdater : ITransientDependency
SemanticVersion latestVersion; SemanticVersion latestVersion;
if (currentSemanticVersion.IsPrerelease && !switchToStable) if (currentSemanticVersion.IsPrerelease && !switchToStable)
{ {
latestVersion = latestNugetReleaseCandidateVersion == null || isLeptonXPackage ? latestVersion = latestNugetReleaseCandidateVersion == null || isLeptonXPackage
await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: true) : latestNugetReleaseCandidateVersion; ? (await _packageVersionCheckerService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: true))?.Version
: latestNugetReleaseCandidateVersion;
} }
else else
{ {
latestVersion = latestNugetVersion == null || isLeptonXPackage ? latestVersion = latestNugetVersion == null || isLeptonXPackage
await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates) : latestNugetVersion; ? (await _packageVersionCheckerService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates))?.Version
: latestNugetVersion;
} }
if (latestVersion != null && (currentSemanticVersion < latestVersion || (currentSemanticVersion.IsPrerelease && switchToStable))) 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.Collections.Generic;
using System.Text; using System.Text;
namespace Volo.Abp.Cli.NuGet; namespace Volo.Abp.Cli.Version;
internal static class CommercialPackages 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 NuGet.Versioning;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
@ -14,9 +15,9 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Json; using Volo.Abp.Json;
using Volo.Abp.Threading; 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; } public ILogger<VoloNugetPackagesVersionUpdater> Logger { get; set; }
protected IJsonSerializer JsonSerializer { get; } protected IJsonSerializer JsonSerializer { get; }
@ -26,7 +27,7 @@ public class NuGetService : ITransientDependency
private readonly CliHttpClientFactory _cliHttpClientFactory; private readonly CliHttpClientFactory _cliHttpClientFactory;
private DeveloperApiKeyResult _apiKeyResult; private DeveloperApiKeyResult _apiKeyResult;
public NuGetService( public PackageVersionCheckerService(
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler, IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
ICancellationTokenProvider cancellationTokenProvider, ICancellationTokenProvider cancellationTokenProvider,
@ -58,26 +59,30 @@ public class NuGetService : ITransientDependency
return versionList.Contains(version); 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) if (versionList == null)
{ {
return null; return null;
} }
List<SemanticVersion> versions; List<SemanticVersion> versions;
if (!includeNightly && !includeReleaseCandidates) 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)
{ {
versions = versionList versions = versionList
.Where(v => !v.Contains("-preview")) .Where(v => !v.Contains("-preview"))
@ -91,7 +96,9 @@ public class NuGetService : ITransientDependency
.OrderByDescending(v => v, new VersionComparer()).ToList(); .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 logger: Logger
)) ))
{ {
if (responseMessage.StatusCode == System.Net.HttpStatusCode.NotFound) if (responseMessage.StatusCode == HttpStatusCode.NotFound)
{ {
//the package doesn't exist... //the package doesn't exist...
return null; return null;
} }
else
{ await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage);
await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage);
}
var responseContent = await responseMessage.Content.ReadAsStringAsync(); var responseContent = await responseMessage.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<NuGetVersionResultDto>(responseContent).Versions; return JsonSerializer.Deserialize<NuGetVersionResultDto>(responseContent).Versions;
@ -183,9 +188,46 @@ public class NuGetService : ITransientDependency
return CliUrls.GetNuGetPackageInfoUrl(_apiKeyResult.ApiKey, packageId); 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 public class NuGetVersionResultDto
{ {
[JsonProperty("versions")] [JsonProperty("versions")]
public List<string> Versions { get; set; } 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;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs; using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection; 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;
using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
@ -13,6 +14,7 @@ using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Client.StaticProxying;
using Volo.Abp.Http.Modeling; using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection; using Volo.Abp.Reflection;
@ -24,14 +26,17 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention
protected readonly IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder; protected readonly IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder;
protected readonly List<ControllerModel> ControllerWithAttributeRoute; protected readonly List<ControllerModel> ControllerWithAttributeRoute;
protected readonly List<ActionModel> ActionWithAttributeRoute; protected readonly List<ActionModel> ActionWithAttributeRoute;
protected readonly AbpHttpClientStaticProxyingOptions StaticProxyingOptions;
public AbpHttpClientProxyServiceConvention( public AbpHttpClientProxyServiceConvention(
IOptions<AbpAspNetCoreMvcOptions> options, IOptions<AbpAspNetCoreMvcOptions> options,
IConventionalRouteBuilder conventionalRouteBuilder, IConventionalRouteBuilder conventionalRouteBuilder,
IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder) IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder,
IOptions<AbpHttpClientStaticProxyingOptions> staticProxyingOptions)
: base(options, conventionalRouteBuilder) : base(options, conventionalRouteBuilder)
{ {
ClientProxyApiDescriptionFinder = clientProxyApiDescriptionFinder; ClientProxyApiDescriptionFinder = clientProxyApiDescriptionFinder;
StaticProxyingOptions = staticProxyingOptions.Value;
ControllerWithAttributeRoute = new List<ControllerModel>(); ControllerWithAttributeRoute = new List<ControllerModel>();
ActionWithAttributeRoute = new List<ActionModel>(); 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) protected virtual bool ShouldBeRemove(ApplicationModel application, ControllerModel controllerModel)
{ {
return application.Controllers 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)) 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); _databaseApis.Add(key, api);
@ -221,7 +221,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency
if (_transactionApis.ContainsKey(key)) 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); _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 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 {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 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.": "هذا الحقل لا يمثل رقم بطاقة ائتمان صالح.", "ThisFieldIsNotAValidCreditCardNumber.": "هذا الحقل لا يمثل رقم بطاقة ائتمان صالح.",
"ThisFieldIsNotValid.": "هذا الحقل غير صالح.", "ThisFieldIsNotValid.": "هذا الحقل غير صالح.",
"ThisFieldIsNotAValidEmailAddress.": "هذا الحقل لا يمثل عنوان بريد إلكتروني صالح.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "V poli {0} není platné číslo kreditní karty.",
"ThisFieldIsNotValid.": "{0} není platný.", "ThisFieldIsNotValid.": "{0} není platný.",
"ThisFieldIsNotAValidEmailAddress.": "V poli {0} není platný email.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Dieses Feld ist keine gültige Kreditkartennummer.",
"ThisFieldIsNotValid.": "Dieses Feld ist ungültig.", "ThisFieldIsNotValid.": "Dieses Feld ist ungültig.",
"ThisFieldIsNotAValidEmailAddress.": "Dieses Feld ist keine gültige E-Mail-Adresse.", "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 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 {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 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.": "Αυτό το πεδίο δεν περιέχει έγκυρο αριθμό πιστωτικής κάρτας.", "ThisFieldIsNotAValidCreditCardNumber.": "Αυτό το πεδίο δεν περιέχει έγκυρο αριθμό πιστωτικής κάρτας.",
"ThisFieldIsNotValid.": "Αυτό το πεδίο δεν είναι έγκυρο.", "ThisFieldIsNotValid.": "Αυτό το πεδίο δεν είναι έγκυρο.",
"ThisFieldIsNotAValidEmailAddress.": "Αυτό το πεδίο δεν περιέχει έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.", "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.", "The field {0} is invalid.": "The field {0} is invalid.",
"ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.", "ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.",
"ThisFieldIsNotValid.": "This field is not valid.", "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.", "ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.",
"ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "This field only accepts files with the following extensions: {0}", "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}'.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.",
"ThisFieldIsNotValid.": "This field is not valid.", "ThisFieldIsNotValid.": "This field is not valid.",
"ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.", "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.", "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "This field is not a valid fully-qualified http, https, or ftp URL.",
"ThisFieldIsInvalid.": "This field is invalid." "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "El campo no es un número de tarjeta de crédito valido.",
"ThisFieldIsNotValid.": "Este campo no es valido.", "ThisFieldIsNotValid.": "Este campo no es valido.",
"ThisFieldIsNotAValidEmailAddress.": "Este campo no es una dirección de e-mail valida.", "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 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 {0} field is not a valid fully-qualified http, https, or ftp URL.": "فیلد {0} یک نشانی اینترنتی http ، https ، یا ftp کاملاً واجد شرایط نیست.",
"The field {0} is invalid.": "فیلد {0} نامعتبر است.", "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.": "این قسمت شماره کارت اعتباری معتبری نیست.", "ThisFieldIsNotAValidCreditCardNumber.": "این قسمت شماره کارت اعتباری معتبری نیست.",
"ThisFieldIsNotValid.": "این قسمت معتبر نیست.", "ThisFieldIsNotValid.": "این قسمت معتبر نیست.",
"ThisFieldIsNotAValidEmailAddress.": "این قسمت آدرس ایمیل معتبری نیست.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Tämä kenttä ei ole kelvollinen luottokortin numero.",
"ThisFieldIsNotValid.": "Tämä kenttä ei kelpaa.", "ThisFieldIsNotValid.": "Tämä kenttä ei kelpaa.",
"ThisFieldIsNotAValidEmailAddress.": "Tämä kenttä ei ole kelvollinen sähköpostiosoite.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Ce champ n'est pas un numéro de carte de crédit valide.",
"ThisFieldIsNotValid.": "Ce champ n'est pas valide.", "ThisFieldIsNotValid.": "Ce champ n'est pas valide.",
"ThisFieldIsNotAValidEmailAddress.": "Ce champ n'est pas une adresse e-mail 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 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 {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 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.": "यह फ़ील्ड मान्य क्रेडिट कार्ड नंबर नहीं है।", "ThisFieldIsNotAValidCreditCardNumber.": "यह फ़ील्ड मान्य क्रेडिट कार्ड नंबर नहीं है।",
"ThisFieldIsNotValid.": "यह फ़ील्ड मान्य नहीं है।", "ThisFieldIsNotValid.": "यह फ़ील्ड मान्य नहीं है।",
"ThisFieldIsNotAValidEmailAddress.": "यह फ़ील्ड मान्य ई-मेल पता नहीं है।", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Ovo polje nije važeći broj kreditne kartice.",
"ThisFieldIsNotValid.": "Ovo polje nije valjano.", "ThisFieldIsNotValid.": "Ovo polje nije valjano.",
"ThisFieldIsNotAValidEmailAddress.": "Ovo polje nije valjana e-mail adresa.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "A mező nem érvényes bankkártya számot tartalmaz.",
"ThisFieldIsNotValid.": "A mező nem érvényes.", "ThisFieldIsNotValid.": "A mező nem érvényes.",
"ThisFieldIsNotAValidEmailAddress.": "A mező nem érvényes email cím.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Þessi reitur hefur ekki gilt kreditkortanúmer.",
"ThisFieldIsNotValid.": "Reiturinn er ekki rétt útfylltur.", "ThisFieldIsNotValid.": "Reiturinn er ekki rétt útfylltur.",
"ThisFieldIsNotAValidEmailAddress.": "Þessi reitur hefur ekki gilt netfang.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Questo campo non è un numero di carta di credito valido.",
"ThisFieldIsNotValid.": "Questo campo non è valido.", "ThisFieldIsNotValid.": "Questo campo non è valido.",
"ThisFieldIsNotAValidEmailAddress.": "Questo campo non è un indirizzo e-mail 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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Dit veld is geen geldig krediet kaartnummer.",
"ThisFieldIsNotValid.": "Dir veld is ongeldig.", "ThisFieldIsNotValid.": "Dir veld is ongeldig.",
"ThisFieldIsNotAValidEmailAddress.": "Dit veld is geen geldig e-mail adres.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "To pole nie jest prawidłowym numerem karty kredytowej.",
"ThisFieldIsNotValid.": "To pole jest nieprawidłowe.", "ThisFieldIsNotValid.": "To pole jest nieprawidłowe.",
"ThisFieldIsNotAValidEmailAddress.": "To pole nie jest prawidłowym adresem e-mail.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Não é um cartão de crédito válido.",
"ThisFieldIsNotValid.": "Campo inválido.", "ThisFieldIsNotValid.": "Campo inválido.",
"ThisFieldIsNotAValidEmailAddress.": "E-mail 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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Acest câmp nu este un număr de card de credit valid.",
"ThisFieldIsNotValid.": "Acest câmp nu este valid.", "ThisFieldIsNotValid.": "Acest câmp nu este valid.",
"ThisFieldIsNotAValidEmailAddress.": "Acest câmp nu este o adresă de e-mail 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 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 {0} field is not a valid fully-qualified http, https, or ftp URL.": "Поле {0} не является действительным полным http, https или ftp адресом.",
"The field {0} is invalid.": "Значение в поле {0} недопустимо.", "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.": "Это поле не содержит действительный номер кредитной карты.", "ThisFieldIsNotAValidCreditCardNumber.": "Это поле не содержит действительный номер кредитной карты.",
"ThisFieldIsNotValid.": "Значение в этом поле недействительно.", "ThisFieldIsNotValid.": "Значение в этом поле недействительно.",
"ThisFieldIsNotAValidEmailAddress.": "Это поле не содержит действительный адрес электронной почты.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "V tomto poli nie je platné číslo kreditnej karty.",
"ThisFieldIsNotValid.": "Toto pole nie je platné.", "ThisFieldIsNotValid.": "Toto pole nie je platné.",
"ThisFieldIsNotAValidEmailAddress.": "V tomto poli nie je platná e-mailová adresa.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "To polje ni veljavna številka kreditne kartice.",
"ThisFieldIsNotValid.": "To polje ni veljavno.", "ThisFieldIsNotValid.": "To polje ni veljavno.",
"ThisFieldIsNotAValidEmailAddress.": "To polje ni veljaven e-poštni naslov.", "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 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 {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 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.", "ThisFieldIsNotAValidCreditCardNumber.": "Bu alan geçerli bir kredi kartı numarası olmalıdır.",
"ThisFieldIsNotValid.": "Bu alan geçerli değil.", "ThisFieldIsNotValid.": "Bu alan geçerli değil.",
"ThisFieldIsNotAValidEmailAddress.": "Bu alan geçerli bir e-posta adresi olmalıdır.", "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.", "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." "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 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 {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 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ệ.", "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ệ.", "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ệ.", "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 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 {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 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.": "字段不是有效的信用卡号码.", "ThisFieldIsNotAValidCreditCardNumber.": "字段不是有效的信用卡号码.",
"ThisFieldIsNotValid.": "验证未通过.", "ThisFieldIsNotValid.": "验证未通过.",
"ThisFieldIsNotAValidEmailAddress.": "字段不是有效的邮箱地址.", "ThisFieldIsNotAValidEmailAddress.": "字段不是有效的邮箱地址.",
@ -33,4 +36,4 @@
"ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "字段{0}不是有效的完全限定的http,https或ftp URL.", "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "字段{0}不是有效的完全限定的http,https或ftp URL.",
"ThisFieldIsInvalid.": "该字段无效." "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 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 {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 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.": "此欄位不是有效的信用卡號碼.", "ThisFieldIsNotAValidCreditCardNumber.": "此欄位不是有效的信用卡號碼.",
"ThisFieldIsNotValid.": "此驗證未通過.", "ThisFieldIsNotValid.": "此驗證未通過.",
"ThisFieldIsNotAValidEmailAddress.": "此欄位不是有效的郵箱地址.", "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;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Xunit; using Xunit;
@ -59,7 +60,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase
jobObject.ExecutedValues.ShouldContain("42"); jobObject.ExecutedValues.ShouldContain("42");
} }
[Fact] [Fact]
public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant() public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant()
{ {
@ -77,7 +78,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase
new MyJobArgs("42", tenantId) new MyJobArgs("42", tenantId)
) )
); );
await _backgroundJobExecuter.ExecuteAsync( await _backgroundJobExecuter.ExecuteAsync(
new JobExecutionContext( new JobExecutionContext(
ServiceProvider, ServiceProvider,
@ -91,4 +92,48 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase
jobObject.TenantId.ShouldBe(tenantId); jobObject.TenantId.ShouldBe(tenantId);
asyncJobObject.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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs; namespace Volo.Abp.BackgroundJobs;
public class MyAsyncJob : AsyncBackgroundJob<MyAsyncJobArgs>, ISingletonDependency public class MyAsyncJob : AsyncBackgroundJob<MyAsyncJobArgs>, ISingletonDependency
{ {
public List<string> ExecutedValues { get; } = new List<string>(); public List<string> ExecutedValues { get; } = new List<string>();
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
private readonly ICurrentTenant _currentTenant; 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; _currentTenant = currentTenant;
_cancellationTokenProvider = cancellationTokenProvider;
} }
public override Task ExecuteAsync(MyAsyncJobArgs args) public override Task ExecuteAsync(MyAsyncJobArgs args)
{ {
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
Canceled = true;
}
ExecutedValues.Add(args.Value); ExecutedValues.Add(args.Value);
TenantId = _currentTenant.Id; TenantId = _currentTenant.Id;
return Task.CompletedTask; return Task.CompletedTask;

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

@ -1,25 +1,38 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs; namespace Volo.Abp.BackgroundJobs;
public class MyJob : BackgroundJob<MyJobArgs>, ISingletonDependency public class MyJob : BackgroundJob<MyJobArgs>, ISingletonDependency
{ {
public List<string> ExecutedValues { get; } = new List<string>(); public List<string> ExecutedValues { get; } = new List<string>();
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
private readonly ICurrentTenant _currentTenant; private readonly ICurrentTenant _currentTenant;
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public MyJob(ICurrentTenant currentTenant)
public bool Canceled { get; set; }
public MyJob(
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider)
{ {
_currentTenant = currentTenant; _currentTenant = currentTenant;
_cancellationTokenProvider = cancellationTokenProvider;
} }
public override void Execute(MyJobArgs args) public override void Execute(MyJobArgs args)
{ {
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
Canceled = true;
}
ExecutedValues.Add(args.Value); ExecutedValues.Add(args.Value);
TenantId = _currentTenant.Id; 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 System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Account.Settings;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.Settings;
namespace Volo.Abp.Account.Web.Pages.Account; namespace Volo.Abp.Account.Web.Pages.Account;
@ -28,7 +30,12 @@ public class LogoutModel : AccountPageModel
return RedirectSafely(ReturnUrl, ReturnUrlHash); 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() 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;
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; namespace Volo.Abp.BackgroundJobs.DemoApp.HangFire;
class Program 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(); await application.InitializeAsync();
}))
{ await CancelableBackgroundJobAsync(application.ServiceProvider);
application.Initialize();
Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!"); Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine(); 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;
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; namespace Volo.Abp.BackgroundJobs.DemoApp.Quartz;
class Program 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(); options.UseAutofac();
})) }))
{ {
application.Initialize(); await application.InitializeAsync();
await CancelableBackgroundJobAsync(application.ServiceProvider);
Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!"); Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine(); 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;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundJobs.DemoApp.RabbitMq; namespace Volo.Abp.BackgroundJobs.DemoApp.RabbitMq;
class Program 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(); options.UseAutofac();
})) }))
{ {
application.Initialize(); await application.InitializeAsync();
Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!"); Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine(); 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;
using System.Threading;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs 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;
using System.Threading;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs 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.DemoApp.Shared;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore; using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
@ -27,19 +28,21 @@ public class DemoAppModule : AbpModule
Configure<AbpBackgroundJobWorkerOptions>(options => Configure<AbpBackgroundJobWorkerOptions>(options =>
{ {
//Configure for fast running //Configure for fast running
options.JobPollPeriod = 1000; options.JobPollPeriod = 1000;
options.DefaultFirstWaitDuration = 1; options.DefaultFirstWaitDuration = 1;
options.DefaultWaitFactor = 1; options.DefaultWaitFactor = 1;
}); });
} }
public override void OnApplicationInitialization(ApplicationInitializationContext context) public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
{ {
//TODO: Configure console logging //TODO: Configure console logging
//context //context
// .ServiceProvider // .ServiceProvider
// .GetRequiredService<ILoggerFactory>() // .GetRequiredService<ILoggerFactory>()
// .AddConsole(LogLevel.Debug); // .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;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundJobs.DemoApp; namespace Volo.Abp.BackgroundJobs.DemoApp;
class Program 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(); options.UseAutofac();
})) }))
{ {
application.Initialize(); await application.InitializeAsync();
Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Started: " + typeof(Program).Namespace);
Console.WriteLine("Press ENTER to stop the application..!"); Console.WriteLine("Press ENTER to stop the application..!");
Console.ReadLine(); 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", "name": "asp.net",
"private": true, "private": true,
"dependencies": { "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" "highlight.js": "^9.13.1"
}, },
"devDependencies": {} "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", "name": "asp.net",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.1", "@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.2",
"@abp/prismjs": "^7.1.0-rc.1" "@abp/prismjs": "^7.1.0-rc.2"
}, },
"devDependencies": {} "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", "name": "volo.blogtestapp",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.1", "@abp/aspnetcore.mvc.ui.theme.basic": "^7.1.0-rc.2",
"@abp/blogging": "^7.1.0-rc.1" "@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 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); 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.Admin.Pages.Blogging.Admin.Blogs
@using Volo.Blogging @using Volo.Blogging
@using Microsoft.AspNetCore.Mvc.Localization @using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using Volo.Blogging.Localization @using Volo.Blogging.Localization
@inherits Volo.Blogging.Admin.Pages.Blogging.BloggingAdminPage @inherits Volo.Blogging.Admin.Pages.Blogging.BloggingAdminPage
@model IndexModel @model IndexModel
@ -12,6 +13,11 @@
@{ @{
ViewBag.PageTitle = "Blogs"; ViewBag.PageTitle = "Blogs";
} }
@inject IPageLayout PageLayout
@{
PageLayout.Content.Title = L["Blogs"].Value;
PageLayout.Content.MenuItemName = BloggingAdminMenuNames.Blogs;
}
@section scripts { @section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName"> <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)); var postDto = await _postAppService.GetAsync(new Guid(PostId));
Post = ObjectMapper.Map<PostWithDetailsDto, EditPostViewModel>(postDto); Post = ObjectMapper.Map<PostWithDetailsDto, EditPostViewModel>(postDto);
Post.Tags = String.Join(", ", postDto.Tags.Select(p => p.Name).ToArray()); Post.Tags = String.Join(", ", postDto.Tags.Select(p => p.Name).ToArray());
Post.Url = WebUtility.UrlDecode(Post.Url);
return Page(); return Page();
} }
@ -60,7 +61,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
{ {
BlogId = Post.BlogId, BlogId = Post.BlogId,
Title = Post.Title, Title = Post.Title,
Url = Post.Url, Url = WebUtility.UrlEncode(Post.Url),
CoverImage = Post.CoverImage, CoverImage = Post.CoverImage,
Content = Post.Content, Content = Post.Content,
Tags = Post.Tags, 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.Description = Post.Content.Truncate(PostConsts.MaxSeoFriendlyDescriptionLength);
} }
Post.Url = WebUtility.UrlEncode(Post.Url);
var postWithDetailsDto = await _postAppService.CreateAsync(ObjectMapper.Map<CreatePostViewModel, CreatePostDto>(Post)); var postWithDetailsDto = await _postAppService.CreateAsync(ObjectMapper.Map<CreatePostViewModel, CreatePostDto>(Post));
//TODO: Try Url.Page(...) //TODO: Try Url.Page(...)

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

@ -3,6 +3,6 @@
"name": "client-simulation-web", "name": "client-simulation-web",
"private": true, "private": true,
"dependencies": { "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, "private": true,
"dependencies": { "dependencies": {
"@abp/ng.account": "~7.1.0-rc.1", "@abp/ng.account": "~7.1.0-rc.2",
"@abp/ng.identity": "~7.1.0-rc.1", "@abp/ng.identity": "~7.1.0-rc.2",
"@abp/ng.setting-management": "~7.1.0-rc.1", "@abp/ng.setting-management": "~7.1.0-rc.2",
"@abp/ng.tenant-management": "~7.1.0-rc.1", "@abp/ng.tenant-management": "~7.1.0-rc.2",
"@abp/ng.theme.basic": "~7.1.0-rc.1", "@abp/ng.theme.basic": "~7.1.0-rc.2",
"@angular/animations": "~10.0.0", "@angular/animations": "~10.0.0",
"@angular/common": "~10.0.0", "@angular/common": "~10.0.0",
"@angular/compiler": "~10.0.0", "@angular/compiler": "~10.0.0",

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

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

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

Loading…
Cancel
Save