mirror of https://github.com/abpframework/abp.git
340 changed files with 21047 additions and 2339 deletions
@ -0,0 +1,6 @@ |
|||||
|
# Getting Started with the Startup Templates |
||||
|
|
||||
|
See the following tutorials to learn how to get started with the ABP Framework using the pre-built application startup templates: |
||||
|
|
||||
|
* [Getting Started With the ASP.NET Core MVC / Razor Pages UI](Getting-Started-AspNetCore-MVC-Template.md) |
||||
|
* [Getting Started with the Angular UI](Getting-Started-Angular-Template.md) |
||||
@ -0,0 +1,3 @@ |
|||||
|
# Object Extensions |
||||
|
|
||||
|
TODO |
||||
@ -0,0 +1,56 @@ |
|||||
|
# ContentSecurityStrategy |
||||
|
|
||||
|
`ContentSecurityStrategy` is an abstract class exposed by @abp/ng.core package. It helps you mark inline scripts or styles as safe in terms of [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy). |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## API |
||||
|
|
||||
|
|
||||
|
### constructor(public nonce?: string) |
||||
|
|
||||
|
- `nonce` enables whitelisting inline script or styles in order to avoid using `unsafe-inline` in [script-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#Unsafe_inline_script) and [style-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src#Unsafe_inline_styles) directives. |
||||
|
|
||||
|
|
||||
|
### applyCSP(element: HTMLScriptElement | HTMLStyleElement): void |
||||
|
|
||||
|
This method maps the aforementioned properties to the given `element`. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## LooseContentSecurityPolicy |
||||
|
|
||||
|
`LooseContentSecurityPolicy` is a class that extends `ContentSecurityStrategy`. It requires `nonce` and marks given `<script>` or `<style>` tag with it. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## StrictContentSecurityPolicy |
||||
|
|
||||
|
`StrictContentSecurityPolicy` is a class that extends `ContentSecurityStrategy`. It does not mark inline scripts and styles as safe. You can consider it as a noop alternative. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## Predefined Content Security Strategies |
||||
|
|
||||
|
Predefined content security strategies are accessible via `CONTENT_SECURITY_STRATEGY` constant. |
||||
|
|
||||
|
|
||||
|
### Loose(nonce: string) |
||||
|
|
||||
|
`nonce` will be set. |
||||
|
|
||||
|
|
||||
|
### Strict() |
||||
|
|
||||
|
Nothing will be done. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## What's Next? |
||||
|
|
||||
|
TODO: Place new InsertionStrategy link here. |
||||
@ -0,0 +1,41 @@ |
|||||
|
# CrossOriginStrategy |
||||
|
|
||||
|
`CrossOriginStrategy` is a class exposed by @abp/ng.core package. Its instances define how a source referenced by an element will be retrieved by the browser and are consumed by other classes such as `LoadingStrategy`. |
||||
|
|
||||
|
|
||||
|
## API |
||||
|
|
||||
|
|
||||
|
### constructor(public crossorigin: 'anonymous' | 'use-credentials', public integrity?: string) |
||||
|
|
||||
|
- `crossorigin` is mapped to [the HTML attribute with the same name](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin). |
||||
|
- `integrity` is a hash for validating a remote resource. Its use is explained [here](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). |
||||
|
|
||||
|
|
||||
|
### setCrossOrigin(element: HTMLElement): void |
||||
|
|
||||
|
This method maps the aforementioned properties to the given `element`. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## Predefined Cross-Origin Strategies |
||||
|
|
||||
|
Predefined cross-origin strategies are accessible via `CROSS_ORIGIN_STRATEGY` constant. |
||||
|
|
||||
|
|
||||
|
### Anonymous(integrity?: string) |
||||
|
|
||||
|
`crossorigin` will be set as `"anonymous"` and `integrity` is optional. |
||||
|
|
||||
|
|
||||
|
### UseCredentials(integrity?: string) |
||||
|
|
||||
|
`crossorigin` will be set as `"use-credentials"` and `integrity` is optional. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## What's Next? |
||||
|
|
||||
|
- [LoadingStrategy](./Loading-Strategy.md) |
||||
@ -0,0 +1,58 @@ |
|||||
|
# DomStrategy |
||||
|
|
||||
|
`DomStrategy` is a class exposed by @abp/ng.core package. Its instances define how an element will be attached to the DOM and are consumed by other classes such as `LoadingStrategy`. |
||||
|
|
||||
|
|
||||
|
## API |
||||
|
|
||||
|
|
||||
|
### constructor(public target?: HTMLElement, public position?: InsertPosition) |
||||
|
|
||||
|
- `target` is an HTMLElement (_default: document.head_). |
||||
|
- `position` defines where the created element will be placed. All possible values of `position` can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement) (_default: 'beforeend'_). |
||||
|
|
||||
|
|
||||
|
### insertElement(element: HTMLElement): void |
||||
|
|
||||
|
This method inserts given `element` to `target` based on the `position`. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## Predefined Dom Strategies |
||||
|
|
||||
|
Predefined dom strategies are accessible via `DOM_STRATEGY` constant. |
||||
|
|
||||
|
|
||||
|
### AppendToBody() |
||||
|
|
||||
|
`insertElement` will place the given `element` at the end of `<body>`. |
||||
|
|
||||
|
|
||||
|
### AppendToHead() |
||||
|
|
||||
|
`insertElement` will place the given `element` at the end of `<head>`. |
||||
|
|
||||
|
|
||||
|
### PrependToHead() |
||||
|
|
||||
|
`insertElement` will place the given `element` at the beginning of `<head>`. |
||||
|
|
||||
|
|
||||
|
### AfterElement(target: HTMLElement) |
||||
|
|
||||
|
`insertElement` will place the given `element` after (as a sibling to) the `target`. |
||||
|
|
||||
|
|
||||
|
### BeforeElement(target: HTMLElement) |
||||
|
|
||||
|
`insertElement` will place the given `element` before (as a sibling to) the `target`. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## What's Next? |
||||
|
|
||||
|
- [LoadingStrategy](./Loading-Strategy.md) |
||||
|
|
||||
|
TODO: Place new InsertionStrategy link here. |
||||
@ -0,0 +1,136 @@ |
|||||
|
# How to Lazy Load Scripts and Styles |
||||
|
|
||||
|
You can use the `LazyLoadService` in @abp/ng.core package in order to lazy load scripts and styles in an easy and explicit way. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## Getting Started |
||||
|
|
||||
|
You do not have to provide the `LazyLoadService` at module or component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services. |
||||
|
|
||||
|
```js |
||||
|
import { LazyLoadService } from '@abp/ng.core'; |
||||
|
|
||||
|
@Component({ |
||||
|
/* class metadata here */ |
||||
|
}) |
||||
|
class DemoComponent { |
||||
|
constructor(private lazyLoadService: LazyLoadService) {} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
You can use the `load` method of `LazyLoadService` to create a `<script>` or `<link>` element in the DOM at the desired position and force the browser to download the target resource. |
||||
|
|
||||
|
|
||||
|
|
||||
|
### How to Load Scripts |
||||
|
|
||||
|
The first parameter of `load` method expects a `LoadingStrategy`. If you pass a `ScriptLoadingStrategy` instance, the `LazyLoadService` will create a `<script>` element with given `src` and place it in the designated DOM position. |
||||
|
|
||||
|
```js |
||||
|
import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core'; |
||||
|
|
||||
|
@Component({ |
||||
|
template: ` |
||||
|
<some-component *ngIf="libraryLoaded$ | async"></some-component> |
||||
|
` |
||||
|
}) |
||||
|
class DemoComponent { |
||||
|
libraryLoaded$ = this.lazyLoad.load( |
||||
|
LOADING_STRATEGY.AppendAnonymousScriptToHead('/assets/some-library.js'), |
||||
|
); |
||||
|
|
||||
|
constructor(private lazyLoadService: LazyLoadService) {} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
The `load` method returns an observable to which you can subscibe in your component or with an `async` pipe. In the example above, the `NgIf` directive will render `<some-component>` only **if the script gets successfully loaded or is already loaded before**. |
||||
|
|
||||
|
> You can subscribe multiple times in your template with `async` pipe. The styles will only be loaded once. |
||||
|
|
||||
|
Please refer to [LoadingStrategy](./Loading-Strategy.md) to see all available loading strategies and how you can build your own loading strategy. |
||||
|
|
||||
|
|
||||
|
|
||||
|
### How to Load Styles |
||||
|
|
||||
|
If you pass a `StyleLoadingStrategy` instance as the first parameter of `load` method, the `LazyLoadService` will create a `<link>` element with given `href` and place it in the designated DOM position. |
||||
|
|
||||
|
```js |
||||
|
import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core'; |
||||
|
|
||||
|
@Component({ |
||||
|
template: ` |
||||
|
<some-component *ngIf="stylesLoaded$ | async"></some-component> |
||||
|
` |
||||
|
}) |
||||
|
class DemoComponent { |
||||
|
stylesLoaded$ = this.lazyLoad.load( |
||||
|
LOADING_STRATEGY.AppendAnonymousStyleToHead('/assets/some-styles.css'), |
||||
|
); |
||||
|
|
||||
|
constructor(private lazyLoadService: LazyLoadService) {} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
The `load` method returns an observable to which you can subscibe in your component or with an `AsyncPipe`. In the example above, the `NgIf` directive will render `<some-component>` only **if the style gets successfully loaded or is already loaded before**. |
||||
|
|
||||
|
> You can subscribe multiple times in your template with `async` pipe. The styles will only be loaded once. |
||||
|
|
||||
|
Please refer to [LoadingStrategy](./Loading-Strategy.md) to see all available loading strategies and how you can build your own loading strategy. |
||||
|
|
||||
|
|
||||
|
|
||||
|
### Advanced Usage |
||||
|
|
||||
|
You have quite a bit of freedom to define how your lazy load will be implemented. Here is an example: |
||||
|
|
||||
|
```js |
||||
|
const domStrategy = DOM_STRATEGY.PrependToHead(); |
||||
|
|
||||
|
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.Anonymous( |
||||
|
'sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh', |
||||
|
); |
||||
|
|
||||
|
const loadingStrategy = new StyleLoadingStrategy( |
||||
|
'https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css', |
||||
|
domStrategy, |
||||
|
crossOriginStrategy, |
||||
|
); |
||||
|
|
||||
|
this.lazyLoad.load(loadingStrategy, 1, 2000); |
||||
|
``` |
||||
|
|
||||
|
This code will create a `<link>` element with given url and integrity hash, insert it to to top of the `<head>` element, and retry once after 2 seconds if first try fails. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## API |
||||
|
|
||||
|
|
||||
|
|
||||
|
### loaded: Set<string> |
||||
|
|
||||
|
All previously loaded paths are available via this property. It is a simple [JavaScript Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). |
||||
|
|
||||
|
|
||||
|
|
||||
|
### load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable<Event> |
||||
|
|
||||
|
- `strategy` parameter is the primary focus here and is explained above. |
||||
|
- `retryTimes` defines how many times the loading will be tried again before fail (_default: 2_). |
||||
|
- `retryDelay` defines how much delay there will be between retries (_default: 1000_). |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## What's Next? |
||||
|
|
||||
|
- [TrackByService](./Track-By-Service.md) |
||||
@ -0,0 +1,77 @@ |
|||||
|
# LoadingStrategy |
||||
|
|
||||
|
`LoadingStrategy` is an abstract class exposed by @abp/ng.core package. There are two loading strategies extending it: `ScriptLoadingStrategy` and `StyleLoadingStrategy`. Implementing the same methods and properties, both of these strategies help you define how your lazy loading will work. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## API |
||||
|
|
||||
|
|
||||
|
### constructor(public path: string, protected domStrategy?: DomStrategy, protected crossOriginStrategy?: CrossOriginStrategy) |
||||
|
|
||||
|
- `path` is set to `<script>` elements as `src` and `<link>` elements as `href` attribute. |
||||
|
- `domStrategy` is the `DomStrategy` that will be used when inserting the created element. (_default: AppendToHead_) |
||||
|
- `crossOriginStrategy` is the `CrossOriginStrategy` that will be used on the created element before inserting it. (_default: Anonymous_) |
||||
|
|
||||
|
Please refer to [DomStrategy](./Dom-Strategy.md) and [CrossOriginStrategy](./Cross-Origin-Strategy.md) documentation for their usage. |
||||
|
|
||||
|
|
||||
|
### createElement(): HTMLScriptElement | HTMLLinkElement |
||||
|
|
||||
|
This method creates and returns a `<script>` or `<link>` element with `path` set as `src` or `href`. |
||||
|
|
||||
|
|
||||
|
### createStream(): Observable<Event> |
||||
|
|
||||
|
This method creates and returns an observable stream that emits on success and throws on error. |
||||
|
|
||||
|
|
||||
|
|
||||
|
## ScriptLoadingStrategy |
||||
|
|
||||
|
`ScriptLoadingStrategy` is a class that extends `LoadingStrategy`. It lets you **lazy load a script**. |
||||
|
|
||||
|
|
||||
|
|
||||
|
## StyleLoadingStrategy |
||||
|
|
||||
|
`StyleLoadingStrategy` is a class that extends `LoadingStrategy`. It lets you **lazy load a style**. |
||||
|
|
||||
|
|
||||
|
|
||||
|
## Predefined Loading Strategies |
||||
|
|
||||
|
Predefined content security strategies are accessible via `LOADING_STRATEGY` constant. |
||||
|
|
||||
|
|
||||
|
### AppendAnonymousScriptToHead(src: string, integrity?: string) |
||||
|
|
||||
|
Sets given paremeters and `crossorigin="anonymous"` as attributes of created `<script>` element and places it at the **end** of `<head>` tag in the document. |
||||
|
|
||||
|
|
||||
|
### PrependAnonymousScriptToHead(src: string, integrity?: string) |
||||
|
|
||||
|
Sets given paremeters and `crossorigin="anonymous"` as attributes of created `<script>` element and places it at the **beginning** of `<head>` tag in the document. |
||||
|
|
||||
|
|
||||
|
### AppendAnonymousScriptToBody(src: string, integrity?: string) |
||||
|
|
||||
|
Sets given paremeters and `crossorigin="anonymous"` as attributes of created `<script>` element and places it at the **end** of `<body>` tag in the document. |
||||
|
|
||||
|
|
||||
|
### AppendAnonymousStyleToHead(href: string, integrity?: string) |
||||
|
|
||||
|
Sets given paremeters and `crossorigin="anonymous"` as attributes of created `<style>` element and places it at the **end** of `<head>` tag in the document. |
||||
|
|
||||
|
|
||||
|
### PrependAnonymousStyleToHead(href: string, integrity?: string) |
||||
|
|
||||
|
Sets given paremeters and `crossorigin="anonymous"` as attributes of created `<style>` element and places it at the **beginning** of `<head>` tag in the document. |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
## What's Next? |
||||
|
|
||||
|
- [LazyLoadService](./Lazy-Load-Service.md) |
||||
@ -0,0 +1,67 @@ |
|||||
|
## Service Proxies |
||||
|
|
||||
|
It is common to call a REST endpoint in the server from our Angular applications. In this case, we generally create **services** (those have methods for each service method on the server side) and **model objects** (matches to [DTOs](../../Data-Transfer-Objects) in the server side). |
||||
|
|
||||
|
In addition to manually creating such server-interacting services, we could use tools like [NSWAG](https://github.com/RicoSuter/NSwag) to generate service proxies for us. But NSWAG has the following problems we've experienced: |
||||
|
|
||||
|
* It generates a **big, single** .ts file which has some problems; |
||||
|
* It get **too large** when your application grows. |
||||
|
* It doesn't fit into the **[modular](../../Module-Development-Basics) approach** of the ABP framework. |
||||
|
* It creates a bit **ugly code**. We want to have a clean code (just like if we write manually). |
||||
|
* It can not generate the same **method signature** declared in the server side (because swagger.json doesn't exactly reflect the method signature of the backend service). We've created an endpoint that exposes server side method contacts to allow clients generate a better aligned client proxies. |
||||
|
|
||||
|
ABP CLI `generate-proxies` command automatically generates the typescript client proxies by creating folders which separated by module names in the `src/app` folder. |
||||
|
Run the following command in the **root folder** of the angular application: |
||||
|
|
||||
|
```bash |
||||
|
abp generate-proxy |
||||
|
``` |
||||
|
|
||||
|
It only creates proxies only for your own application's services. It doesn't create proxies for the services of the application modules you're using (by default). There are several options. See the [CLI documentation](../../CLI). |
||||
|
|
||||
|
The files generated with the `--module all` option like below: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
### Services |
||||
|
|
||||
|
Each generated service matches a back-end controller. The services methods call back-end APIs via [RestService](./Http-Requests#restservice). |
||||
|
|
||||
|
A variable named `apiName` (available as of v2.4) is defined in each service. `apiName` matches the module's RemoteServiceName. This variable passes to the `RestService` as a parameter at each request. If there is no microservice API defined in the environment, `RestService` uses the default. See [getting a specific API endpoint from application config](./Http-Requests#how-to-get-a-specific-api-endpoint-from-application-config) |
||||
|
|
||||
|
The `providedIn` property of the services is defined as `'root'`. Therefore no need to add a service as a provider to a module. You can use a service by injecting it into a constructor as shown below: |
||||
|
|
||||
|
```js |
||||
|
import { AbpApplicationConfigurationService } from '../app/shared/services'; |
||||
|
|
||||
|
//... |
||||
|
export class HomeComponent{ |
||||
|
constructor(private appConfigService: AbpApplicationConfigurationService) {} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.appConfigService.get().subscribe() |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
The Angular compiler removes the services that have not been injected anywhere from the final output. See the [tree-shakable providers documentation](https://angular.io/guide/dependency-injection-providers#tree-shakable-providers). |
||||
|
|
||||
|
### Models |
||||
|
|
||||
|
The generated models match the DTOs in the back-end. Each model is generated as a class under the `src/app/*/shared/models` folder. |
||||
|
|
||||
|
There are a few [base classes](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/dtos.ts) in the `@abp/ng.core` package. Some models extend these classes. |
||||
|
|
||||
|
A class instance can be created as shown below: |
||||
|
|
||||
|
```js |
||||
|
import { IdentityRoleCreateDto } from '../identity/shared/models'; |
||||
|
//... |
||||
|
const instance = new IdentityRoleCreateDto({name: 'Role 1', isDefault: false, isPublic: true}) |
||||
|
``` |
||||
|
|
||||
|
Initial values can optionally be passed to each class constructor. |
||||
|
|
||||
|
## What's Next? |
||||
|
|
||||
|
* [HTTP Requests](./Http-Requests) |
||||
|
After Width: | Height: | Size: 235 KiB |
File diff suppressed because it is too large
@ -0,0 +1,3 @@ |
|||||
|
## Getting Started With the Angular Application Template |
||||
|
|
||||
|
TODO... |
||||
@ -0,0 +1,6 @@ |
|||||
|
# 启动模板入门 |
||||
|
|
||||
|
参阅下面的教程来学习如何开始使用的ABP框架预构建的应用程序启动模板: |
||||
|
|
||||
|
* [ASP.NET Core MVC/Razor页面模板入门](Getting-Started-AspNetCore-MVC-Template.md) |
||||
|
* [Angular UI模板入门](Getting-Started-Angular-Template.md) |
||||
@ -1,3 +1,469 @@ |
|||||
# ASP.NET Core (MVC / Razor Pages) 用户界面自定义指南 |
# ASP.NET Core (MVC / Razor Pages) 用户界面自定义指南 |
||||
|
|
||||
TODO... |
本文档解释了如何重写ASP.NET Core MVC / Razor Page 应用程序依赖[应用模块](../../Modules/Index.md)的用户界面. |
||||
|
|
||||
|
## 重写页面 |
||||
|
|
||||
|
本节介绍了[Razor 页面](https://docs.microsoft.com/zh-cn/aspnet/core/razor-pages/)开发,它是ASP.NET Core推荐的服务端渲染用户页面的方法. 预构建的模块通常使用Razor页面替代经典的MVC方式(下一节也介绍MVC模式). |
||||
|
|
||||
|
你通过有三种重写页面的需求: |
||||
|
|
||||
|
* 仅**重写页面模型**(C#)端执行其他逻辑,不更改UI. |
||||
|
* 仅**重写Razor页面**(.cshtml文件),不更改逻辑. |
||||
|
* **完全重写** 页面. |
||||
|
|
||||
|
### 重写页面模型 (C#) |
||||
|
|
||||
|
````csharp |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Identity; |
||||
|
using Volo.Abp.Identity.Web.Pages.Identity.Users; |
||||
|
|
||||
|
namespace Acme.BookStore.Web.Pages.Identity.Users |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices(typeof(EditModalModel))] |
||||
|
public class MyEditModalModel : EditModalModel |
||||
|
{ |
||||
|
public MyEditModalModel( |
||||
|
IIdentityUserAppService identityUserAppService, |
||||
|
IIdentityRoleAppService identityRoleAppService |
||||
|
) : base( |
||||
|
identityUserAppService, |
||||
|
identityRoleAppService) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override async Task<IActionResult> OnPostAsync() |
||||
|
{ |
||||
|
//TODO: Additional logic |
||||
|
await base.OnPostAsync(); |
||||
|
//TODO: Additional logic |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
* 这个类继承并替换 `EditModalModel` ,重写了 `OnPostAsync` 方法在基类代码的前后执行附加逻辑 |
||||
|
* 它使用 `ExposeServices` 和 `Dependency` attributes去替换这个类. |
||||
|
|
||||
|
### 重写Razor页面 (.CSHTML) |
||||
|
|
||||
|
使用[虚拟文件系统](../../Virtual-File-System.md)可以重写 `.cshtml` 文件(razor page, razor view, view component... 等.) |
||||
|
|
||||
|
虚拟文件系统允许我们将**资源嵌入到程序集中**. 通过这个方式,预构建的模块在Nuget包中定义了Razor页面. 当你依赖模块时,可以覆盖这个模块向虚拟文件系统添加的任何文件,包括页面/视图. |
||||
|
|
||||
|
#### 示例 |
||||
|
|
||||
|
这个示例重写了[账户模块](../../Modules/Account.md)定义的**登录页面**UI |
||||
|
|
||||
|
物理文件可以覆盖相同位置的嵌入文件. 账户模块在 `Pages/Account` 文件夹下定义了 `Login.cshtml` 文件. 所以你可以在同一路径下创建文件覆盖它: |
||||
|
 |
||||
|
|
||||
|
通常你想要拷贝模块的 `.cshtml` 原文件,然后进行需要的更改. 你可以在[这里](https://github.com/abpframework/abp/blob/dev/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml)找到源文件. 不要拷贝 `Login.cshtml.cs` 文件,它是隐藏razor页面的代码,我们不希望覆盖它(见下节). |
||||
|
|
||||
|
这就够了,接下来你可以对文件内容做你想要的更改. |
||||
|
|
||||
|
### 完全重写Razo页面 |
||||
|
|
||||
|
也许你想要完全重写页面,Razor和页面相关的C#文件. |
||||
|
|
||||
|
在这种情况下; |
||||
|
|
||||
|
1. 像上面描述过的那术重写C#页面模型类,但不需要替换已存在的页面模型类. |
||||
|
2. 像上面描述过的那样重写Razor页面,并且更改@model指向新的页面模型 |
||||
|
|
||||
|
#### 示例 |
||||
|
|
||||
|
这个示例重写了[账户模块](../../Modules/Account.md)定义的**登录页面** |
||||
|
|
||||
|
创建一个继承自 `LoginModel`(定义在`Volo.Abp.Account.Web.Pages.Account`命名空间下)的页面模型类: |
||||
|
|
||||
|
````csharp |
||||
|
public class MyLoginModel : LoginModel |
||||
|
{ |
||||
|
public MyLoginModel( |
||||
|
IAuthenticationSchemeProvider schemeProvider, |
||||
|
IOptions<AbpAccountOptions> accountOptions |
||||
|
) : base( |
||||
|
schemeProvider, |
||||
|
accountOptions) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public override Task<IActionResult> OnPostAsync(string action) |
||||
|
{ |
||||
|
//TODO: Add logic |
||||
|
return base.OnPostAsync(action); |
||||
|
} |
||||
|
|
||||
|
//TODO: Add new methods and properties... |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
如果需要,你可以重写任何方法或添加新的属性/方法 |
||||
|
|
||||
|
> 注意我们没有使用 `[Dependency(ReplaceServices = true)]` 或 `[ExposeServices(typeof(LoginModel))]`,因为我们不想替换依赖注入中已存在的类,我们定义了一个新的. |
||||
|
|
||||
|
拷贝 `Login.cshtml` 到你们解决方案,更改 **@model** 指定到 `MyLoginModel`: |
||||
|
|
||||
|
````xml |
||||
|
@page |
||||
|
... |
||||
|
@model Acme.BookStore.Web.Pages.Account.MyLoginModel |
||||
|
... |
||||
|
```` |
||||
|
|
||||
|
这就够了,接下来你可以做任何想要更改. |
||||
|
|
||||
|
#### 不使用继承替换页面模型 |
||||
|
|
||||
|
你不需要继承源页面模型类(像之前的示例). 你可以完全**重写实现**你自己的页面. 在这种事情下你可以从 `PageModel`,`AbpPageModel` 或任何你需要的合适的基类派生. |
||||
|
|
||||
|
## 重写视图组件 |
||||
|
|
||||
|
在ABP框架,预构建的模块和主题定义了一些**可重用的视图组件**. 这些视图组件可以像页面一样被替换. |
||||
|
|
||||
|
### 示例 |
||||
|
|
||||
|
下面是应用程序启动模板自带的 **基本主题** 的截图. |
||||
|
|
||||
|
 |
||||
|
|
||||
|
[基本主题](../../Themes/Basic.md) 为layout定义了一些视图组件. 例如上面带有红色矩形的突出显示区域称为 **Brand组件**, 你可能想添加自己的**自己的应用程序logo**来自定义此组件. 让我们来看看如何去做. |
||||
|
|
||||
|
首先创建你的logo并且放到你的web应用程序文件夹中,我们使用 `wwwroot/logos/bookstore-logo.png` 路径. 然后在 `Themes/Basic/Components/Brand` 文件夹下复制[Brand组件视图](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml). 结果应该是类似下面的图片: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
然后对 `Default.cshtml` 文件做你想要的更改. 例如内容可以是这样的: |
||||
|
|
||||
|
````xml |
||||
|
<a href="/"> |
||||
|
<img src="~/logos/bookstore-logo.png" width="250" height="60"/> |
||||
|
</a> |
||||
|
```` |
||||
|
|
||||
|
现在你可以运行应用程序看到结果: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
如果你需要,你也可以仅使用依赖注入系统替换组件[背后的C#类代码](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/MainNavbarBrandViewComponent.cs) |
||||
|
|
||||
|
### 重写主题 |
||||
|
|
||||
|
正如上所解释的,你可以更改任何组件,layout或c#类. 参阅[主题文档]了解更多关于主题系统的信息. |
||||
|
|
||||
|
## 重写静态资源 |
||||
|
|
||||
|
重写模块的静态资源(像JavaScript,Css或图片文件)是很简单的. 只需要在解决方案的相同路径创建文件,虚拟文件系统会自动处理它. |
||||
|
|
||||
|
## 操作捆绑 |
||||
|
|
||||
|
[捆绑 & 压缩](Bundling-Minification.md) 系统提供了**动态可扩展的** 系统去创建**script**和**style**捆绑. 它允许你扩展和操作现有的包. |
||||
|
|
||||
|
### 示例: 添加全局CSS文件 |
||||
|
|
||||
|
例如APP框架定义了一个**全局样式捆绑**添加到所有的页面(事实上由主题添加layout). 让我们添加一个**自定义样式文件**到这个捆绑文件的最后,我们可以覆盖任何全局样式. |
||||
|
|
||||
|
创建在 `wwwroot` 文件夹下创建一个CSS文件 |
||||
|
|
||||
|
 |
||||
|
|
||||
|
在CSS文件中定义一些规则. 例如: |
||||
|
|
||||
|
````css |
||||
|
.card-title { |
||||
|
color: orange; |
||||
|
font-size: 2em; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
.btn-primary { |
||||
|
background-color: red; |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
然后在你的[模块](../../Module-Development-Basics.md) `ConfigureServices` 方法添加这个文件到标准的全局样式捆绑包: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpBundlingOptions>(options => |
||||
|
{ |
||||
|
options.StyleBundles.Configure( |
||||
|
StandardBundles.Styles.Global, //The bundle name! |
||||
|
bundleConfiguration => |
||||
|
{ |
||||
|
bundleConfiguration.AddFiles("/styles/my-global-styles.css"); |
||||
|
} |
||||
|
); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
#### 全局脚本捆绑包 |
||||
|
|
||||
|
就像 `StandardBundles.Styles.Global` 一样,还有一个 `StandardBundles.Scripts.Global`,你可以添加文件或操作现有文件. |
||||
|
|
||||
|
### 示例: 操作捆绑包文件 |
||||
|
|
||||
|
上面的示例中添加了新文件到捆绑包. 如果你创建 **bundle contributor** 类则可以做到更多. 示例: |
||||
|
|
||||
|
````csharp |
||||
|
public class MyGlobalStyleBundleContributor : BundleContributor |
||||
|
{ |
||||
|
public override void ConfigureBundle(BundleConfigurationContext context) |
||||
|
{ |
||||
|
context.Files.Clear(); |
||||
|
context.Files.Add("/styles/my-global-styles.css"); |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
然后你可以添加这个contributor到已存在的捆绑中: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpBundlingOptions>(options => |
||||
|
{ |
||||
|
options.StyleBundles.Configure( |
||||
|
StandardBundles.Styles.Global, |
||||
|
bundleConfiguration => |
||||
|
{ |
||||
|
bundleConfiguration.AddContributors(typeof(MyGlobalStyleBundleContributor)); |
||||
|
} |
||||
|
); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
示例中清除了所有的CSS文件,在现实中这并不是一个好主意,你可以找到某个特定的文件替换成你自己的文件. |
||||
|
|
||||
|
### 示例: 为特定页面添加JavaScript文件 |
||||
|
|
||||
|
上面的示例将全局包添加到布局中. 如果要在依赖模块中为特定页面定义添加CSS/JavaScript文件(或替换文件)怎么做? |
||||
|
|
||||
|
假设你想要用户进入身份模块的**角色管理**页面时运行**JavaScript代码**. |
||||
|
|
||||
|
首先在 `wwwroot`, `Pages` 或 `Views` 文件夹下创建一个标准的JavaScript文件(默认ABP支持这些文件夹下的静态文件). 根据约定我们推荐 `Pages/Identity/Roles` 文件夹: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
该文件的内容很简单: |
||||
|
|
||||
|
````js |
||||
|
$(function() { |
||||
|
abp.log.info('My custom role script file has been loaded!'); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
然后将这个文件添加到角色管页面理捆绑包中: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpBundlingOptions>(options => |
||||
|
{ |
||||
|
options.ScriptBundles |
||||
|
.Configure( |
||||
|
typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.IndexModel).FullName, |
||||
|
bundleConfig => |
||||
|
{ |
||||
|
bundleConfig.AddFiles("/Pages/Identity/Roles/my-role-script.js"); |
||||
|
}); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
`typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.IndexModel).FullName` 是获取角色管理页面捆绑包名称的安全方式: |
||||
|
|
||||
|
> 请注意并非每个页面都定义了这个页面的捆绑包. 它们仅在需要时定义. |
||||
|
|
||||
|
除了添加新的CSS/JavaScript文件到页面,你也可以以替换(通过捆绑包contributor)已存在. |
||||
|
|
||||
|
## 布局定制 |
||||
|
|
||||
|
布局由主题([参阅主题](Theming.md))定义设计. 它们不包含在下载的应用程序解决方案中. 通过这种方式你可以轻松的**更改**主题并获取新的功能. 你不能**直接更改**应用程序中的布局代码,除非你用自己的布局替换它(在下一部分中说明). |
||||
|
|
||||
|
有一些通用的方法可以**自定义布局**,将在下一节中介绍. |
||||
|
|
||||
|
### 菜单贡献者 |
||||
|
|
||||
|
ABP框架定义了两个**标准菜单**: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
* `StandardMenus.Main`: 应用程序的主菜单. |
||||
|
* `StandardMenus.User`: 用户菜单 (通常在屏幕的右上方). |
||||
|
|
||||
|
显示菜单是主题的责任,但**菜单项**由模板和你的应用程序代码决定. 只需要实现 `IMenuContributor` 接口并在 `ConfigureMenuAsync` 方法操作菜单项. |
||||
|
|
||||
|
渲染菜单时需要执行菜单贡献者. **应用程序启动模板** 已经定义了菜单贡献者,所以你可以使用它. 参阅[导航菜单](Navigation-Menu.md)文档了解更多. |
||||
|
|
||||
|
### 工具栏贡献者 |
||||
|
|
||||
|
[工具栏系统](Toolbars.md)用于在用户界面定义 **工具栏** . 模块 (或你的应用程序)可以将 **项** 添加到工具栏, 随后主题将在**布局**上呈现工具栏. |
||||
|
|
||||
|
只有一个 **标准工具栏** (名称为 "Main" - 定义为常量: `StandardToolbars.Main`). 对于基本主题,按如下呈现: |
||||
|
|
||||
|
在上面的屏幕快照中,主工具栏添加了两个项目:语言开关组件和用户菜单. 你可以在此处添加自己的项. |
||||
|
|
||||
|
#### 示例: 添加通知图标 |
||||
|
|
||||
|
在这个示例中,我们会添加一个**通知(响铃)图标**到语言切换项的左侧. 工具栏的项项目是一个**视图组件**. 所以,在你的项目中创建一个新的视图组件: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
**NotificationViewComponent.cs** |
||||
|
|
||||
|
````csharp |
||||
|
public class NotificationViewComponent : AbpViewComponent |
||||
|
{ |
||||
|
public async Task<IViewComponentResult> InvokeAsync() |
||||
|
{ |
||||
|
return View("/Pages/Shared/Components/Notification/Default.cshtml"); |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
**Default.cshtml** |
||||
|
|
||||
|
````xml |
||||
|
<div id="MainNotificationIcon" style="color: white; margin: 8px;"> |
||||
|
<i class="far fa-bell"></i> |
||||
|
</div> |
||||
|
```` |
||||
|
|
||||
|
现在,我们创建一个类实现 `IToolbarContributor` 接口: |
||||
|
|
||||
|
````csharp |
||||
|
public class MyToolbarContributor : IToolbarContributor |
||||
|
{ |
||||
|
public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) |
||||
|
{ |
||||
|
if (context.Toolbar.Name == StandardToolbars.Main) |
||||
|
{ |
||||
|
context.Toolbar.Items |
||||
|
.Insert(0, new ToolbarItem(typeof(NotificationViewComponent))); |
||||
|
} |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
这个类向 `Main` 工具栏的第一项添加了 `NotificationViewComponent`. |
||||
|
|
||||
|
最后你需要将这个贡献者添加到 `AbpToolbarOptions`,在你模块类的 `ConfigureServices` 方法: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpToolbarOptions>(options => |
||||
|
{ |
||||
|
options.Contributors.Add(new MyToolbarContributor()); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
这就够了,当你运行应用程序后会看到工具栏上的通知图标: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
示例中的 `NotificationViewComponent` 返回没有任何数据的视图. 在实际场景中,你可能想**查询数据库**(或调用HTTP API)获取通知并传递给视图. 如果需要可以将 `JavaScript` 或 `CSS` 文件添加到工具栏的全局捆绑包中(如前所述). |
||||
|
|
||||
|
参阅[工具栏文档](Toolbars.md)了解更多关于工具栏系统. |
||||
|
|
||||
|
### 布局钩子 |
||||
|
|
||||
|
[布局钩子](Layout-Hooks.md) 系统允许你在布局页面的某些特定部分 **添加代码** . 所有主题的所有布局都应该实现这些钩子. 然后你可以将**视图组件**添加到钩子. |
||||
|
|
||||
|
#### 示例: 添加谷歌统计 |
||||
|
|
||||
|
假设你想要添加谷歌统计脚本到布局(将适用所有的页面). 首先在你的项目中**创建一个视图组件**: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
**NotificationViewComponent.cs** |
||||
|
|
||||
|
````csharp |
||||
|
public class GoogleAnalyticsViewComponent : AbpViewComponent |
||||
|
{ |
||||
|
public IViewComponentResult Invoke() |
||||
|
{ |
||||
|
return View("/Pages/Shared/Components/GoogleAnalytics/Default.cshtml"); |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
**Default.cshtml** |
||||
|
|
||||
|
````html |
||||
|
<script> |
||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ |
||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), |
||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) |
||||
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); |
||||
|
|
||||
|
ga('create', 'UA-xxxxxx-1', 'auto'); |
||||
|
ga('send', 'pageview'); |
||||
|
</script> |
||||
|
```` |
||||
|
|
||||
|
在你自己的代码中更改 `UA-xxxxxx-1` . |
||||
|
|
||||
|
然后你可以在你模块的 `ConfigureServices` 方法将这个组件添加到任何的钩子点: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpLayoutHookOptions>(options => |
||||
|
{ |
||||
|
options.Add( |
||||
|
LayoutHooks.Head.Last, //The hook name |
||||
|
typeof(GoogleAnalyticsViewComponent) //The component to add |
||||
|
); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
现在谷歌统计代码将在页面的 `head` 所为最后一项插入. 你(或你在使用的模块)可以将多个项添加到相同的钩子,它们都会添加到布局. |
||||
|
|
||||
|
在上面我们添加 `GoogleAnalyticsViewComponent` 到所有的布局,你可能只想添加到指定的布局: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpLayoutHookOptions>(options => |
||||
|
{ |
||||
|
options.Add( |
||||
|
LayoutHooks.Head.Last, |
||||
|
typeof(GoogleAnalyticsViewComponent), |
||||
|
layout: StandardLayouts.Application //Set the layout to add |
||||
|
); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
参阅下面的布局部分,以了解有关布局系统的更多信息. |
||||
|
|
||||
|
### 布局 |
||||
|
|
||||
|
布局系统允许主题定义标准,命名布局并且允许任何页面选择使用合适的布局. 有三种预定义的布局: |
||||
|
|
||||
|
* "**Application**": 应用程序的主要(和默认)布局. 它通常包含页眉,菜单(侧栏),页脚,工具栏等. |
||||
|
* "**Account**": 登录,注册和其他类似页面使用此布局. 默认它用于 `/Pages/Account` 文件夹下的页面. |
||||
|
* "**Empty**": 空的最小的布局. |
||||
|
|
||||
|
这些名称在 `StandardLayouts` 类定义为常量. 这是标准的布局名称,所有的主题开箱即用的实现. 你也可以创建自己的布局. |
||||
|
|
||||
|
#### 布局位置 |
||||
|
|
||||
|
你可以在[这里](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts)找到基本主题的布局文件. 你可以将它们作用构建自己的布局的参考,也可以在必要时覆盖它们. |
||||
|
|
||||
|
#### ITheme |
||||
|
|
||||
|
ABP框架使用 `ITheme` 服务通过局部名称获取布局位置. 你可以替换此服务动态的选择布局位置. |
||||
|
|
||||
|
#### IThemeManager |
||||
|
|
||||
|
`IThemeManager` 用于获取当前主题,并得到了布局路径. 任何页面可以都决定自己的布局. 例: |
||||
|
|
||||
|
````html |
||||
|
@using Volo.Abp.AspNetCore.Mvc.UI.Theming |
||||
|
@inject IThemeManager ThemeManager |
||||
|
@{ |
||||
|
Layout = ThemeManager.CurrentTheme.GetLayout(StandardLayouts.Empty); |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
此页面将使用空白布局. 它使用 `ThemeManager.CurrentTheme.GetEmptyLayout()` 扩展方法. |
||||
|
|
||||
|
如果你设置特定目录下所有页面的布局,可以在该文件夹下的 `_ViewStart.cshtml` 文件编写以上代码. |
||||
|
|||||
@ -0,0 +1,80 @@ |
|||||
|
# Alerts |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-alert` 是创建alert的主要元素. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-alert alert-type="Primary"> |
||||
|
A simple primary alert—check it out! |
||||
|
</abp-alert> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[alerts demo页面](https://bootstrap-taghelpers.abp.io/Components/Alerts)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### alert-type |
||||
|
|
||||
|
值做为alert的Type,应为以下值之一: |
||||
|
|
||||
|
* `Default` (默认值) |
||||
|
* `Primary` |
||||
|
* `Secondary` |
||||
|
* `Success` |
||||
|
* `Danger` |
||||
|
* `Warning` |
||||
|
* `Info` |
||||
|
* `Light` |
||||
|
* `Dark` |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-alert alert-type="Warning"> |
||||
|
A simple warning alert—check it out! |
||||
|
</abp-alert> |
||||
|
```` |
||||
|
|
||||
|
### alert-link |
||||
|
|
||||
|
alert的链接. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-alert alert-type="Danger"> |
||||
|
A simple danger alert with <a abp-alert-link href="#">an example link</a>. Give it a click if you like. |
||||
|
</abp-alert> |
||||
|
```` |
||||
|
|
||||
|
### dismissible |
||||
|
|
||||
|
使alert可被忽略: |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-alert alert-type="Warning" dismissible="true"> |
||||
|
Holy guacamole! You should check in on some of those fields below. |
||||
|
</abp-alert> |
||||
|
```` |
||||
|
|
||||
|
### Additional content |
||||
|
|
||||
|
`abp-alert`还可以包含其他HTML元素,例如标题,段落和分隔符. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-alert alert-type="Success"> |
||||
|
<h4>Well done!</h4> |
||||
|
<p>Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.</p> |
||||
|
<hr> |
||||
|
<p class="mb-0">Whenever you need to, be sure to use margin utilities to keep things nice and tidy.</p> |
||||
|
</abp-alert> |
||||
|
```` |
||||
@ -0,0 +1,180 @@ |
|||||
|
# 卡片 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-card` 是从bootstrap card元素派生的内容容器. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-card style="width: 18rem;"> |
||||
|
<img abp-card-image="Top" src="~/imgs/demo/300x200.png"/> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title>Card Title</abp-card-title> |
||||
|
<abp-card-text>Some quick example text to build on the card title and make up the bulk of the card's content.</abp-card-text> |
||||
|
<a abp-button="Primary" href="#"> Go somewhere</a> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
```` |
||||
|
|
||||
|
##### 使用标题,文本和链接: |
||||
|
|
||||
|
`abp-card` 可以使用以下标签 |
||||
|
|
||||
|
* `abp-card-title` |
||||
|
* `abp-card-subtitle` |
||||
|
* `a abp-card-link` |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-card style="width: 18rem;"> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title>Card title</abp-card-title> |
||||
|
<abp-card-subtitle class="mb-2 text-muted">Card subtitle</abp-card-subtitle> |
||||
|
<abp-card-text>Some quick example text to build on the card title and make up the bulk of the card's content.</abp-card-text> |
||||
|
<a abp-card-link href="#">Card link</a> |
||||
|
<a abp-card-link href="#">Another link</a> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
```` |
||||
|
|
||||
|
##### 使用列表组: |
||||
|
|
||||
|
* `abp-list-group flush="true"` : `flush` 属性渲染到 bootstrap `list-group-flush` 的 calss 中,该类用于删除边界和圆角以使列表组项在父容器中并排显示. |
||||
|
* `abp-list-group-item` |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-card style="width: 18rem;"> |
||||
|
<img abp-card-image="Top" src="~/imgs/demo/300x200.png" /> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title>Card Title</abp-card-title> |
||||
|
<abp-card-text>Some quick example text to build on the card title and make up the bulk of the card's content.</abp-card-text> |
||||
|
</abp-card-body> |
||||
|
<abp-list-group flush="true"> |
||||
|
<abp-list-group-item>Cras justo odio</abp-list-group-item> |
||||
|
<abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item> |
||||
|
<abp-list-group-item>Vestibulum at eros</abp-list-group-item> |
||||
|
</abp-list-group> |
||||
|
<abp-card-body> |
||||
|
<a abp-card-link href="#">Card link</a> |
||||
|
<a abp-card-link href="#">Another link</a> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
```` |
||||
|
|
||||
|
##### 使用页眉,页脚和块引用: |
||||
|
|
||||
|
* `abp-card-header` |
||||
|
* `abp-card-footer` |
||||
|
* `abp-blockquote` |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-card style="width: 18rem;"> |
||||
|
<abp-card-header>Featured</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title> Special title treatment</abp-card-title> |
||||
|
<abp-card-text>With supporting text below as a natural lead-in to additional content.</abp-card-text> |
||||
|
<a abp-button="Primary" href="#"> Go somewhere</a> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
``` |
||||
|
|
||||
|
引用示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-card> |
||||
|
<abp-card-header>Quote</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-blockquote> |
||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p> |
||||
|
<footer>Someone famous in Source Title</footer> |
||||
|
</abp-blockquote> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
``` |
||||
|
|
||||
|
页脚示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-card class="text-center"> |
||||
|
<abp-card-header>Featured</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-blockquote> |
||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p> |
||||
|
<footer>Someone famous in Source Title</footer> |
||||
|
</abp-blockquote> |
||||
|
</abp-card-body> |
||||
|
<abp-card-footer class="text-muted"> 2 days ago</abp-card-footer> |
||||
|
</abp-card> |
||||
|
``` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[卡片demo页面](https://bootstrap-taghelpers.abp.io/Components/Cards)查看示例. |
||||
|
|
||||
|
## abp-card Attributes |
||||
|
|
||||
|
- **background:** 值指定卡片背景的颜色. |
||||
|
- **text-color**: 值指定卡片内文本的颜色. |
||||
|
- **border:** 值指定卡片边框的颜色. |
||||
|
|
||||
|
应为以下值之一: |
||||
|
|
||||
|
* `Default` (默认值) |
||||
|
* `Primary` |
||||
|
* `Secondary` |
||||
|
* `Success` |
||||
|
* `Danger` |
||||
|
* `Warning` |
||||
|
* `Info` |
||||
|
* `Light` |
||||
|
* `Dark` |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-card background="Success" text-color="Danger" border="Dark"> |
||||
|
```` |
||||
|
|
||||
|
### sizing |
||||
|
|
||||
|
卡片的默认值为100%,可以使用自定义CSS,栅格类,栅格Sass mixins或[utilities](https://getbootstrap.com/docs/4.0/utilities/sizing/)进行更改. |
||||
|
|
||||
|
````xml |
||||
|
<abp-card style="width: 18rem;"> |
||||
|
```` |
||||
|
|
||||
|
### card-deck 和 card-columns |
||||
|
|
||||
|
`abp-card` 可以在 `card-deck` 或 `card-columns` 里使用. |
||||
|
|
||||
|
````xml |
||||
|
<div class="card-deck"> |
||||
|
<abp-card background="Primary"> |
||||
|
<abp-card-header>First Deck</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title> Ace </abp-card-title> |
||||
|
<abp-card-text>Here is the content for Ace.</abp-card-text> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
<abp-card background="Info"> |
||||
|
<abp-card-header>Second Deck</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title> Beta </abp-card-title> |
||||
|
<abp-card-text>Beta content.</abp-card-text> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
<abp-card background="Warning"> |
||||
|
<abp-card-header>Third Deck</abp-card-header> |
||||
|
<abp-card-body> |
||||
|
<abp-card-title> Epsilon </abp-card-title> |
||||
|
<abp-card-text>Content for Epsilon.</abp-card-text> |
||||
|
</abp-card-body> |
||||
|
</abp-card> |
||||
|
</div> |
||||
|
```` |
||||
@ -0,0 +1,90 @@ |
|||||
|
# Collapse |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-collapse-body` 是显示和隐藏内容的主要容器. `abp-collapse-id` 用于显示和隐藏内容容器. 可以通过 `abp-button` 和 `a` 标签触发. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-button button-type="Primary" abp-collapse-id="collapseExample" text="Button with data-target" /> |
||||
|
<a abp-button="Primary" abp-collapse-id="collapseExample"> Link with href </a> |
||||
|
|
||||
|
<abp-collapse-body id="collapseExample"> |
||||
|
Anim pariatur wolf moon tempor,,, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. |
||||
|
</abp-collapse-body> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[collapse demo 页面](https://bootstrap-taghelpers.abp.io/Components/Collapse)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### show |
||||
|
|
||||
|
指定折叠主体初始化时是折叠还是展开. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### multi |
||||
|
|
||||
|
指定 `abp-collapse-body` 是否可以通过显示/隐藏多个折叠体的元素显示或隐藏. 此属性做为 "multi-collapse" class 添加到 `abp-collapse-body`. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<a abp-button="Primary" abp-collapse-id="FirstCollapseExample"> Toggle first element </a> |
||||
|
<abp-button button-type="Primary" abp-collapse-id="SecondCollapseExample" text="Toggle second element" /> |
||||
|
<abp-button button-type="Primary" abp-collapse-id="FirstCollapseExample SecondCollapseExample" text="Toggle both elements" /> |
||||
|
|
||||
|
<abp-row class="mt-3"> |
||||
|
<abp-column size-sm="_6"> |
||||
|
<abp-collapse-body id="FirstCollapseExample" multi="true"> |
||||
|
Curabitur porta porttitor libero eu luctus. Praesent ultrices mattis commodo. Integer sodales massa risus, in molestie enim sagittis blandit |
||||
|
</abp-collapse-body> |
||||
|
</abp-column> |
||||
|
<abp-column size-sm="_6"> |
||||
|
<abp-collapse-body id="SecondCollapseExample" multi="true"> |
||||
|
Anim pariatur wolf moon tempor,,, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. |
||||
|
</abp-collapse-body> |
||||
|
</abp-column> |
||||
|
</abp-row> |
||||
|
```` |
||||
|
|
||||
|
## 手风琴示例 |
||||
|
|
||||
|
`abp-accordion` 是手风琴项的主容器. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-accordion> |
||||
|
<abp-accordion-item title="Collapsible Group Item #1"> |
||||
|
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry rtat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. |
||||
|
</abp-accordion-item> |
||||
|
<abp-accordion-item title="Collapsible Group Item #2"> |
||||
|
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. |
||||
|
</abp-accordion-item> |
||||
|
<abp-accordion-item title="Collapsible Group Item #3"> |
||||
|
Anim pariatur wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. |
||||
|
</abp-accordion-item> |
||||
|
</abp-accordion> |
||||
|
```` |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### active |
||||
|
|
||||
|
指定手风琴项目在初始化时是显示还是隐藏. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### title |
||||
|
|
||||
|
指定手风琴项的标题. 应为字符串类型的值. |
||||
@ -0,0 +1,93 @@ |
|||||
|
# 下拉菜单 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-dropdown` 是下拉菜单的主要容器. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-dropdown> |
||||
|
<abp-dropdown-button text="Dropdown button" /> |
||||
|
<abp-dropdown-menu> |
||||
|
<abp-dropdown-item href="#">Action</abp-dropdown-item> |
||||
|
<abp-dropdown-item href="#">Another action</abp-dropdown-item> |
||||
|
<abp-dropdown-item href="#">Something else here</abp-dropdown-item> |
||||
|
</abp-dropdown-menu> |
||||
|
</abp-dropdown> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅 [下拉菜单demo页面](https://bootstrap-taghelpers.abp.io/Components/Dropdowns)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### direction |
||||
|
|
||||
|
指定下拉菜单的方向. 应为以下值之一: |
||||
|
|
||||
|
* `Down` (默认值) |
||||
|
* `Up` |
||||
|
* `Right` |
||||
|
* `Left` |
||||
|
|
||||
|
### dropdown-style |
||||
|
|
||||
|
指定 `abp-dropdown-button` 是否具有用于拆分的拆分图标. 应为以下值之一: |
||||
|
|
||||
|
* `Single` (默认值) |
||||
|
* `Split` |
||||
|
|
||||
|
## Menu items |
||||
|
|
||||
|
`abp-dropdown-menu` 下拉菜单项的主要容器. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-dropdown> |
||||
|
<abp-dropdown-button button-type="Secondary" text="Dropdown"/> |
||||
|
<abp-dropdown-menu> |
||||
|
<abp-dropdown-header>Dropdown Header</abp-dropdown-header> |
||||
|
<abp-dropdown-item href="#">Action</abp-dropdown-item> |
||||
|
<abp-dropdown-item active="true" href="#">Active action</abp-dropdown-item> |
||||
|
<abp-dropdown-item disabled="true" href="#">Disabled action</abp-dropdown-item> |
||||
|
<abp-dropdown-divider/> |
||||
|
<abp-dropdown-item-text>Dropdown Item Text</abp-dropdown-item-text> |
||||
|
<abp-dropdown-item href="#">Something else here</abp-dropdown-item> |
||||
|
</abp-dropdown-menu> |
||||
|
</abp-dropdown> |
||||
|
```` |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### align |
||||
|
|
||||
|
指定 `abp-dropdown-menu` 在哪个方向对齐. 应为以下值之一: |
||||
|
|
||||
|
* `Left` (默认值) |
||||
|
* `Right` |
||||
|
|
||||
|
### Additional content |
||||
|
|
||||
|
`abp-dropdown-menu` 也可以包含其他HTML元素,例如标题,段落,分隔符或form元素. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-dropdown > |
||||
|
<abp-dropdown-button button-type="Secondary" text="Dropdown With Form"/> |
||||
|
<abp-dropdown-menu> |
||||
|
<form class="px-4 py-3"> |
||||
|
<abp-input asp-for="EmailAddress"></abp-input> |
||||
|
<abp-input asp-for="Password"></abp-input> |
||||
|
<abp-input asp-for="RememberMe"></abp-input> |
||||
|
<abp-button button-type="Primary" text="Sign In" type="submit" /> |
||||
|
</form> |
||||
|
<abp-dropdown-divider></abp-dropdown-divider> |
||||
|
<abp-dropdown-item href="#">New around here? Sign up</abp-dropdown-item> |
||||
|
<abp-dropdown-item href="#">Forgot password?</abp-dropdown-item> |
||||
|
</abp-dropdown-menu> |
||||
|
</abp-dropdown> |
||||
|
```` |
||||
@ -0,0 +1,273 @@ |
|||||
|
# 栅格 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
ABP标签助手基于bootstrap栅格系统. |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[网络demo页面](https://bootstrap-taghelpers.abp.io/Components/Grids)查看示例. |
||||
|
|
||||
|
### Sizing |
||||
|
|
||||
|
**等宽:** 创建等宽的列. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-container> |
||||
|
<abp-row> |
||||
|
<abp-column abp-border="Info">1 of 2</abp-column> |
||||
|
<abp-column abp-border="Danger">2 of 2</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column abp-border="Primary">1 of 3</abp-column> |
||||
|
<abp-column abp-border="Secondary">2 of 3</abp-column> |
||||
|
<abp-column abp-border="Dark">3 of 3</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
```` |
||||
|
|
||||
|
**列中断:** `abp-column-breaker` 用于中断当前行的自动放置宽度,然后在新行中开始. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-container> |
||||
|
<abp-row> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column-breaker/> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
```` |
||||
|
|
||||
|
**设置列宽度:** size属性用于设置特定列的宽度. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-container> |
||||
|
<abp-row> |
||||
|
<abp-column>1 of 3</abp-column> |
||||
|
<abp-column size="_6">2 of 3 (wider)</abp-column> |
||||
|
<abp-column>3 of 3</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column>1 of 3</abp-column> |
||||
|
<abp-column size="_5">2 of 3 (wider)</abp-column> |
||||
|
<abp-column>3 of 3</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
``` |
||||
|
|
||||
|
**可变宽度内容:** 根据内容自动调整列的大小. |
||||
|
|
||||
|
```xml |
||||
|
<abp-container> |
||||
|
<abp-row h-align="Center"> |
||||
|
<abp-column size-lg="_2" abp-border="Info">1 of 3</abp-column> |
||||
|
<abp-column size-md="Auto" abp-border="Danger">Contrary to popular belief, Lorem Ipsum is not simply random text.</abp-column> |
||||
|
<abp-column size-lg="_2" abp-border="Warning">3 of 3</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column>1 of 3</abp-column> |
||||
|
<abp-column size-md="Auto">Variable width content</abp-column> |
||||
|
<abp-column size-lg="_2">3 of 3</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
``` |
||||
|
|
||||
|
### 响应类 |
||||
|
|
||||
|
响应式类可以在abp标签中强类型使用. |
||||
|
|
||||
|
```xml |
||||
|
<abp-row> |
||||
|
<abp-column size-sm="_8">col-sm-8</abp-column> |
||||
|
<abp-column size-sm="_4">col-sm-4</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column size-sm="_">col-sm</abp-column> |
||||
|
<abp-column size-sm="_">col-sm</abp-column> |
||||
|
<abp-column size-sm="_">col-sm</abp-column> |
||||
|
<abp-column size-sm="_">col-sm</abp-column> |
||||
|
</abp-row> |
||||
|
<!-- Stack the columns on mobile by making one full-width and the other half-width --> |
||||
|
<abp-row> |
||||
|
<abp-column size="_12" size-md="_8">.col-12 .col-md-8</abp-column> |
||||
|
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column> |
||||
|
</abp-row> |
||||
|
|
||||
|
<!-- Columns start at 50% wide on mobile and bump up to 33.3% wide on desktop --> |
||||
|
<abp-row> |
||||
|
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column> |
||||
|
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column> |
||||
|
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column> |
||||
|
</abp-row> |
||||
|
|
||||
|
<!-- Columns are always 50% wide, on mobile and desktop --> |
||||
|
<abp-row> |
||||
|
<abp-column size="_6">.col-6</abp-column> |
||||
|
<abp-column size="_6">.col-6</abp-column> |
||||
|
</abp-row> |
||||
|
``` |
||||
|
|
||||
|
### 对齐 |
||||
|
|
||||
|
可以使用强类型的abp标签在垂直和水平方向上进行列对齐. |
||||
|
|
||||
|
**垂直对齐**: `v-align` 属性值用于对垂直齐列. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-container> |
||||
|
<abp-row v-align="Start"> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row v-align="Center"> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row v-align="End"> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
<abp-column>column</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
``` |
||||
|
|
||||
|
**水平对齐**: `h-align` 属性值用于对水平齐列. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-container> |
||||
|
<abp-row h-align="Start"> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row h-align="Center"> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row h-align="End"> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row h-align="Around"> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row h-align="Between"> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
``` |
||||
|
|
||||
|
**无间隙**: 可以使用 `gutters="false"` 删除预定义栅格类中列之间的栅格线. 这会从 `abp-row` 中消除负边距,并从所有直接子列中消除水平边距. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-row gutters="false"> |
||||
|
<abp-column size="_8">One of two columns</abp-column> |
||||
|
<abp-column size="_4">One of two columns</abp-column> |
||||
|
</abp-row> |
||||
|
``` |
||||
|
|
||||
|
**列包装**: 如果在一行中放置超过12列,则将每组额外的列作为一个单元包装到新行上. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-row> |
||||
|
<abp-column size="_9">.col-9</abp-column> |
||||
|
<abp-column size="_4">.col-4<br>Since 9 + 4 = 13 > 12, this 4-column-wide div gets wrapped onto a new line as one contiguous unit.</abp-column> |
||||
|
<abp-column size="_6">.col-6<br>Subsequent columns continue along the new line.s</abp-column> |
||||
|
</abp-row> |
||||
|
``` |
||||
|
|
||||
|
### 重新排序 |
||||
|
|
||||
|
**Order类**: `order` 属性用于控制内容的视觉顺序. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-container> |
||||
|
<abp-row> |
||||
|
<abp-column order="_12">First, but Last</abp-column> |
||||
|
<abp-column>Second, but unordered</abp-column> |
||||
|
<abp-column order="_6">Third, but Second</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
``` |
||||
|
|
||||
|
**偏移列**: `offset` 属性用于设置栅格列的偏移量. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
```xml |
||||
|
<abp-container> |
||||
|
<abp-row> |
||||
|
<abp-column size-md="_4">.col-md-4</abp-column> |
||||
|
<abp-column size-md="_4" offset-md="_4">.col-md-4 .offset-md-4</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column size-md="_3" offset-md="_3">.col-md-3 .offset-md-3</abp-column> |
||||
|
<abp-column size-md="_3" offset-md="_3">.col-md-3 .offset-md-3</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column size-md="_6" offset-md="_3">.col-md-6 .offset-md-3</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column size-sm="_5" size-md="_6">.col-sm-5 .col-md-6</abp-column> |
||||
|
<abp-column size-sm="_5" offset-sm="_2" size-md="_6" offset-md="_">.col-sm-5 .offset-sm-2 .col-md-6 .offset-md-0</abp-column> |
||||
|
</abp-row> |
||||
|
<abp-row> |
||||
|
<abp-column size-sm="_6" size-md="_5" size-lg="_6">col-sm-6 .col-md-5 .col-lg-6</abp-column> |
||||
|
<abp-column size-sm="_6" size-md="_5" offset-md="_2" size-lg="_6" offset-lg="_">.col-sm-6 .col-md-5 .offset-md-2 .col-lg-6 .offset-lg-0</abp-column> |
||||
|
</abp-row> |
||||
|
</abp-container> |
||||
|
``` |
||||
|
|
||||
|
## abp-row Attributes |
||||
|
|
||||
|
- **v-align:** 指定包含列的垂直位置. 应为以下值之一: |
||||
|
* `Default` (默认值) |
||||
|
* `Start` |
||||
|
* `Center` |
||||
|
* `End` |
||||
|
|
||||
|
- **h-align**: 指定包含列的水平位置. 应为以下值之一: |
||||
|
* `Default` (默认值) |
||||
|
* `Start` |
||||
|
* `Center` |
||||
|
* `Around` |
||||
|
* `Between` |
||||
|
* `End` |
||||
|
- **gutter**: 指定是否将从所有子列中删除负边距和水平填充. 如果未设置,默认为 `true`. 应为以下值之一: |
||||
|
* `true` |
||||
|
* `false` |
||||
|
|
||||
|
## abp-column Attributes |
||||
|
|
||||
|
- **size:** 指定列的宽度: `_`, `Undefined`, `_1`..`_12`, `Auto`. 或者可以与预定义值一起使用,例如: |
||||
|
- `size-sm` |
||||
|
- `size-md` |
||||
|
- `size-lg` |
||||
|
- `size-xl` |
||||
|
- **order**: 指定列的顺序: `Undefined`, `_1`..`_12`, `First` 和 `Last`. |
||||
|
- **offset:** 指定列的偏移量: `_`, `Undefined`, `_1`..`_12`, `Auto`. 或者可以与预定义值一起使用,例如: |
||||
|
- `offset-sm` |
||||
|
- `offset-md` |
||||
|
- `offset-lg` |
||||
|
- `offset-xl` |
||||
@ -0,0 +1,76 @@ |
|||||
|
# 列表组 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-list-group` 是列表组内容的主要容器. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-list-group> |
||||
|
<abp-list-group-item>Cras justo odio</abp-list-group-item> |
||||
|
<abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item> |
||||
|
<abp-list-group-item>Morbi leo risus</abp-list-group-item> |
||||
|
<abp-list-group-item>Vestibulum at eros</abp-list-group-item> |
||||
|
</abp-list-group> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[列表组demo页面](https://bootstrap-taghelpers.abp.io/Components/ListGroups)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### flush |
||||
|
|
||||
|
指定 `abp-list-group` 项可删除某些边框和圆角,以在父容器中无边框呈现列表组项. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### active |
||||
|
|
||||
|
指定 `abp-list-group-item` 是否处于active. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### disabled |
||||
|
|
||||
|
指定 `abp-list-group-item` 是否被禁用. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### href |
||||
|
|
||||
|
指定 `abp-list-group-item` 是否含有链接. 应该是一个字符串链接值. |
||||
|
|
||||
|
### type |
||||
|
|
||||
|
指定 `abp-list-group-item` 具有状态背景和颜色的样式类. 应为以下值之一: |
||||
|
|
||||
|
* `Default` (默认值) |
||||
|
* `Primary` |
||||
|
* `Secondary` |
||||
|
* `Success` |
||||
|
* `Danger` |
||||
|
* `Warning` |
||||
|
* `Info` |
||||
|
* `Light` |
||||
|
* `Dark` |
||||
|
* `Link` |
||||
|
|
||||
|
### Additional content |
||||
|
|
||||
|
`abp-list-group-item` 还可以包含其他HTML元素(例如span). |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-list-group> |
||||
|
<abp-list-group-item>Cras justo odio <span abp-badge-pill="Primary">14</span></abp-list-group-item> |
||||
|
<abp-list-group-item>Dapibus ac facilisis in <span abp-badge-pill="Primary">2</span></abp-list-group-item> |
||||
|
<abp-list-group-item>Morbi leo risus <span abp-badge-pill="Primary">1</span></abp-list-group-item> |
||||
|
</abp-list-group> |
||||
|
```` |
||||
@ -0,0 +1,79 @@ |
|||||
|
# 模态框 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-modal` 是创建模态框的主要元素. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-button button-type="Primary" data-toggle="modal" data-target="#myModal">Launch modal</abp-button> |
||||
|
|
||||
|
<abp-modal centered="true" size="Large" id="myModal"> |
||||
|
<abp-modal-header title="Modal title"></abp-modal-header> |
||||
|
<abp-modal-body> |
||||
|
Woohoo, you're reading this text in a modal! |
||||
|
</abp-modal-body> |
||||
|
<abp-modal-footer buttons="Close"></abp-modal-footer> |
||||
|
</abp-modal> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[模态框demo页面](https://bootstrap-taghelpers.abp.io/Components/Modals)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### centered |
||||
|
|
||||
|
指定模态框的位置. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### size |
||||
|
|
||||
|
指定模态框的大小. 应为以下值之一: |
||||
|
|
||||
|
* `Default` (默认值) |
||||
|
* `Small` |
||||
|
* `Large` |
||||
|
* `ExtraLarge` |
||||
|
|
||||
|
### static |
||||
|
|
||||
|
指定模态框是否是静态的. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### Additional content |
||||
|
|
||||
|
`abp-modal-footer` 可以有多个带有对齐选项的按钮. |
||||
|
|
||||
|
添加 `@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal` 到你的页面. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-button button-type="Primary" data-toggle="modal" data-target="#myModal">Launch modal</abp-button> |
||||
|
|
||||
|
<abp-modal centered="true" size="Large" id="myModal" static="true"> |
||||
|
<abp-modal-header title="Modal title"></abp-modal-header> |
||||
|
<abp-modal-body> |
||||
|
Woohoo, you're reading this text in a modal! |
||||
|
</abp-modal-body> |
||||
|
<abp-modal-footer buttons="@(AbpModalButtons.Save|AbpModalButtons.Close)" button-alignment="Between"></abp-modal-footer> |
||||
|
</abp-modal> |
||||
|
```` |
||||
|
|
||||
|
### button-alignment |
||||
|
|
||||
|
指定模态页脚按钮的位置. 应为以下值之一: |
||||
|
|
||||
|
* `Default` (默认值) |
||||
|
* `Start` |
||||
|
* `Center` |
||||
|
* `Around` |
||||
|
* `Between` |
||||
|
* `End` |
||||
@ -0,0 +1,55 @@ |
|||||
|
# 分页器 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-paginator` 是分页器的abp标签. 需要 `Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination.PagerModel` 类型的模型. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-paginator model="Model.PagerModel" show-info="true"></abp-paginator> |
||||
|
```` |
||||
|
|
||||
|
模型: |
||||
|
|
||||
|
````csharp |
||||
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components |
||||
|
{ |
||||
|
public class PaginatorModel : PageModel |
||||
|
{ |
||||
|
public PagerModel PagerModel { get; set; } |
||||
|
|
||||
|
public void OnGet(int currentPage, string sort) |
||||
|
{ |
||||
|
PagerModel = new PagerModel(100, 10, currentPage, 10, "Paginator", sort); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[分页器demo页面](https://bootstrap-taghelpers.abp.io/Components/Paginator)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### model |
||||
|
|
||||
|
`Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination.PagerModel` 类型模型可以用以下数据初始化: |
||||
|
|
||||
|
* `totalCount` |
||||
|
* `shownItemsCount` |
||||
|
* `currentPage` |
||||
|
* `pageSize` |
||||
|
* `pageUrl` |
||||
|
* `sort` (默认值为null) |
||||
|
|
||||
|
### show-info |
||||
|
|
||||
|
指定是否显示开始,结束和总记录的其他信息. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
@ -0,0 +1,68 @@ |
|||||
|
# 进度条 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-progress-bar` 是进度条状态的abp标签. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-progress-bar value="70" /> |
||||
|
|
||||
|
<abp-progress-bar type="Warning" value="25"> %25 </abp-progress-bar> |
||||
|
|
||||
|
<abp-progress-bar type="Success" value="40" strip="true"/> |
||||
|
|
||||
|
<abp-progress-bar type="Dark" value="10" min-value="5" max-value="15" strip="true"> %50 </abp-progress-bar> |
||||
|
|
||||
|
<abp-progress-group> |
||||
|
<abp-progress-part type="Success" value="25"/> |
||||
|
<abp-progress-part type="Danger" value="10" strip="true"> %10 </abp-progress-part> |
||||
|
<abp-progress-part type="Primary" value="50" animation="true" strip="true" /> |
||||
|
</abp-progress-group> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[进度条demo页面](https://bootstrap-taghelpers.abp.io/Components/Progress-Bars)查看示例. |
||||
|
|
||||
|
## Attributes |
||||
|
|
||||
|
### value |
||||
|
|
||||
|
指定当前进度条的进度. |
||||
|
|
||||
|
### type |
||||
|
|
||||
|
指定进度条的背景颜色. 应为下列值之一: |
||||
|
|
||||
|
* `Default` (默认值) |
||||
|
* `Secondary` |
||||
|
* `Success` |
||||
|
* `Danger` |
||||
|
* `Warning` |
||||
|
* `Info` |
||||
|
* `Light` |
||||
|
* `Dark` |
||||
|
|
||||
|
### min-value |
||||
|
|
||||
|
进度条的最小值. 默认值是0。 |
||||
|
|
||||
|
### max-value |
||||
|
|
||||
|
进度条的最大值. 默认值是100. |
||||
|
|
||||
|
### strip |
||||
|
|
||||
|
指定进度条的背景样式是否被去除. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
|
|
||||
|
### animation |
||||
|
|
||||
|
指定进度条的背景样式是否为动画. 应为以下值之一: |
||||
|
|
||||
|
* `false` (默认值) |
||||
|
* `true` |
||||
@ -0,0 +1,91 @@ |
|||||
|
# 标签页 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-tab` 是从引导标签元素派生的基本标签导航内容容器. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-tabs> |
||||
|
<abp-tab title="Home"> |
||||
|
Content_Home |
||||
|
</abp-tab> |
||||
|
<abp-tab-link title="Link" href="#" /> |
||||
|
<abp-tab title="profile"> |
||||
|
Content_Profile |
||||
|
</abp-tab> |
||||
|
<abp-tab-dropdown title="Contact" name="ContactDropdown"> |
||||
|
<abp-tab title="Contact 1" parent-dropdown-name="ContactDropdown"> |
||||
|
Content_1_Content |
||||
|
</abp-tab> |
||||
|
<abp-tab title="Contact 2" parent-dropdown-name="ContactDropdown"> |
||||
|
Content_2_Content |
||||
|
</abp-tab> |
||||
|
</abp-tab-dropdown> |
||||
|
</abp-tabs> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[标签页demo页面](https://bootstrap-taghelpers.abp.io/Components/Tabs)查看示例. |
||||
|
|
||||
|
## abp-tab Attributes |
||||
|
|
||||
|
- **title**: 设置标签页菜单文字. |
||||
|
- **name:** 设置生成元素的"id"属性. 默认值为Guid. 除非使用Jquery更改或修改了选项卡,否则不需要. |
||||
|
- **active**: 设置active标签页. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-tabs name="TabId"> |
||||
|
<abp-tab name="nav-home" title="Home"> |
||||
|
Content_Home |
||||
|
</abp-tab> |
||||
|
<abp-tab name="nav-profile" active="true" title="profile"> |
||||
|
Content_Profile |
||||
|
</abp-tab> |
||||
|
<abp-tab name="nav-contact" title="Contact"> |
||||
|
Content_Contact |
||||
|
</abp-tab> |
||||
|
</abp-tabs> |
||||
|
```` |
||||
|
|
||||
|
### Pills |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-tabs tab-style="Pill"> |
||||
|
<abp-tab title="Home"> |
||||
|
Content_Home |
||||
|
</abp-tab> |
||||
|
<abp-tab title="profile"> |
||||
|
Content_Profile |
||||
|
</abp-tab> |
||||
|
<abp-tab title="Contact"> |
||||
|
Content_Contact |
||||
|
</abp-tab> |
||||
|
</abp-tabs> |
||||
|
```` |
||||
|
|
||||
|
### Vertical |
||||
|
|
||||
|
**vertical-header-size**: 设置标签标题的列宽. |
||||
|
|
||||
|
示例: |
||||
|
|
||||
|
````xml |
||||
|
<abp-tabs tab-style="PillVertical" vertical-header-size="_2" > |
||||
|
<abp-tab active="true" title="Home"> |
||||
|
Content_Home |
||||
|
</abp-tab> |
||||
|
<abp-tab title="profile"> |
||||
|
Content_Profile |
||||
|
</abp-tab> |
||||
|
<abp-tab title="Contact"> |
||||
|
Content_Contact |
||||
|
</abp-tab> |
||||
|
</abp-tabs> |
||||
|
```` |
||||
@ -0,0 +1,33 @@ |
|||||
|
# 提示工具 |
||||
|
|
||||
|
## 介绍 |
||||
|
|
||||
|
`abp-tooltip` 是提示工具的abp标签. |
||||
|
|
||||
|
基本用法: |
||||
|
|
||||
|
````xml |
||||
|
<abp-button abp-tooltip="Tooltip"> |
||||
|
Tooltip Default |
||||
|
</abp-button> |
||||
|
|
||||
|
<abp-button abp-tooltip-top="Tooltip"> |
||||
|
Tooltip on top |
||||
|
</abp-button> |
||||
|
|
||||
|
<abp-button abp-tooltip-right="Tooltip"> |
||||
|
Tooltip on right |
||||
|
</abp-button> |
||||
|
|
||||
|
<abp-button abp-tooltip-bottom="Tooltip"> |
||||
|
Tooltip on bottom |
||||
|
</abp-button> |
||||
|
|
||||
|
<abp-button disabled="true" abp-tooltip="Tooltip"> |
||||
|
Disabled button Tooltip |
||||
|
</abp-button> |
||||
|
```` |
||||
|
|
||||
|
## Demo |
||||
|
|
||||
|
参阅[提示工具demo页面](https://bootstrap-taghelpers.abp.io/Components/Tooltips)查看示例. |
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,37 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace AutoMapper |
||||
|
{ |
||||
|
public static class AbpAutoMapperExtensibleDtoExtensions |
||||
|
{ |
||||
|
public static IMappingExpression<TSource, TDestination> MapExtraProperties<TSource, TDestination>( |
||||
|
this IMappingExpression<TSource, TDestination> mappingExpression, |
||||
|
MappingPropertyDefinitionChecks? definitionChecks = null) |
||||
|
where TDestination : IHasExtraProperties |
||||
|
where TSource : IHasExtraProperties |
||||
|
{ |
||||
|
return mappingExpression |
||||
|
.ForMember( |
||||
|
x => x.ExtraProperties, |
||||
|
y => y.MapFrom( |
||||
|
(source, destination, extraProps) => |
||||
|
{ |
||||
|
var result = extraProps.IsNullOrEmpty() |
||||
|
? new Dictionary<string, object>() |
||||
|
: new Dictionary<string, object>(extraProps); |
||||
|
|
||||
|
HasExtraPropertiesObjectExtendingExtensions |
||||
|
.MapExtraPropertiesTo<TSource, TDestination>( |
||||
|
source.ExtraProperties, |
||||
|
result, |
||||
|
definitionChecks |
||||
|
); |
||||
|
|
||||
|
return result; |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Text.RegularExpressions; |
||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Volo.Abp.Cli.ProjectBuilding.Files; |
||||
|
using Volo.Abp.Text; |
||||
|
|
||||
|
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps |
||||
|
{ |
||||
|
public class ConnectionStringChangeStep : ProjectBuildPipelineStep |
||||
|
{ |
||||
|
private const string DefaultConnectionStringKey = "Default"; |
||||
|
|
||||
|
public override void Execute(ProjectBuildContext context) |
||||
|
{ |
||||
|
var appSettingsJsonFiles = context.Files.Where(f => |
||||
|
f.Name.EndsWith("appsettings.json", StringComparison.OrdinalIgnoreCase)) |
||||
|
.ToArray(); |
||||
|
|
||||
|
if (!appSettingsJsonFiles.Any()) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var newConnectionString = $"\"{DefaultConnectionStringKey}\": \"{context.BuildArgs.ConnectionString}\""; |
||||
|
|
||||
|
foreach (var appSettingsJson in appSettingsJsonFiles) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var appSettingJsonContentWithoutBom = StringHelper.ConvertFromBytesWithoutBom(appSettingsJson.Bytes); |
||||
|
var jsonObject = JObject.Parse(appSettingJsonContentWithoutBom); |
||||
|
|
||||
|
var connectionStringContainer = (JContainer)jsonObject?["ConnectionStrings"]; |
||||
|
if (connectionStringContainer == null) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (!connectionStringContainer.Any()) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var connectionStrings = connectionStringContainer.ToList(); |
||||
|
|
||||
|
foreach (var connectionString in connectionStrings) |
||||
|
{ |
||||
|
var property = ((JProperty)connectionString); |
||||
|
var connectionStringName = property.Name; |
||||
|
|
||||
|
if (connectionStringName == DefaultConnectionStringKey) |
||||
|
{ |
||||
|
var defaultConnectionString = property.ToString(); |
||||
|
if (defaultConnectionString == null) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
appSettingsJson.ReplaceText(defaultConnectionString, newConnectionString); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Console.WriteLine("Cannot change the connection string in " + appSettingsJson.Name + ". Error: " + ex.Message); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace Volo.Abp.ExceptionHandling |
||||
|
{ |
||||
|
public class ExceptionNotificationContext |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The exception object.
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public Exception Exception { get; } |
||||
|
|
||||
|
public LogLevel LogLevel { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// True, if it is handled.
|
||||
|
/// </summary>
|
||||
|
public bool Handled { get; } |
||||
|
|
||||
|
public ExceptionNotificationContext( |
||||
|
[NotNull] Exception exception, |
||||
|
LogLevel? logLevel = null, |
||||
|
bool handled = true) |
||||
|
{ |
||||
|
Exception = Check.NotNull(exception, nameof(exception)); |
||||
|
LogLevel = logLevel ?? exception.GetLogLevel(); |
||||
|
Handled = handled; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.ExceptionHandling |
||||
|
{ |
||||
|
public class ExceptionNotifier : IExceptionNotifier, ITransientDependency |
||||
|
{ |
||||
|
public ILogger<ExceptionNotifier> Logger { get; set; } |
||||
|
|
||||
|
protected IEnumerable<IExceptionSubscriber> ExceptionSubscribers { get; } |
||||
|
|
||||
|
public ExceptionNotifier(IEnumerable<IExceptionSubscriber> exceptionSubscribers) |
||||
|
{ |
||||
|
ExceptionSubscribers = exceptionSubscribers; |
||||
|
Logger = NullLogger<ExceptionNotifier>.Instance; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task NotifyAsync([NotNull] ExceptionNotificationContext context) |
||||
|
{ |
||||
|
Check.NotNull(context, nameof(context)); |
||||
|
|
||||
|
foreach (var exceptionSubscriber in ExceptionSubscribers) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
await exceptionSubscriber.HandleAsync(context); |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
Logger.LogWarning($"Exception subscriber of type {exceptionSubscriber.GetType().AssemblyQualifiedName} has thrown an exception!"); |
||||
|
Logger.LogException(e, LogLevel.Warning); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace Volo.Abp.ExceptionHandling |
||||
|
{ |
||||
|
public static class ExceptionNotifierExtensions |
||||
|
{ |
||||
|
public static Task NotifyAsync( |
||||
|
[NotNull] this IExceptionNotifier exceptionNotifier, |
||||
|
[NotNull] Exception exception, |
||||
|
LogLevel? logLevel = null, |
||||
|
bool handled = true) |
||||
|
{ |
||||
|
Check.NotNull(exceptionNotifier, nameof(exceptionNotifier)); |
||||
|
|
||||
|
return exceptionNotifier.NotifyAsync( |
||||
|
new ExceptionNotificationContext( |
||||
|
exception, |
||||
|
logLevel, |
||||
|
handled |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.ExceptionHandling |
||||
|
{ |
||||
|
[ExposeServices(typeof(IExceptionSubscriber))] |
||||
|
public abstract class ExceptionSubscriber : IExceptionSubscriber, ITransientDependency |
||||
|
{ |
||||
|
public abstract Task HandleAsync(ExceptionNotificationContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.ExceptionHandling |
||||
|
{ |
||||
|
public interface IExceptionNotifier |
||||
|
{ |
||||
|
Task NotifyAsync([NotNull] ExceptionNotificationContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.ExceptionHandling |
||||
|
{ |
||||
|
public interface IExceptionSubscriber |
||||
|
{ |
||||
|
Task HandleAsync([NotNull] ExceptionNotificationContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System.Text; |
||||
|
|
||||
|
namespace Volo.Abp.Text |
||||
|
{ |
||||
|
public class StringHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Converts a byte[] to string without BOM (byte order mark).
|
||||
|
/// </summary>
|
||||
|
/// <param name="bytes">The byte[] to be converted to string</param>
|
||||
|
/// <param name="encoding">The encoding to get string. Default is UTF8</param>
|
||||
|
/// <returns></returns>
|
||||
|
public static string ConvertFromBytesWithoutBom(byte[] bytes, Encoding encoding = null) |
||||
|
{ |
||||
|
if (bytes == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (encoding == null) |
||||
|
{ |
||||
|
encoding = Encoding.UTF8; |
||||
|
} |
||||
|
|
||||
|
var hasBom = bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF; |
||||
|
|
||||
|
if (hasBom) |
||||
|
{ |
||||
|
return encoding.GetString(bytes, 3, bytes.Length - 3); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return encoding.GetString(bytes); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IAuditedObject"/> interface.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPrimaryKey">Type of primary key</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleAuditedEntityDto<TPrimaryKey> : ExtensibleCreationAuditedEntityDto<TPrimaryKey>, IAuditedObject |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public DateTime? LastModificationTime { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Guid? LastModifierId { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IAuditedObject"/> interface.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleAuditedEntityDto : ExtensibleCreationAuditedEntityDto, IAuditedObject |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public DateTime? LastModificationTime { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Guid? LastModifierId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IAuditedObject"/> interface.
|
||||
|
/// It has the <see cref="Creator"/> and <see cref="LastModifier"/> objects as a DTOs represent the related user.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPrimaryKey">Type of primary key</typeparam>
|
||||
|
/// <typeparam name="TUserDto">Type of the User DTO</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleAuditedEntityWithUserDto<TPrimaryKey, TUserDto> : ExtensibleAuditedEntityDto<TPrimaryKey>, IAuditedObject<TUserDto> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto Creator { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto LastModifier { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IAuditedObject"/> interface.
|
||||
|
/// It has the <see cref="Creator"/> and <see cref="LastModifier"/> objects as a DTOs represent the related user.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TUserDto">Type of the User DTO</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleAuditedEntityWithUserDto<TUserDto> : ExtensibleAuditedEntityDto, |
||||
|
IAuditedObject<TUserDto> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto Creator { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto LastModifier { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="ICreationAuditedObject"/> interface.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPrimaryKey">Type of primary key</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleCreationAuditedEntityDto<TPrimaryKey> : ExtensibleEntityDto<TPrimaryKey>, ICreationAuditedObject |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Guid? CreatorId { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="ICreationAuditedObject"/> interface.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleCreationAuditedEntityDto : ExtensibleEntityDto, ICreationAuditedObject |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public DateTime CreationTime { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Guid? CreatorId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="ICreationAuditedObject{TCreator}"/> interface.
|
||||
|
/// It has the <see cref="Creator"/> object as a DTO represents the user.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPrimaryKey">Type of primary key</typeparam>
|
||||
|
/// <typeparam name="TUserDto">Type of the User DTO</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleCreationAuditedEntityWithUserDto<TPrimaryKey, TUserDto> : ExtensibleCreationAuditedEntityDto<TPrimaryKey>, ICreationAuditedObject<TUserDto> |
||||
|
{ |
||||
|
public TUserDto Creator { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="ICreationAuditedObject{TCreator}"/> interface.
|
||||
|
/// It has the <see cref="Creator"/> object as a DTO represents the user.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TUserDto">Type of the User DTO</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleCreationAuditedEntityWithUserDto<TUserDto> : ExtensibleCreationAuditedEntityDto, |
||||
|
ICreationAuditedObject<TUserDto> |
||||
|
{ |
||||
|
public TUserDto Creator { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleEntityDto<TKey> : ExtensibleObject, IEntityDto<TKey> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Id of the entity.
|
||||
|
/// </summary>
|
||||
|
public TKey Id { get; set; } |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return $"[DTO: {GetType().Name}] Id = {Id}"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleEntityDto : ExtensibleObject, IEntityDto |
||||
|
{ |
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return $"[DTO: {GetType().Name}]"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IFullAuditedObject"/> interface.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPrimaryKey">Type of primary key</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleFullAuditedEntityDto<TPrimaryKey> : ExtensibleAuditedEntityDto<TPrimaryKey>, IFullAuditedObject |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public bool IsDeleted { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Guid? DeleterId { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public DateTime? DeletionTime { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IFullAuditedObject"/> interface.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleFullAuditedEntityDto : ExtensibleAuditedEntityDto, IFullAuditedObject |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public bool IsDeleted { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public Guid? DeleterId { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public DateTime? DeletionTime { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.Application.Dtos |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IFullAuditedObject{TUser}"/> interface.
|
||||
|
/// It has the <see cref="Creator"/>, <see cref="LastModifier"/> and <see cref="Deleter"/> objects as a DTOs represent the related user.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPrimaryKey">Type of primary key</typeparam>
|
||||
|
/// <typeparam name="TUserDto">Type of the User</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleFullAuditedEntityWithUserDto<TPrimaryKey, TUserDto> : ExtensibleFullAuditedEntityDto<TPrimaryKey>, IFullAuditedObject<TUserDto> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto Creator { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto LastModifier { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto Deleter { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class can be inherited by DTO classes to implement <see cref="IFullAuditedObject{TUser}"/> interface.
|
||||
|
/// It has the <see cref="Creator"/>, <see cref="LastModifier"/> and <see cref="Deleter"/> objects as a DTOs represent the related user.
|
||||
|
/// It also implements the <see cref="IHasExtraProperties"/> interface.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TUserDto">Type of the User</typeparam>
|
||||
|
[Serializable] |
||||
|
public abstract class ExtensibleFullAuditedEntityWithUserDto<TUserDto> : ExtensibleFullAuditedEntityDto, |
||||
|
IFullAuditedObject<TUserDto> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto Creator { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto LastModifier { get; set; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public TUserDto Deleter { get; set; } |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue