Merge branch 'dev' into maliming/IdentityClientConfiguration

pull/9675/head
maliming 4 years ago committed by GitHub
commit c6dfe8911b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,6 +12,7 @@ The following features are currently available:
* Provides a [**comment**](Comments.md) system to add comments feature to any kind of resource, like blog post or a product review page.
* Provides a [**reaction**](Reactions.md) system to add reactions (smileys) feature to any kind of resource, like a blog post or a comment.
* Provides a [**rating**](Ratings.md) system to add rating feature to any kind of resource.
* Provides a [**menu**](Menus.md) system to manage public menus dynamically.
Click to a feature to understand and learn how to use it.

@ -0,0 +1,88 @@
# CMS Kit: Pages
CMS Kit Menu system allows to manage public menus dynamically.
## The User Interface
### Menu items
CMS Kit module admin side adds the following items to the main menu, under the *CMS* menu item:
* **Menus**: Menu management page.
`CmsKitAdminMenus` class has the constants for the menu item names.
### Menus
#### Menu Management
Menus page is used to manage dynamic public menus in the system.
![cms-kit-menus-page](../../images/cmskit-module-menus-page.png)
Created menus will be visible on public site.
![cms-kit-public-menus](../../images//cmskit-module-menus-public.png)
# Internals
## Domain Layer
#### Aggregates
This module follows the [Entity Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Entities) guide.
##### Menus
- `MenuItem` (aggregate root): A Menu Item presents a single node at menu tree.
#### Repositories
This module follows the [Repository Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories) guide.
Following custom repositories are defined for this feature:
- `IMenuItemRepository`
#### Domain services
This module follows the [Domain Services Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services) guide.
##### Menu Item Manager
`MenuItemManager` is used to perform some operations for the `MenuItemManager` aggregate root.
### Application layer
#### Application services
- `MenuItemAdminAppService` (implements `IMenuItemAdminAppService`): Implements the management operations of menu system.
- `MenuItemPublicAppService` (implements `IMenuItemPublicAppService`): Implements the public use cases of menu system.
### Database providers
#### Common
##### Table / collection prefix & schema
All tables/collections use the `Cms` prefix by default. Set static properties on the `CmsKitDbProperties` class if you need to change the table prefix or set a schema name (if supported by your database provider).
##### Connection string
This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string.
See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details.
#### Entity Framework Core
##### Tables
- CmsMenuItems
#### MongoDB
##### Collections
- CmsMenuItems

@ -0,0 +1,107 @@
# Angular UI: Basic Theme
The Basic Theme is a theme implementation for the Angular UI. It is a minimalist theme that doesn't add any styling on top of the plain [Bootstrap](https://getbootstrap.com/). You can take the Basic Theme as the **base theme** and build your own theme or styling on top of it. See the *Customization* section.
> If you are looking for a professional, enterprise ready theme, you can check the [Lepton Theme](https://commercial.abp.io/themes), which is a part of the [ABP Commercial](https://commercial.abp.io/).
> See the [Theming document](Theming.md) to learn about themes.
## Installation
**This theme is already installed** when you create a new solution using the [startup templates](../../Startup-Templates/Index.md). If you need to manually install it, follow the steps below:
* Install the [@abp/ng.theme.basic](https://www.npmjs.com/package/@abp/ng.theme.basic) NPM package to your Angular project.
* Open the `src/app/app.module.ts` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule.forRoot()` to the `imports` array.
* Open the `src/app/shared/shared.module` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` and `exports` array.
The `ThemeBasicModule` is registered own layouts (`ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`) to a service which is exposed by `@abp/ng.core` package on application initialization.
## Application Layout
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
Application Layout implements the following parts, in addition to the common parts mentioned above;
* Logo area
* Routes area
* Language selection & user menu
* [Page Alerts](Page-Alerts.md)
See Application Layout components:
![application layout components](./images/layout-components.png)
### How to Use a Layout
Routes should be added to the menu by calling `add` method `RoutesService`. A layout can be set in the object of your route. See the [modifying the menu](Modifying-the-Menu#how-to-add-a-navigation-element) for more information.
## Customization
You have two options two customize this theme:
### Overriding Styles / Components
In this approach, you continue to use the theme as an NPM package and customize the parts you need to. There are several ways to customize it;
#### Override the Styles
You can simply override the styles in the global styles (`src/styles.scss`) file of your application.
#### Override the Components
See the [Component Replacement](Component-Replacement.md) to learn how you can replace components, customize and extend the user interface.
### Copy & Customize
You can run the following [ABP CLI](../../CLI.md) command in **Angular** project directory to copy the source code to your solution:
`abp add-package @abp/ng.theme.basic --with-source-code`
----
Or, you can download the [source code](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/theme-basic) of the Basic Theme, manually copy the project content into your project (`projects/theme-basic` folder), open `angular.json` file and add configuration below to the `projects` object:
```json
{
"projects": {
...
"theme-basic": {
"projectType": "library",
"root": "projects/theme-basic",
"sourceRoot": "projects/theme-basic/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/theme-basic/tsconfig.lib.json",
"project": "projects/theme-basic/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/theme-basic/tsconfig.lib.prod.json"
}
}
}
}
}
}
}
```
Then, open the `tsconfig.json` file and add new paths as follows:
```json
"paths": {
...
"@abp/ng.theme.basic": ["projects/theme-basic/src/public-api.ts"],
"@abp/ng.theme.basic/testing": ["projects/theme-basic/testing/src/public-api.ts"]
}
```
You can now freely customize the theme based on your application requirements.
## See Also
* [Theming](Theming.md)

@ -0,0 +1,228 @@
# Angular UI: Theming
## Introduction
ABP Framework provides a complete **UI Theming** system with the following goals:
* Reusable [application modules](../../Modules/Index.md) are developed **theme-independent**, so they can work with any UI theme.
* UI theme is **decided by the final application**.
* The theme is distributed via an NPM package, so it is **easily upgradable**.
* The final application can **customize** the selected theme.
In order to accomplish these goals, ABP Framework;
* Determines a set of **base libraries** used and adapted by all the themes. So, module and application developers can depend on and use these libraries without depending on a particular theme.
* Provides a system that consists of layout parts (like navigation menus and toolbars) that is implemented by all the themes. So, the modules and the application contribute to the layout to compose a consistent application UI.
### Current Themes
Currently, two themes are **officially provided**:
* The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**.
* The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license.
## Overall
### The Base Libraries
All the themes must depend on the [@abp/ng.theme.shared](https://www.npmjs.com/package/@abp/ng.theme.shared) NuGet package, so they are indirectly depending on the following libraries:
* [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework.
* [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library.
* [NG Bootstrap](https://ng-bootstrap.github.io/#/home) as a component library that supports the Bootstrap and adds extra components like modal and datepicker.
* [Ngx-Datatable](https://swimlane.gitbook.io/ngx-datatable/) as a datatable library.
* [ngx-validate](https://github.com/ng-turkey/ngx-validate) a dynamic validation of reactive forms library.
* [Chart.js](https://www.chartjs.org/) as a widget library.
These libraries are selected as the base libraries and available to the applications and modules.
> Bootstrap's JavaScript part is not used since the NG Bootstrap library already provides the necessary functionalities to the Bootstrap components in a native way.
### The Layout
All themes must define a layout for the application. The following image shows the user management page in the [Basic Theme](Basic-Theme.md) application layout:
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
And the same page is shown below with the [Lepton Theme](https://commercial.abp.io/themes) application layout:
![lepton-theme-application-layout](../../images/lepton-theme-application-layout.png)
As you can see, the page is the same, but the look is completely different in the themes above.
The application layout typically includes the following parts;
* Main menu
* Nav items area with the following components;
* User menu
* Language switch dropdown
* [Page alerts](Page-Alerts.md)
* The page content (aka `<router-outlet>`)
## Implementing a Theme
A theme is simply an NPM package and comes with startup templates.
### The Easy Way
The easiest way to create a new theme is to add Basic Theme Source Code to your project via [ABP CLI](../../CLI.md) command and customize it.
You can run the following command in **Angular** project directory to copy the source code to your solution:
`abp add-package @abp/ng.theme.basic --with-source-code`
### Global/Component Styles
Angular can bundle global style files and component styles with components.
See the [component styles](https://angular.io/guide/component-styles) guide on Angular documentation for more information.
### Layout Parts
A typical layout consists of several parts. The theme should include the necessary parts in each layout.
**Example: The Basic Theme has the following parts for the Application Layout**
![basic-theme-application-layout-parts](images/basic-theme-application-layout-parts.png)
The application code and the modules can only show contents in the Page Content part. If they need to change the other parts (to add a menu item, to add a nav item, to change the application name in the logo area...) they should use the ABP Framework APIs.
The following sections explain the fundamental parts pre-defined by the ABP Framework and can be implemented by the themes.
> It is a good practice to split the layout into components/partials, so the final application can override them partially for customization purpose.
#### Logo
The `application` object of an environment file should be configured to get the name and the logo URL of the application to render in the logo part. Additionally, `LogoComponent` can be replaced. See [Component Replacement](Component-Replacement.md) document for more.
The [Application Startup Template](../../Startup-Templates/Application.md) has an implementation of this interface to set the values by the application developer.
#### Main Menu / Routes
`RoutesService` service is used to manage the main menu items and render them on the layout.
**Example: Adding a route to the main menu**
```ts
import { RoutesService, eLayoutType } from '@abp/ng.core';
import { Component } from '@angular/core';
@Component(/* component metadata */)
export class AppComponent {
constructor(routes: RoutesService) {
routes.add([
{
path: '/your-path',
name: 'Your navigation',
order: 101,
iconClass: 'fas fa-question-circle',
requiredPolicy: 'permission key here',
layout: eLayoutType.application,
},
{
path: '/your-path/child',
name: 'Your child navigation',
parentName: 'Your navigation',
order: 1,
requiredPolicy: 'permission key here',
},
]);
}
}
```
See the [Modifying the Menu](Modifying-the-Menu.md) document to learn more about the navigation system.
#### Toolbar / Nav Items
`NavItemsService` service is used to get the menu's right part items and render on the layout. You can add an HTML content or Angular component as an element to render.
**Example: Adding an element to right part of the menu**
````ts
import { NavItemsService } from '@abp/ng.theme.shared';
import { Component } from '@angular/core';
@Component({
template: `
<input type="search" placeholder="Search" class="bg-transparent border-0 color-white" />
`,
})
export class MySearchInputComponent {}
@Component(/* component metadata */)
export class AppComponent {
constructor(private navItems: NavItemsService) {
navItems.addItems([
{
id: 'MySearchInput',
order: 1,
component: MySearchInputComponent,
},
{
id: 'SignOutIcon',
html: '<i class="fas fa-sign-out-alt fa-lg text-white m-2"><i>',
action: () => console.log('Clicked the sign out icon'),
order: 101, // puts as last element
},
]);
}
}
````
> See the [How to Add an Element to Right Part of the Menu](Modifying-the-Menu#how-to-add-an-element-to-right-part-of-the-menu) document to learn more on the nav items system.
The theme has a responsibility to add two pre-defined items to the toolbar: Language Selection and User Menu.
##### Language Selection
Language Selection toolbar item is generally a dropdown that is used to switch between languages. `ConfigStateService` is used to get the list of available languages and `SessionStateService` is used to learn the current language.
`SessionStateService` is used to get and set the current language.
**Example: Get the currently selected language**
````ts
import {SessionStateService} from '@abp/ng.core';
//...
constructor(private sessionState: SessionStateService) {
const lang = this.sessionState.getLanguage()
}
````
**Example: Set the selected language**
````ts
import {SessionStateService} from '@abp/ng.core';
//...
constructor(private sessionState: SessionStateService) {
const lang = this.sessionState.setLanguage('en')
}
````
##### User Menu
User menu is a component that can be replaceable. See an example to learn how can you replace it:
````ts
import { eThemeBasicComponents } from '@abp/ng.theme.basic';
import { NavItemsService } from '@abp/ng.theme.shared';
import { Component } from '@angular/core';
@Component({/* component metadata */})
export class AppComponent {
constructor(private navItems: NavItemsService) {
this.navItems.patchItem(eThemeBasicComponents.CurrentUser, { component: MyUserMenuComponent });
}
}
````
[`ConfigStateService`](Config-State-Service.md) service can be used to obtain the `application-configuration` API response (e.g. getting current user or tenant).
#### Page Alerts
`PageAlertService` service is used to get the current page alerts to render on the layout. See the [Page Alerts](Page-Alerts.md) document to learn more.

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@ -38,7 +38,7 @@ You have two options two customize this theme:
### Overriding Styles / Components
In this approach, you continue to use the the theme as NuGet and NPM packages and customize the parts you need to. There are several ways to customize it;
In this approach, you continue to use the theme as NuGet and NPM packages and customize the parts you need to. There are several ways to customize it;
#### Override the Styles

@ -365,8 +365,8 @@
"path": "Object-To-Object-Mapping.md"
},
{
"text":"String Encryption",
"path":"String-Encryption.md"
"text": "String Encryption",
"path": "String-Encryption.md"
},
{
"text": "Text Templating",
@ -1025,6 +1025,19 @@
"text": "Customization Guide",
"path": "UI/Angular/Customization-User-Interface.md"
},
{
"text": "Theming",
"items": [
{
"text": "Overall",
"path": "UI/Angular/Theming.md"
},
{
"text": "The Basic Theme",
"path": "UI/Angular/Basic-Theme.md"
}
]
},
{
"text": "Modifying the Menu",
"path": "UI/Angular/Modifying-the-Menu.md"

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -385,6 +385,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MongoDB.Tests.Seco
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.IdentityModel.Tests", "test\Volo.Abp.IdentityModel.Tests\Volo.Abp.IdentityModel.Tests.csproj", "{40C6740E-BFCA-4D37-8344-3D84E2044BB2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Threading.Tests", "test\Volo.Abp.Threading.Tests\Volo.Abp.Threading.Tests.csproj", "{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1147,6 +1149,10 @@ Global
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Release|Any CPU.Build.0 = Release|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1341,6 +1347,7 @@ Global
{75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{90B1866A-EF99-40B9-970E-B898E5AA523F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{40C6740E-BFCA-4D37-8344-3D84E2044BB2} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

@ -64,6 +64,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
context,
requestCulture
);
context.Items[AbpRequestLocalizationMiddleware.HttpContextItemName] = true;
}
await next(context);

@ -33,6 +33,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization
new RequestCulture(culture, uiCulture)
);
HttpContext.Items[AbpRequestLocalizationMiddleware.HttpContextItemName] = true;
var context = new QueryStringCultureReplacementContext(HttpContext, new RequestCulture(culture, uiCulture), returnUrl);
await QueryStringCultureReplacement.ReplaceAsync(context);

@ -10,6 +10,8 @@ namespace Microsoft.AspNetCore.RequestLocalization
{
public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependency
{
public const string HttpContextItemName = "__AbpSetCultureCookie";
private readonly IAbpRequestLocalizationOptionsProvider _requestLocalizationOptionsProvider;
private readonly ILoggerFactory _loggerFactory;
@ -29,6 +31,23 @@ namespace Microsoft.AspNetCore.RequestLocalization
_loggerFactory
);
context.Response.OnStarting(() =>
{
if (context.Items[HttpContextItemName] == null)
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
if (requestCultureFeature?.Provider is QueryStringRequestCultureProvider)
{
AbpRequestCultureCookieHelper.SetCultureCookie(
context,
requestCultureFeature.RequestCulture
);
}
}
return Task.CompletedTask;
});
await middleware.Invoke(context);
}
}

@ -6,13 +6,26 @@ using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Threading
{
[Dependency(ReplaceServices = true)]
public class HttpContextCancellationTokenProvider : ICancellationTokenProvider, ITransientDependency
public class HttpContextCancellationTokenProvider : CancellationTokenProviderBase, ITransientDependency
{
public CancellationToken Token => _httpContextAccessor.HttpContext?.RequestAborted ?? CancellationToken.None;
private readonly IHttpContextAccessor _httpContextAccessor;
public HttpContextCancellationTokenProvider(IHttpContextAccessor httpContextAccessor)
public override CancellationToken Token
{
get
{
if (OverrideValue != null)
{
return OverrideValue.CancellationToken;
}
return _httpContextAccessor.HttpContext?.RequestAborted ?? CancellationToken.None;
}
}
public HttpContextCancellationTokenProvider(
IAmbientScopeProvider<CancellationTokenOverride> cancellationTokenOverrideScopeProvider,
IHttpContextAccessor httpContextAccessor)
: base(cancellationTokenOverrideScopeProvider)
{
_httpContextAccessor = httpContextAccessor;
}

@ -14,10 +14,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Blazorise" Version="0.9.3.6" />
<PackageReference Include="Blazorise.DataGrid" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Snackbar" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Components" Version="0.9.3.6" />
<PackageReference Include="Blazorise" Version="0.9.4.1" />
<PackageReference Include="Blazorise.DataGrid" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Snackbar" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Components" Version="0.9.4.1" />
</ItemGroup>
</Project>

@ -0,0 +1,14 @@
using System.Threading;
namespace Volo.Abp.Threading
{
public class CancellationTokenOverride
{
public CancellationToken CancellationToken { get; }
public CancellationTokenOverride(CancellationToken cancellationToken)
{
CancellationToken = cancellationToken;
}
}
}

@ -0,0 +1,26 @@
using System;
using System.Threading;
namespace Volo.Abp.Threading
{
public abstract class CancellationTokenProviderBase : ICancellationTokenProvider
{
public const string CancellationTokenOverrideContextKey = "Volo.Abp.Threading.CancellationToken.Override";
public abstract CancellationToken Token { get; }
protected IAmbientScopeProvider<CancellationTokenOverride> CancellationTokenOverrideScopeProvider { get; }
protected CancellationTokenOverride OverrideValue => CancellationTokenOverrideScopeProvider.GetValue(CancellationTokenOverrideContextKey);
protected CancellationTokenProviderBase(IAmbientScopeProvider<CancellationTokenOverride> cancellationTokenOverrideScopeProvider)
{
CancellationTokenOverrideScopeProvider = cancellationTokenOverrideScopeProvider;
}
public IDisposable Use(CancellationToken cancellationToken)
{
return CancellationTokenOverrideScopeProvider.BeginScope(CancellationTokenOverrideContextKey, new CancellationTokenOverride(cancellationToken));
}
}
}

@ -1,9 +1,12 @@
using System.Threading;
using System;
using System.Threading;
namespace Volo.Abp.Threading
{
public interface ICancellationTokenProvider
{
CancellationToken Token { get; }
IDisposable Use(CancellationToken cancellationToken);
}
}

@ -2,15 +2,15 @@
namespace Volo.Abp.Threading
{
public class NullCancellationTokenProvider : ICancellationTokenProvider
public class NullCancellationTokenProvider : CancellationTokenProviderBase
{
public static NullCancellationTokenProvider Instance { get; } = new NullCancellationTokenProvider();
public CancellationToken Token { get; } = CancellationToken.None;
public override CancellationToken Token => OverrideValue?.CancellationToken ?? CancellationToken.None;
private NullCancellationTokenProvider()
: base(new AmbientDataContextAmbientScopeProvider<CancellationTokenOverride>(new AsyncLocalAmbientDataContext()))
{
}
}
}
}

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
</ItemGroup>
</Project>

@ -0,0 +1,15 @@
using Volo.Abp.Modularity;
namespace Volo.Abp.Threading
{
[DependsOn(
typeof(AbpThreadingModule),
typeof(AbpTestBaseModule)
)]
public class AbpThreadingTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}

@ -0,0 +1,63 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Threading
{
public class NullCancellationTokenProvider_Tests : AbpIntegratedTest<AbpThreadingTestModule>
{
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public NullCancellationTokenProvider_Tests()
{
_cancellationTokenProvider = NullCancellationTokenProvider.Instance;
}
[Fact]
public void Should_Return_None_Token()
{
_cancellationTokenProvider.Token.ShouldBe(CancellationToken.None);
}
[Fact]
public void Should_Return_Specific_Token()
{
var cts = new CancellationTokenSource();
using (_cancellationTokenProvider.Use(cts.Token))
{
var newCancellationTokenProvider = NullCancellationTokenProvider.Instance;
newCancellationTokenProvider.Token.ShouldBe(cts.Token);
}
_cancellationTokenProvider.Token.ShouldBe(CancellationToken.None);
}
[Fact]
public void Should_Cancel_After_100_Milliseconds()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMilliseconds(100));
using (_cancellationTokenProvider.Use(cts.Token))
{
var newCancellationTokenProvider = NullCancellationTokenProvider.Instance;
Should.Throw<OperationCanceledException>(() => LongTask(1000, newCancellationTokenProvider.Token));
}
}
private void LongTask(int loopCounter, CancellationToken cancellationToken = default)
{
for (var i = 0; i < loopCounter; i++)
{
cancellationToken.ThrowIfCancellationRequested();
Thread.Sleep(10);
}
}
}
}

@ -14,8 +14,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.4.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="5.0.*" />

@ -14,8 +14,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.4.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
</ItemGroup>

@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.4.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.*" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.*" />
</ItemGroup>

@ -8,8 +8,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.3.6" />
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.4.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.*" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.*" />
</ItemGroup>

@ -13,8 +13,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.3.5" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.3.5" />
<PackageReference Include="Blazorise.Bootstrap" Version="0.9.4.1" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="0.9.4.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.*" />

@ -119,7 +119,7 @@ namespace MyCompanyName.MyProjectName
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch"));
options.Languages.Add(new LanguageInfo("es", "es", "Español"s));
options.Languages.Add(new LanguageInfo("es", "es", "Español"));
});
Configure<AbpAuditingOptions>(options =>

Loading…
Cancel
Save