diff --git a/docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md new file mode 100644 index 0000000000..36905df43c --- /dev/null +++ b/docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md @@ -0,0 +1,73 @@ +# ABP Framework v2.0 Has Been Released + +ABP Framework v2.0 has been released in this week. This post explains why we've released an early major version and what is changed with the v2.0. + +## Why 2.0 instead of 1.2? + +Actually, it was planned to release v1.2 after the [v1.1.2](https://github.com/abpframework/abp/releases/tag/1.1.2) release. However, [it is reported](https://github.com/abpframework/abp/issues/2026) that v1.x has some **performance** and **stability** problems on Linux, especially when you deploy your application into **Linux** containers with **low CPU and memory** resources. + +We have investigated the problem deeply and have seen that the root cause of the problem is related to the implementation of **intercepting async methods**. In addition, there were some **async over sync** usages effected the thread pool optimization. + +Finally, we **solved all the problems** with the huge help of the **community**. But we also had some important **design decisions** which cause some **breaking changes** and we had to change the major version number of the framework because of the **semantic versioning**. + +Most of the applications won't be effected by [the breaking changes](https://github.com/abpframework/abp/releases), or it will be trivial to make necessary changes. + +## Breaking Changes + +### Removed Some Sync APIs + +We've [removed some sync APIs](https://github.com/abpframework/abp/pull/2464) because they eventually causes async over sync problems. Because some of the interceptors need to use async APIs and if they intercept sync methods they need to call async over sync. + +**Async over sync** problem is a classic problem of C# when you need to **call an async method inside a sync method**. While there are some solutions to this problem, they all have **disadvantages** and it is suggested to **not write** such code at all. You can find plenty of documents related to this topic on the web, so I will not write more about it. + +So, to not cause this problem; + +* Removed sync [Repository](https://docs.abp.io/en/abp/latest/Repositories) methods (like Insert, Update... etc). +* Removed sync APIs of the [Unit Of Work](https://docs.abp.io/en/abp/latest/Unit-Of-Work). +* Removed sync API of the [background jobs](https://docs.abp.io/en/abp/latest/Background-Jobs). +* Removed sync APIs of [Audit logging](https://docs.abp.io/en/abp/latest/Audit-Logging). + +Also removed some other rarely used sync APIs. If you get any compile error, just use the async versions of these APIs. + +### Always Async! + +Beginning from the v2.0, ABP framework assumes that you are writing your application code async. Otherwise, some framework funtionalities may not properly work. + +It is suggested to write async for all your [application services](https://docs.abp.io/en/abp/latest/Application-Services), [repository methods](https://docs.abp.io/en/abp/latest/Repositories), controller actions, page handlers. + +Even if your application service method doesn't need to be async, write it as async, because interceptors perform async operations (for authorization, unit of work... etc.). You can return `Task.Completed` from a method that doesn't make an async call. + +Example: + +````csharp +public Task GetValueAsync() +{ + ... + return Task.CompletedTask(42); +} +```` + +The example above doesn't need to be async because it doesn't perform an async call to any service. However, making it async helps to the ABP framework to run interceptors without async over sync calls. + +This rule doesn't force you to write every method async. This would not be good and would be tedious. It is only needed for the intercepted services (especially for [application services](https://docs.abp.io/en/abp/latest/Application-Services) and [repository methods](https://docs.abp.io/en/abp/latest/Repositories)) + +### Other Breaking Changes + +See [the release notes](https://github.com/abpframework/abp/releases/tag/2.0.0) for the other breaking changes while most of them will not effect your application code. + +## New Features + +This release also contains a few new features and tens of enhancements. Some of them are; + +* [#2597](https://github.com/abpframework/abp/pull/2597) New Volo.Abp.AspNetCore.Serilog package. +* [#2526](https://github.com/abpframework/abp/issues/2526) Client side validation for the dynamic C# client proxies. +* [#2374](https://github.com/abpframework/abp/issues/2374) Async background jobs. +* [#265](https://github.com/abpframework/abp/issues/265) Managing the application shutdown. +* [#2472](https://github.com/abpframework/abp/issues/2472) Implemented DeviceFlowCodes and TokenCleanupService for the IdentityServer module. + +See [the release notes](https://github.com/abpframework/abp/releases/tag/2.0.0) for the other features, enhancements and bug fixes. + +## Documentation + +We've completed some missing documentation with the v2.0 release. In the next weeks, we will mostly focus on the basic documentation and tutorials. + diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs index 3fdd0aae1d..a8ac0e0357 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs @@ -45,5 +45,10 @@ namespace Volo.Abp.Cli.Auth FileHelper.DeleteIfExists(CliPaths.AccessToken); return Task.CompletedTask; } + + public static bool IsLoggedIn() + { + return File.Exists(CliPaths.AccessToken); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs index 81c64a3b5f..ca1a23fcfc 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Http/CliHttpClient.cs @@ -3,6 +3,7 @@ using System.IO; using System.Net.Http; using System.Text; using IdentityModel.Client; +using Volo.Abp.Cli.Auth; namespace Volo.Abp.Cli.Http { @@ -29,7 +30,7 @@ namespace Volo.Abp.Cli.Http private static void AddAuthentication(HttpClient client) { - if (!File.Exists(CliPaths.AccessToken)) + if (!AuthService.IsLoggedIn()) { return; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs index 4ed8746ce6..a22b6bba4a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Polly; using Polly.Extensions.Http; +using Volo.Abp.Cli.Auth; using Volo.Abp.Cli.Http; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; @@ -31,6 +32,11 @@ namespace Volo.Abp.Cli.Licensing public async Task GetApiKeyOrNullAsync(bool invalidateCache = false) { + if (!AuthService.IsLoggedIn()) + { + return null; + } + if (invalidateCache) { _apiKeyResult = null; @@ -81,17 +87,6 @@ namespace Volo.Abp.Cli.Licensing var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var apiKeyResult = JsonSerializer.Deserialize(responseContent); - if (apiKeyResult == null || - string.IsNullOrEmpty(apiKeyResult.ApiKey)) - { - _logger.LogError("Couldn't retrieve your NuGet API key!"); - _logger.LogWarning(File.Exists(CliPaths.AccessToken) - ? "Make sure you have an active session and license on commercial.abp.io. To re-sign in you can use the CLI command \"abp login \"." - : "You are not signed in to commercial.abp.io. Use the CLI command \"abp login \" to sign in."); - - return null; - } - return apiKeyResult; } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.html index 985ea58888..a7d5e77fb7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.html @@ -3,14 +3,14 @@
-
{{ toast.title | abpLocalization: toast.options?.titleLocalizationParams }}
-
+

{{ toast.message | abpLocalization: toast.options?.messageLocalizationParams }} -

+

diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.scss b/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.scss index 1bd780815c..be5c871082 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.scss +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.scss @@ -45,7 +45,7 @@ } .toast-content { position: relative; - .close-button { + .toast-close-button { position: absolute; top: 0; right: 0; @@ -53,20 +53,16 @@ align-items: center; justify-content: center; margin: 0; - padding: 5px 10px 5px 5px; + padding: 0px 5px 0 0; width: 25px; height: 25px; border: none; border-radius: 50%; background: transparent; + color: inherit; &:focus { outline: none; } - .close-icon { - width: 16px; - height: 16px; - stroke: #000; - } } .toast-title { margin: 0; @@ -75,6 +71,8 @@ font-weight: 600; } .toast-message { + margin: 0; + padding: 0; } } }