diff --git a/docs/en/CLI.md b/docs/en/CLI.md
index f2da02d889..57e27c23ec 100644
--- a/docs/en/CLI.md
+++ b/docs/en/CLI.md
@@ -27,6 +27,7 @@ While each command may have a set of options, there are some global options that
Here, is the list of all available commands before explaining their details:
* **`help`**: Shows help on the usage of the ABP CLI.
+* **`cli`**: Update or remove ABP CLI.
* **`new`**: Generates a new solution based on the ABP [startup templates](Startup-Templates/Index.md).
* **`update`**: Automatically updates all ABP related NuGet and NPM packages in a solution.
* **`clean`**: Deletes all `BIN` and `OBJ` folders in the current folder.
@@ -63,6 +64,25 @@ abp help # Shows a general help.
abp help new # Shows help about the "new" command.
````
+### cli
+
+Update or remove ABP CLI.
+
+Usage:
+
+````bash
+abp cli [command-name]
+````
+
+Examples:
+
+````bash
+abp cli update
+abp cli update --preview
+abp cli update --version 5.0.0
+abp cli remove
+````
+
### new
Generates a new solution based on the ABP [startup templates](Startup-Templates/Index.md).
@@ -106,6 +126,9 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
+ * `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes:
+ * `leptonx-lite`: [LeptonX Lite Theme](/Themes/LeptonXLite/mvc.md).
+ * `basic`: [Basic Theme](/UI/AspNetCore/Basic-Theme.md).
* **`module`**: [Module template](Startup-Templates/Module.md). Additional options:
* `--no-ui`: Specifies to not include the UI. This makes possible to create service-only modules (a.k.a. microservices - without UI).
* **`console`**: [Console template](Startup-Templates/Console.md).
@@ -118,6 +141,9 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
+ * `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes:
+ * `leptonx-lite`: [LeptonX Lite Theme](/Themes/LeptonXLite/mvc.md).
+ * `basic`: [Basic Theme](/UI/AspNetCore/Basic-Theme.md).
* `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory.
* `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version.
* `--preview`: Use latest preview version.
diff --git a/docs/en/Startup-Templates/Index.md b/docs/en/Startup-Templates/Index.md
index 09755151db..68ab3369f1 100644
--- a/docs/en/Startup-Templates/Index.md
+++ b/docs/en/Startup-Templates/Index.md
@@ -3,6 +3,7 @@
While you can start with an empty project and add needed packages manually, startup templates make easy and comfortable to start a new solution with the ABP framework. Click the name from the list below to see the documentation of the related startup template:
* [**app**](Application.md): Application template.
+* [**app-nolayers**](Application-Single-Layer.md): Application (single layer) template.
* [**module**](Module.md): Module/service template.
* [**console**](Console.md): Console template.
* [**WPF**](WPF.md): WPF template.
diff --git a/docs/en/Tutorials/Todo/Single-Layer/Index.md b/docs/en/Tutorials/Todo/Single-Layer/Index.md
index 0dcabf664e..883a756cc7 100644
--- a/docs/en/Tutorials/Todo/Single-Layer/Index.md
+++ b/docs/en/Tutorials/Todo/Single-Layer/Index.md
@@ -74,7 +74,7 @@ It is good to run the application before starting the development. The solution
Firstly, run the `TodoApp` project in your favorite IDE (or run the `dotnet run` CLI command on your project directory) to see the server-side HTTP API on [Swagger UI](https://swagger.io/tools/swagger-ui/):
-
+
You can explore and test your HTTP API with this UI. If it works, then we can run the Angular client application.
diff --git a/docs/en/Tutorials/Todo/Single-Layer/todo-single-layer-ui-initial.png b/docs/en/Tutorials/Todo/Single-Layer/todo-single-layer-ui-initial.png
new file mode 100644
index 0000000000..2393505147
Binary files /dev/null and b/docs/en/Tutorials/Todo/Single-Layer/todo-single-layer-ui-initial.png differ
diff --git a/docs/en/UI/Angular/Breadcrumb.md b/docs/en/UI/Angular/Breadcrumb.md
new file mode 100644
index 0000000000..58ae826278
--- /dev/null
+++ b/docs/en/UI/Angular/Breadcrumb.md
@@ -0,0 +1,50 @@
+## Breadcrumb Component
+
+ABP provides a component that listens to the angular router's `NavigationEnd`
+event and creates inputs for `BreadcrumbItemsComponent`. This component is used in
+ABP components with [`PageComponent`](./Page-Component.md).
+
+## Breadcrumb Items Component
+
+`BreadcrumbItemsComponent` is used to display breadcrumb items. It can be useful
+when you want to display breadcrumb items in a different way than the default.
+
+### Usage
+
+Example of overriding the default template of `PageComponent`:
+
+```html
+
+
+
+
+
+```
+
+```js
+import { Component } from "@angular/core";
+import { ABP } from "@abp/ng.core";
+
+@Component({
+ /* component metadata */
+})
+export class YourComponent {
+ breadCrumbItems: ABP.Route[] = [
+ {
+ name: "Item 1",
+ },
+ {
+ name: "Item 2",
+ path: "/path",
+ },
+ ];
+}
+```
+
+### Inputs
+
+- items: Partial[] : Array of ABP.Route objects. The source code of ABP.Route can be found in [github](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/common.ts#L69).
+
+## See Also
+
+- [Page Component](./Page-Component.md)
diff --git a/docs/en/UI/Blazor/Global-Features.md b/docs/en/UI/Blazor/Global-Features.md
new file mode 100644
index 0000000000..908f6871e4
--- /dev/null
+++ b/docs/en/UI/Blazor/Global-Features.md
@@ -0,0 +1,25 @@
+# Blazor UI: Global Features
+`GlobalFeatureManager` allows you to check the global features in your Blazor applications.
+
+## Usage
+
+```html
+@using Volo.Abp.GlobalFeatures
+
+@* ... *@
+
+@* Global Feature can be checked with feature name *@
+@if(GlobalFeatureManager.Instance.IsEnabled("Ecommerce.Subscription"))
+{
+ Ecommerce.Subscription is enabled.
+}
+
+@* OR it can be checked with type *@
+
+@if(GlobalFeatureManager.Instance.IsEnabled())
+{
+ Ecommerce.Subscription is enabled.
+}
+```
+
+- You can follow _Check for a Global Feature_ section of the [Global Features document](../../Global-Features.md) to check global features in your C# code.
\ No newline at end of file
diff --git a/docs/en/UI/Blazor/Pwa-Configuration.md b/docs/en/UI/Blazor/Pwa-Configuration.md
new file mode 100644
index 0000000000..c687d040ef
--- /dev/null
+++ b/docs/en/UI/Blazor/Pwa-Configuration.md
@@ -0,0 +1,249 @@
+# PWA Configuration
+
+[PWAs (Progressive Web Apps)](https://web.dev/progressive-web-apps/) are developed using specific technologies to allow applications to take advantage of both web and native app features.
+
+Here is a list of some features that PWA provides:
+
+- **Installable**: A web application can be installed and used like a native/desktop application.
+- **Network Independent**: PWAs support offline scenarios. It can work offline or with a poor network connection.
+- **Responsive**: It's usable on any devices such as mobile phones, tablets, laptops, etc.
+
+## Creating a Project with PWA Support
+
+You can create a new web application with PWA support for **Blazor WebAssembly** by using the `--pwa` option as below:
+
+```bash
+abp new Acme.BookStore -t blazor --pwa
+```
+
+After this command, your application will be created and some additional PWA related files (such as **manifest**, **icons**, **service workers**, etc.) will be added. Then, you can get the full advantages of web and native app features.
+
+## Adding PWA Support to an Existing Project
+
+If you started your application without PWA support, it's possible to change your mind and get the benefit of PWA later. You only need to make some configurations as listed below:
+
+### 1-) Add the `manifest.json` File
+
+> Web Application Manifest provides information about a web application in a JSON text file and it's required for the web application to be downloaded and be presented to the user similarly to a native application.
+
+First, you need to create a JSON file named **manifest.json** under the **wwwroot** folder and define some pieces of information about your application. You can see an example **manifest.json** file content below:
+
+```json
+{
+ "name": "MyProjectName",
+ "short_name": "MyCompanyName.MyProjectName",
+ "start_url": "./",
+ "display": "standalone",
+ "background_color": "#ffffff",
+ "theme_color": "#03173d",
+ "prefer_related_applications": false,
+ "icons": [
+ {
+ "src": "icon-512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ },
+ {
+ "src": "icon-192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ }
+ ]
+}
+```
+
+- Some application specific information should be defined in this file.
+- For example, you can configure which icon needs to be seen in which screen size, background color, description, etc.
+
+### 2-) Add Icons for Specific Screen Sizes (Optional)
+
+You can add some icons for your application to be seen in specific screen sizes and define in which screen sizes icons should be displayed in the **manifest.json** file. You can see the **icons** section in the **manifest.json** file as an example above.
+
+> You can use, default icons from our [template](https://github.com/abpframework/abp/tree/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot).
+
+### 3-) Configure Service Workers
+
+> Service workers are one of the fundamental parts of PWAs. They enable fast loading (regardless of the network), offline access, push notifications, and other web/native app capabilities. They run in the background and don't block the main thread so they don't slow your application.
+
+You need to create `service-worker.js` and `service-worker.published.js` files under the **wwwroot** folder of your project. These files will be used by your project to determine which PWA features you want to use.
+
+You can get the simple configurations for the [service-worker.js](https://github.com/abpframework/abp/blob/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/service-worker.js) and [service-worker.published.js](https://github.com/abpframework/abp/blob/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot/service-worker.published.js) files from our [template](https://github.com/abpframework/abp/tree/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/wwwroot).
+
+After the related service worker files are added, then we need to define them in our `.csproj` file to notify our application. So open your `*.csproj` file and add the following content:
+
+```xml
+
+ net6.0
+ true
+
+
+ service-worker-assets.js
+
+
+
+
+
+
+```
+
+* With the `ServiceWorkerAssetsManifest` MSBuild property, your Blazor application generates a service worker assets manifest with the specified name. This file will be generated in the path of `/bin/Debug/{TARGET FRAMEWORK}/wwwroot/service-worker-assets.js` on runtime. This manifest can list all resources such as images, stylesheets, JS files etc. by examining the `service-worker.published.js` file (regarding to your configurations in this file).
+* The `ServiceWorker` property is used to define which files need to be accounted as **Service Worker** files and service workers are used to determine which PWA features should be used.
+
+
+### 4-) Define Web Application Manifest and Register Service Workers
+
+Finally, now you can define the `manifest.json` file and **icons** in the **index.html** file and register the **service workers** for your application.
+
+Let's start with adding `` elements (between `` tags) for the manifest and app icon in the **index.html** file (under the **wwwroot** folder):
+
+```html
+
+
+
+
+
+
+```
+
+Then, add the following `
+
+```
+
+You've added the related files and made the related configurations with this final touch to add PWA support to your existing application. Now, you can take full advantage of PWAs.
+
+## Differences Between the Debug and Published Service Workers
+
+Application Template produces two service worker files, if you create your application with PWA support:
+
+* The `service-worker.js` file is used during development and does nothing by default.
+* The `service-worker.published.js` file, which is used after the app is published. Caches certain file extensions and supports offline scenarios by default (uses a *cache-first* strategy). A user must first visit the app while they're online. The browser automatically downloads and caches all of the resources required to operate offline and then when the network connection is disconnected, it can be used like before.
+
+You can configure those files as mentioned in the *Customize Service Workers* section down below.
+
+> If you want to share logic between those two service worker files, you can consider creating a third JS file and hold the common logic in this file or use the [self.importScripts](https://developer.mozilla.org/docs/Web/API/WorkerGlobalScope/importScripts)s to load the common logic into both service worker files.
+
+## Customization
+
+You can customize the `manifest.json`, `service-worker.js` and `service-worker.published.js` files generated by the ABP Framework if you created an application with PWA support.
+
+### Customize Web Application Manifest (`manifest.json`)
+
+> The web app manifest is a JSON file that tells the browser about your Progressive Web App and how it should behave when installed on the user's desktop or mobile device. A typical manifest file includes the app name, the icons the app should use, and the URL that should be opened when the app is launched. - From [web.dev](https://web.dev/add-manifest)
+
+You can customize the `manifest.json` file (under the **wwwroot** folder) to your needs. You can set the **name**, **short_name**, **icons**, **description**, **start_url**, etc. You can see an example `manifest.json` file content below:
+
+```json
+{
+ "name": "Acme.BookStore",
+ "short_name": "BookStore",
+ "description": "My application description",
+ "theme_color": "#000000",
+ "background_color": "#ffffff",
+ "icons": [
+ {
+ "src": "../icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "../icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ]
+ // other properties...
+}
+```
+
+* You must provide at least the `short_name` or `name` property. If both of these properties are provided, the `short_name` property is used almost anywhere like the **launcher** and the **home** screen.
+* For Chromium based browsers, you must provide at least a *192x192* px icon and a *512x512* px icon. If only those two icon sizes are provided, the browsers will automatically scale the icons to fit the device. If you don't want to let the browser auto-scale icons, you need to add icons for other sizes too.
+
+> You can see the other properties from [here](https://web.dev/add-manifest/#manifest-properties).
+
+### Customize Service Workers
+
+If you create your application with PWA support, two service worker files will be generated: `service-worker.js` and `service-worker.published.js`.
+
+ABP Framework's service-worker files are the same as the .NET Core's and it's valid for most of the time and you'll probably not need to configure it manually. However, if you want to configure the service workers you can do it easily.
+
+You can configure the `service-worker.js` file for debug mode and the `service-worker.published.js` file for release mode according to your own needs.
+
+#### `service-worker.js`
+
+```js
+// Caution: In development, always fetch from the network and do not enable offline support.
+self.addEventListener('fetch', () => { });
+```
+
+* Configuring this file, you can use additional PWA features in debug mode.
+* By default, it does nothing in debug mode, it fetches from the network (recommended) and does not support offline scenarios. You can change this behavior by configuring this file and also benefit from additional features of PWAs.
+
+#### `service-worker.published.js`
+
+```js
+// Caution: Be sure you understand the caveats before publishing an application with
+// offline support. See https://aka.ms/blazor-offline-considerations
+
+self.importScripts('./service-worker-assets.js');
+self.addEventListener('install', event => event.waitUntil(onInstall(event)));
+self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
+self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
+
+const cacheNamePrefix = 'offline-cache-';
+const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
+const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ];
+const offlineAssetsExclude = [ /^service-worker\.js$/ ];
+
+async function onInstall(event) {
+ console.info('Service worker: Install');
+
+ // Fetch and cache all matching items from the assets manifest
+ const assetsRequests = self.assetsManifest.assets
+ .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
+ .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
+ .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' }));
+ await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
+}
+
+async function onActivate(event) {
+ console.info('Service worker: Activate');
+
+ // Delete unused caches
+ const cacheKeys = await caches.keys();
+ await Promise.all(cacheKeys
+ .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
+ .map(key => caches.delete(key)));
+}
+
+async function onFetch(event) {
+ let cachedResponse = null;
+ if (event.request.method === 'GET') {
+ // For all navigation requests, try to serve index.html from cache
+ // If you need some URLs to be server-rendered, edit the following check to exclude those URLs
+ const shouldServeIndexHtml = event.request.mode === 'navigate';
+
+ const request = shouldServeIndexHtml ? 'index.html' : event.request;
+ const cache = await caches.open(cacheName);
+ cachedResponse = await cache.match(request);
+ }
+
+ return cachedResponse || fetch(event.request);
+}
+```
+
+* You can configure this file if you want to cache additional file extensions such as `.webp` or etc. You can also use some additional features of PWA by configuring this file.
+* By default, dll files (`*.dll`) and some static assets (`*.js`, `*.css`, etc.) are cached.
+* Cached files will be stored in the `service-worker-assets.js` (**/bin/Debug/{TARGET FRAMEWORK}/wwwroot/service-worker-assets.js**). You can change this file name by renaming it in between the `ServiceWorkerAssetsManifest` tags on your `*.csproj` file.
+
+## See Also
+
+* [ASP.NET Core Blazor Progressive Web Application (PWA)](https://docs.microsoft.com/en-us/aspnet/core/blazor/progressive-web-app).
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index e6f4e89ff0..7950313217 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -920,9 +920,17 @@
"text": "Global Scripts & Styles",
"path": "UI/Blazor/Global-Scripts-Styles.md"
},
+ {
+ "text": "Global Features",
+ "path": "UI/Blazor/Global-Features.md"
+ },
{
"text": "Routing",
"path": "UI/Blazor/Routing.md"
+ },
+ {
+ "text": "PWA Configuration",
+ "path": "UI/Blazor/Pwa-Configuration.md"
}
]
},
diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md
index fea3ec781f..96d78538ef 100644
--- a/docs/zh-Hans/CLI.md
+++ b/docs/zh-Hans/CLI.md
@@ -27,6 +27,7 @@ dotnet tool update -g Volo.Abp.Cli
这里是所有可用的命令列表:
* **`help`**: 展示ABP CLI的用法帮助信息.
+* **`cli`**: 更新或删除ABP CLI.
* **`new`**:生成基于ABP的[启动模板](Startup-Templates/Index.md).
* **`update`**:自动更新的ABP解决方案ABP相关的NuGet和NPM包.
* **`clean`**: 删除当前目录下所有的 `BIN` 和 `OBJ` 子目录.
@@ -60,6 +61,25 @@ abp help # Shows a general help.
abp help new # Shows help about the "new" command.
````
+### cli
+
+更新或删除ABP CLI
+
+用法:
+
+````bash
+abp cli [command-name]
+````
+
+示例:
+
+````bash
+abp cli update
+abp cli update --preview
+abp cli update --version 5.0.0
+abp cli remove
+````
+
### new
生成基于ABP[启动模板](Startup-Templates/Index.md)的新解决方案.
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
index 2071e40f0b..355f9fff44 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
@@ -64,7 +64,7 @@ public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITr
client.BaseAddress = new Uri(baseUrl);
foreach (var header in HttpContextAccessor.HttpContext.Request.Headers)
{
- requestMessage.Headers.Add(header.Key, header.Value.ToArray());
+ requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
index 28984ce5d0..193224ae65 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpAspNetCoreComponentsWebModule.cs
@@ -13,11 +13,6 @@ namespace Volo.Abp.AspNetCore.Components.Web;
)]
public class AbpAspNetCoreComponentsWebModule : AbpModule
{
- public override void PreConfigureServices(ServiceConfigurationContext context)
- {
-
- }
-
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(ServiceDescriptor.Transient());
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs
index bb053eac21..7473387f83 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs
@@ -7,11 +7,7 @@ using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Web.Security;
-[ExposeServices(
- typeof(AbpComponentsClaimsCache),
- typeof(IAsyncInitialize)
-)]
-public class AbpComponentsClaimsCache : IScopedDependency, IAsyncInitialize
+public class AbpComponentsClaimsCache : IScopedDependency
{
public ClaimsPrincipal Principal { get; private set; }
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs
index 5c77dcff49..21f29f995c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Microsoft/AspNetCore/Components/WebAssembly/Hosting/AbpWebAssemblyHostBuilderExtensions.cs
@@ -1,15 +1,12 @@
using System;
-using System.Globalization;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
-using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Components.Web.DependencyInjection;
using Volo.Abp.AspNetCore.Components.WebAssembly;
-using Volo.Abp.AspNetCore.Mvc.Client;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
@@ -76,34 +73,5 @@ public static class AbpWebAssemblyHostBuilderExtensions
.GetRequiredService()).ServiceProvider = serviceProvider;
await application.InitializeAsync(serviceProvider);
- await InitializeModulesAsync(serviceProvider);
- await SetCurrentLanguageAsync(serviceProvider);
- }
-
- private async static Task InitializeModulesAsync(IServiceProvider serviceProvider)
- {
- foreach (var service in serviceProvider.GetServices())
- {
- await service.InitializeAsync();
- }
- }
-
- private async static Task SetCurrentLanguageAsync(IServiceProvider serviceProvider)
- {
- var configurationClient = serviceProvider.GetRequiredService();
- var utilsService = serviceProvider.GetRequiredService();
- var configuration = await configurationClient.GetAsync();
- var cultureName = configuration.Localization?.CurrentCulture?.CultureName;
- if (!cultureName.IsNullOrEmpty())
- {
- var culture = new CultureInfo(cultureName);
- CultureInfo.DefaultThreadCurrentCulture = culture;
- CultureInfo.DefaultThreadCurrentUICulture = culture;
- }
-
- if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
- {
- await utilsService.AddClassToTagAsync("body", "rtl");
- }
}
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
index 56dd8106a3..33716d8383 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/AbpAspNetCoreComponentsWebAssemblyModule.cs
@@ -1,10 +1,15 @@
-using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Globalization;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Components.Web.ExceptionHandling;
+using Volo.Abp.AspNetCore.Components.Web.Security;
using Volo.Abp.AspNetCore.Mvc.Client;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
+using Volo.Abp.Threading;
using Volo.Abp.UI;
namespace Volo.Abp.AspNetCore.Components.WebAssembly;
@@ -33,4 +38,35 @@ public class AbpAspNetCoreComponentsWebAssemblyModule : AbpModule
.GetHostBuilder().Logging
.AddProvider(new AbpExceptionHandlingLoggerProvider(context.Services));
}
+
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context));
+ }
+
+ public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
+ {
+ await context.ServiceProvider.GetRequiredService().InitializeAsync();
+ await context.ServiceProvider.GetRequiredService().InitializeAsync();
+ await SetCurrentLanguageAsync(context.ServiceProvider);
+ }
+
+ private async static Task SetCurrentLanguageAsync(IServiceProvider serviceProvider)
+ {
+ var configurationClient = serviceProvider.GetRequiredService();
+ var utilsService = serviceProvider.GetRequiredService();
+ var configuration = await configurationClient.GetAsync();
+ var cultureName = configuration.Localization?.CurrentCulture?.CultureName;
+ if (!cultureName.IsNullOrEmpty())
+ {
+ var culture = new CultureInfo(cultureName);
+ CultureInfo.DefaultThreadCurrentCulture = culture;
+ CultureInfo.DefaultThreadCurrentUICulture = culture;
+ }
+
+ if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
+ {
+ await utilsService.AddClassToTagAsync("body", "rtl");
+ }
+ }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs
index 4dbd188a47..523a770a17 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs
@@ -7,11 +7,6 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.AspNetCore.Components.WebAssembly;
-[ExposeServices(
- typeof(WebAssemblyCachedApplicationConfigurationClient),
- typeof(ICachedApplicationConfigurationClient),
- typeof(IAsyncInitialize)
- )]
public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicationConfigurationClient, ITransientDependency
{
protected AbpApplicationConfigurationClientProxy ApplicationConfigurationAppService { get; }
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs
index f173082fa3..84621fd8c3 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/ICachedApplicationConfigurationClient.cs
@@ -3,7 +3,7 @@ using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
namespace Volo.Abp.AspNetCore.Mvc.Client;
-public interface ICachedApplicationConfigurationClient : IAsyncInitialize
+public interface ICachedApplicationConfigurationClient
{
Task GetAsync();
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
index a7dc58f82a..7a9168eefb 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs
@@ -1,5 +1,8 @@
-using Volo.Abp.EventBus;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.EventBus;
using Volo.Abp.Modularity;
+using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.Client;
@@ -9,4 +12,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Client;
)]
public class AbpAspNetCoreMvcClientModule : AbpModule
{
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context));
+ }
+
+ public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
+ {
+ await context.ServiceProvider.GetRequiredService().InitializeAsync();
+ }
}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs
index fba7a3fdfe..59690b2d03 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs
@@ -11,11 +11,6 @@ using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.Client;
-[ExposeServices(
- typeof(MvcCachedApplicationConfigurationClient),
- typeof(ICachedApplicationConfigurationClient),
- typeof(IAsyncInitialize)
- )]
public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigurationClient, ITransientDependency
{
protected IHttpContextAccessor HttpContextAccessor { get; }
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs
index dfeda11df8..c4cf1d6be0 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundWorkers.Hangfire;
@@ -8,12 +9,12 @@ public abstract class HangfireBackgroundWorkerBase : BackgroundWorkerBase, IHang
public string RecurringJobId { get; set; }
public string CronExpression { get; set; }
-
+
public TimeZoneInfo TimeZone { get; set; }
-
+
public string Queue { get; set; }
- public abstract Task DoWorkAsync();
+ public abstract Task DoWorkAsync(CancellationToken cancellationToken = default);
protected HangfireBackgroundWorkerBase()
{
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs
index b2cb275dab..0dc11e7e0a 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs
@@ -33,19 +33,19 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle
return Task.CompletedTask;
}
- public Task AddAsync(IBackgroundWorker worker)
+ public Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default)
{
if (worker is IHangfireBackgroundWorker hangfireBackgroundWorker)
{
var unProxyWorker = ProxyHelper.UnProxy(hangfireBackgroundWorker);
if (hangfireBackgroundWorker.RecurringJobId.IsNullOrWhiteSpace())
{
- RecurringJob.AddOrUpdate(() => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(),
+ RecurringJob.AddOrUpdate(() => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(cancellationToken),
hangfireBackgroundWorker.CronExpression, hangfireBackgroundWorker.TimeZone, hangfireBackgroundWorker.Queue);
}
else
{
- RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId, () => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(),
+ RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId, () => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(cancellationToken),
hangfireBackgroundWorker.CronExpression, hangfireBackgroundWorker.TimeZone, hangfireBackgroundWorker.Queue);
}
}
@@ -80,7 +80,7 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle
var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker));
var workerAdapter = Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker;
- RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(), GetCron(period.Value), workerAdapter.TimeZone, workerAdapter.Queue);
+ RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(cancellationToken), GetCron(period.Value), workerAdapter.TimeZone, workerAdapter.Queue);
}
return Task.CompletedTask;
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs
index 8fe24f10ed..e1cec7da85 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
@@ -17,9 +18,9 @@ public class HangfirePeriodicBackgroundWorkerAdapter : HangfireBackgrou
_doWorkMethod = typeof(TWorker).GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic);
}
- public async override Task DoWorkAsync()
+ public async override Task DoWorkAsync(CancellationToken cancellationToken = default)
{
- var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider);
+ var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider, cancellationToken);
var worker = ServiceProvider.GetRequiredService();
switch (worker)
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs
index 7402d8427a..883f488684 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.BackgroundWorkers.Hangfire;
@@ -8,12 +9,10 @@ public interface IHangfireBackgroundWorker : IBackgroundWorker
string RecurringJobId { get; set; }
string CronExpression { get; set; }
-
+
TimeZoneInfo TimeZone { get; set; }
string Queue { get; set; }
- Task DoWorkAsync();
+ Task DoWorkAsync(CancellationToken cancellationToken = default);
}
-
-
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs
index 060afd3ac6..e1e3a86140 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs
@@ -4,7 +4,6 @@ using System.Threading.Tasks;
using Quartz;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
-using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundWorkers.Quartz;
@@ -34,12 +33,12 @@ public class QuartzBackgroundWorkerManager : IBackgroundWorkerManager, ISingleto
}
}
- public virtual async Task AddAsync(IBackgroundWorker worker)
+ public virtual async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default)
{
- await ReScheduleJobAsync(worker);
+ await ReScheduleJobAsync(worker, cancellationToken);
}
- protected virtual async Task ReScheduleJobAsync(IBackgroundWorker worker)
+ protected virtual async Task ReScheduleJobAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default)
{
if (worker is IQuartzBackgroundWorker quartzWork)
{
@@ -52,7 +51,7 @@ public class QuartzBackgroundWorkerManager : IBackgroundWorkerManager, ISingleto
}
else
{
- await DefaultScheduleJobAsync(quartzWork);
+ await DefaultScheduleJobAsync(quartzWork, cancellationToken);
}
}
else
@@ -65,22 +64,22 @@ public class QuartzBackgroundWorkerManager : IBackgroundWorkerManager, ISingleto
if (workerAdapter?.Trigger != null)
{
- await DefaultScheduleJobAsync(workerAdapter);
+ await DefaultScheduleJobAsync(workerAdapter, cancellationToken);
}
}
}
- protected virtual async Task DefaultScheduleJobAsync(IQuartzBackgroundWorker quartzWork)
+ protected virtual async Task DefaultScheduleJobAsync(IQuartzBackgroundWorker quartzWork, CancellationToken cancellationToken = default)
{
- if (await _scheduler.CheckExists(quartzWork.JobDetail.Key))
+ if (await _scheduler.CheckExists(quartzWork.JobDetail.Key, cancellationToken))
{
- await _scheduler.AddJob(quartzWork.JobDetail, true, true);
- await _scheduler.ResumeJob(quartzWork.JobDetail.Key);
- await _scheduler.RescheduleJob(quartzWork.Trigger.Key, quartzWork.Trigger);
+ await _scheduler.AddJob(quartzWork.JobDetail, true, true, cancellationToken);
+ await _scheduler.ResumeJob(quartzWork.JobDetail.Key, cancellationToken);
+ await _scheduler.RescheduleJob(quartzWork.Trigger.Key, quartzWork.Trigger, cancellationToken);
}
else
{
- await _scheduler.ScheduleJob(quartzWork.JobDetail, quartzWork.Trigger);
+ await _scheduler.ScheduleJob(quartzWork.JobDetail, quartzWork.Trigger, cancellationToken);
}
}
}
diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
index e0477f7106..fb94408bfe 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
@@ -67,10 +67,10 @@ public class QuartzPeriodicBackgroundWorkerAdapter : QuartzBackgroundWo
.Build();
}
- public override async Task Execute(IJobExecutionContext context)
+ public async override Task Execute(IJobExecutionContext context)
{
var worker = (IBackgroundWorker) ServiceProvider.GetService(typeof(TWorker));
- var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider);
+ var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider, context.CancellationToken);
switch (worker)
{
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs
index 24d4d71096..37911feae5 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs
@@ -12,6 +12,7 @@ public abstract class AsyncPeriodicBackgroundWorkerBase : BackgroundWorkerBase
{
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected AbpAsyncTimer Timer { get; }
+ protected CancellationToken StartCancellationToken { get; set; }
protected AsyncPeriodicBackgroundWorkerBase(
AbpAsyncTimer timer,
@@ -22,13 +23,15 @@ public abstract class AsyncPeriodicBackgroundWorkerBase : BackgroundWorkerBase
Timer.Elapsed = Timer_Elapsed;
}
- public override async Task StartAsync(CancellationToken cancellationToken = default)
+ public async override Task StartAsync(CancellationToken cancellationToken = default)
{
+ StartCancellationToken = cancellationToken;
+
await base.StartAsync(cancellationToken);
Timer.Start(cancellationToken);
}
- public override async Task StopAsync(CancellationToken cancellationToken = default)
+ public async override Task StopAsync(CancellationToken cancellationToken = default)
{
Timer.Stop(cancellationToken);
await base.StopAsync(cancellationToken);
@@ -36,16 +39,16 @@ public abstract class AsyncPeriodicBackgroundWorkerBase : BackgroundWorkerBase
private async Task Timer_Elapsed(AbpAsyncTimer timer)
{
- await DoWorkAsync();
+ await DoWorkAsync(StartCancellationToken);
}
- private async Task DoWorkAsync()
+ private async Task DoWorkAsync(CancellationToken cancellationToken = default)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
try
{
- await DoWorkAsync(new PeriodicBackgroundWorkerContext(scope.ServiceProvider));
+ await DoWorkAsync(new PeriodicBackgroundWorkerContext(scope.ServiceProvider, cancellationToken));
}
catch (Exception ex)
{
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs
index 3276c837c0..d017d442e6 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkerManager.cs
@@ -26,13 +26,13 @@ public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDepen
_backgroundWorkers = new List();
}
- public virtual async Task AddAsync(IBackgroundWorker worker)
+ public virtual async Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default)
{
_backgroundWorkers.Add(worker);
if (IsRunning)
{
- await worker.StartAsync();
+ await worker.StartAsync(cancellationToken);
}
}
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkersApplicationInitializationContextExtensions.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkersApplicationInitializationContextExtensions.cs
index 9df0f6c5e4..652aa35741 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkersApplicationInitializationContextExtensions.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkersApplicationInitializationContextExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
@@ -7,17 +8,17 @@ namespace Volo.Abp.BackgroundWorkers;
public static class BackgroundWorkersApplicationInitializationContextExtensions
{
- public async static Task AddBackgroundWorkerAsync([NotNull] this ApplicationInitializationContext context)
+ public async static Task AddBackgroundWorkerAsync([NotNull] this ApplicationInitializationContext context, CancellationToken cancellationToken = default)
where TWorker : IBackgroundWorker
{
Check.NotNull(context, nameof(context));
- await context.AddBackgroundWorkerAsync(typeof(TWorker));
+ await context.AddBackgroundWorkerAsync(typeof(TWorker), cancellationToken: cancellationToken);
return context;
}
- public async static Task AddBackgroundWorkerAsync([NotNull] this ApplicationInitializationContext context, [NotNull] Type workerType)
+ public async static Task AddBackgroundWorkerAsync([NotNull] this ApplicationInitializationContext context, [NotNull] Type workerType, CancellationToken cancellationToken = default)
{
Check.NotNull(context, nameof(context));
Check.NotNull(workerType, nameof(workerType));
@@ -29,9 +30,7 @@ public static class BackgroundWorkersApplicationInitializationContextExtensions
await context.ServiceProvider
.GetRequiredService()
- .AddAsync(
- (IBackgroundWorker)context.ServiceProvider.GetRequiredService(workerType)
- );
+ .AddAsync((IBackgroundWorker)context.ServiceProvider.GetRequiredService(workerType), cancellationToken);
return context;
}
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IBackgroundWorkerManager.cs
index 7f5268afff..499524f7ca 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IBackgroundWorkerManager.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/IBackgroundWorkerManager.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Threading;
+using System.Threading.Tasks;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundWorkers;
@@ -14,5 +15,6 @@ public interface IBackgroundWorkerManager : IRunnable
///
/// The worker. It should be resolved from IOC.
///
- Task AddAsync(IBackgroundWorker worker);
+ ///
+ Task AddAsync(IBackgroundWorker worker, CancellationToken cancellationToken = default);
}
diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs
index 2a192ef155..0aef36fe4e 100644
--- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs
+++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerContext.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
namespace Volo.Abp.BackgroundWorkers;
@@ -6,8 +7,17 @@ public class PeriodicBackgroundWorkerContext
{
public IServiceProvider ServiceProvider { get; }
+ public CancellationToken CancellationToken { get; }
+
public PeriodicBackgroundWorkerContext(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
+ CancellationToken = default;
+ }
+
+ public PeriodicBackgroundWorkerContext(IServiceProvider serviceProvider, CancellationToken cancellationToken)
+ {
+ ServiceProvider = serviceProvider;
+ CancellationToken = cancellationToken;
}
}
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
index 3e4649b6e3..4fda075521 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
@@ -64,6 +64,7 @@ public class AbpCliCoreModule : AbpModule
options.Commands[CreateMigrationAndRunMigratorCommand.Name] = typeof(CreateMigrationAndRunMigratorCommand);
options.Commands[InstallLibsCommand.Name] = typeof(InstallLibsCommand);
options.Commands[CleanCommand.Name] = typeof(CleanCommand);
+ options.Commands[CliCommand.Name] = typeof(CliCommand);
});
Configure(options =>
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CliCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CliCommand.cs
new file mode 100644
index 0000000000..7a6926ecdd
--- /dev/null
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CliCommand.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Volo.Abp.Cli.Args;
+using Volo.Abp.Cli.Commands.Services;
+using Volo.Abp.Cli.NuGet;
+using Volo.Abp.Cli.Utils;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.Cli.Commands;
+
+public class CliCommand : IConsoleCommand, ITransientDependency
+{
+ public const string Name = "cli";
+
+ private const string CliPackageName = "Volo.Abp.Cli";
+
+ private readonly ICmdHelper _cmdHelper;
+ private readonly NuGetService _nuGetService;
+ private readonly AbpNuGetIndexUrlService _nuGetIndexUrlService;
+ public ILogger Logger { get; set; }
+
+ public CliCommand(ICmdHelper cmdHelper, NuGetService nuGetService, AbpNuGetIndexUrlService nuGetIndexUrlService)
+ {
+ _cmdHelper = cmdHelper;
+ _nuGetService = nuGetService;
+ _nuGetIndexUrlService = nuGetIndexUrlService;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
+ {
+ var operationType = NamespaceHelper.NormalizeNamespace(commandLineArgs.Target);
+
+ var preview = commandLineArgs.Options.ContainsKey(Options.Preview.Short) ||
+ commandLineArgs.Options.ContainsKey(Options.Preview.Long);
+
+ var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
+
+ switch (operationType)
+ {
+ case "":
+ case null:
+ _cmdHelper.RunCmd("abp");
+ break;
+
+ case "update":
+ await UpdateCliAsync(version, preview);
+ break;
+
+ case "remove":
+ RemoveCli();
+ break;
+ }
+ }
+
+ private async Task UpdateCliAsync(string version = null, bool preview = false)
+ {
+ var infoText = "Updating ABP CLI ";
+ if (version != null)
+ {
+ infoText += "to the " + version + "... ";
+ }
+ else if (preview)
+ {
+ infoText += "to the latest preview version...";
+ }
+ else
+ {
+ infoText += "...";
+ }
+
+ Logger.LogInformation(infoText);
+
+ try
+ {
+ var versionOption = string.Empty;
+
+ if (preview)
+ {
+ var latestPreviewVersion = await GetLatestPreviewVersion();
+ if (latestPreviewVersion != null)
+ {
+ versionOption = $" --version {latestPreviewVersion}";
+ Logger.LogInformation("Latest preview version is " + latestPreviewVersion);
+ }
+ }
+ else if (version != null)
+ {
+ versionOption = $" --version {version}";
+ }
+
+ _cmdHelper.RunCmdAndExit($"dotnet tool update {CliPackageName}{versionOption} -g", delaySeconds: 2);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("Couldn't update ABP CLI." + ex.Message);
+ ShowCliManualUpdateCommand();
+ }
+ }
+
+ private async Task GetLatestPreviewVersion()
+ {
+ var latestPreviewVersion = await _nuGetService
+ .GetLatestVersionOrNullAsync(
+ packageId: CliPackageName,
+ includeReleaseCandidates: true
+ );
+
+ return latestPreviewVersion.IsPrerelease ? latestPreviewVersion.ToString() : null;
+ }
+
+ private void ShowCliManualUpdateCommand()
+ {
+ Logger.LogError("You can also run the following command to update ABP CLI.");
+ Logger.LogError("dotnet tool update -g Volo.Abp.Cli");
+ }
+
+ private void RemoveCli()
+ {
+ Logger.LogInformation("Removing CLI...");
+ _cmdHelper.RunCmdAndExit("dotnet tool uninstall " + CliPackageName + " -g", delaySeconds: 2);
+ }
+
+ public string GetUsageInfo()
+ {
+ var sb = new StringBuilder();
+
+ sb.AppendLine("");
+ sb.AppendLine("Usage:");
+ sb.AppendLine("");
+ sb.AppendLine(" abp cli [options]");
+ sb.AppendLine("");
+ sb.AppendLine("Options:");
+ sb.AppendLine("");
+ sb.AppendLine("update (update ABP CLI to the latest)");
+ sb.AppendLine("remove (uninstall ABP CLI)");
+ sb.AppendLine("");
+ sb.AppendLine("Examples:");
+ sb.AppendLine("");
+ sb.AppendLine(" abp cli update");
+ sb.AppendLine(" abp cli update --preview");
+ sb.AppendLine(" abp cli update --version 4.2.2");
+ sb.AppendLine(" abp cli remove");
+ sb.AppendLine("");
+
+ return sb.ToString();
+ }
+
+ public string GetShortDescription()
+ {
+ return "Update or remove ABP CLI. See https://docs.abp.io/en/abp/latest/CLI";
+ }
+
+ public static class Options
+ {
+ public static class Preview
+ {
+ public const string Long = "preview";
+ public const string Short = "p";
+ }
+
+ public static class Version
+ {
+ public const string Long = "version";
+ public const string Short = "v";
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
index 741390dc73..c6325a4681 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
@@ -1,4 +1,5 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using Volo.Abp.DependencyInjection;
@@ -125,15 +126,31 @@ public class CmdHelper : ICmdHelper, ITransientDependency
return output.Trim();
}
- public string GetArguments(string command)
+ public void RunCmdAndExit(string command, string workingDirectory = null, int? delaySeconds = null)
+ {
+ var procStartInfo = new ProcessStartInfo(
+ GetFileName(),
+ GetArguments(command, delaySeconds)
+ );
+
+ if (!string.IsNullOrEmpty(workingDirectory))
+ {
+ procStartInfo.WorkingDirectory = workingDirectory;
+ }
+
+ Process.Start(procStartInfo);
+ Environment.Exit(0);
+ }
+
+ public string GetArguments(string command, int? delaySeconds = null)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
- return "-c \"" + command + "\"";
+ return delaySeconds == null ? "-c \"" + command + "\"" : "-c \"" + $"sleep {delaySeconds}s > /dev/null && " + command + "\"";
}
//Windows default.
- return "/C \"" + command + "\"";
+ return delaySeconds == null ? "/C \"" + command + "\"" : "/C \"" + $"timeout /nobreak /t {delaySeconds} >null && " + command + "\"";
}
public string GetFileName()
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs
index 648215d24f..f96697b1cc 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs
@@ -8,20 +8,22 @@ public interface ICmdHelper
void Run(string file, string arguments);
- string GetArguments(string command);
+ string GetArguments(string command, int? delaySeconds = null);
string GetFileName();
void RunCmd(string command, string workingDirectory = null);
Process RunCmdAndGetProcess(string command, string workingDirectory = null);
-
+
void RunCmd(string command, out int exitCode, string workingDirectory = null);
string RunCmdAndGetOutput(string command, string workingDirectory = null);
-
string RunCmdAndGetOutput(string command, out bool isExitCodeSuccessful, string workingDirectory = null);
string RunCmdAndGetOutput(string command, out int exitCode, string workingDirectory = null);
+
+ void RunCmdAndExit(string command, string workingDirectory = null, int? delaySeconds = null);
+
}
diff --git a/framework/src/Volo.Abp.Core/System/Linq/AbpQueryableExtensions.cs b/framework/src/Volo.Abp.Core/System/Linq/AbpQueryableExtensions.cs
index ea6ddddd13..4297f5c697 100644
--- a/framework/src/Volo.Abp.Core/System/Linq/AbpQueryableExtensions.cs
+++ b/framework/src/Volo.Abp.Core/System/Linq/AbpQueryableExtensions.cs
@@ -95,4 +95,21 @@ public static class AbpQueryableExtensions
? (TQueryable)query.Where(predicate)
: query;
}
+
+ ///
+ /// Order a by given predicate if given condition is true.
+ ///
+ /// Queryable to apply filtering
+ /// A boolean value
+ /// Order the query
+ /// Order or not order query based on
+ public static TQueryable OrderByIf([NotNull] this TQueryable query, bool condition, string sorting)
+ where TQueryable : IQueryable
+ {
+ Check.NotNull(query, nameof(query));
+
+ return condition
+ ? (TQueryable)Dynamic.Core.DynamicQueryableExtensions.OrderBy(query, sorting)
+ : query;
+ }
}
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProvider.cs
index b7df112377..870e1f8faf 100644
--- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProvider.cs
+++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProvider.cs
@@ -4,27 +4,13 @@ using System.Collections.Generic;
namespace Volo.Abp.DependencyInjection;
[ExposeServices(typeof(ICachedServiceProvider))]
-public class CachedServiceProvider : ICachedServiceProvider, IScopedDependency
+public class CachedServiceProvider :
+ CachedServiceProviderBase,
+ ICachedServiceProvider,
+ IScopedDependency
{
- protected IServiceProvider ServiceProvider { get; }
-
- protected IDictionary CachedServices { get; }
-
public CachedServiceProvider(IServiceProvider serviceProvider)
+ : base(serviceProvider)
{
- ServiceProvider = serviceProvider;
-
- CachedServices = new Dictionary
- {
- {typeof(IServiceProvider), serviceProvider}
- };
- }
-
- public object GetService(Type serviceType)
- {
- return CachedServices.GetOrAdd(
- serviceType,
- () => ServiceProvider.GetService(serviceType)
- );
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs
new file mode 100644
index 0000000000..14c42b7b7f
--- /dev/null
+++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Concurrent;
+
+namespace Volo.Abp.DependencyInjection;
+
+public abstract class CachedServiceProviderBase
+{
+ private readonly IServiceProvider _serviceProvider;
+ private readonly ConcurrentDictionary> _cachedServices;
+
+ protected CachedServiceProviderBase(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ _cachedServices = new ConcurrentDictionary>();
+ _cachedServices.TryAdd(typeof(IServiceProvider), new Lazy