mirror of https://github.com/abpframework/abp.git
38 changed files with 1275 additions and 1113 deletions
@ -0,0 +1,140 @@ |
|||
# 自动API控制器 |
|||
|
|||
创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做. |
|||
|
|||
ABP可以按照惯例 **自动** 将你的应用程序服务配置为API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义. |
|||
|
|||
## 配置 |
|||
|
|||
基本配置很简单. 只需配置`AbpAspNetCoreMvcOptions`并使用`ConventionalControllers.Create`方法,如下所示: |
|||
|
|||
````csharp |
|||
[DependsOn(BookStoreApplicationModule)] |
|||
public class BookStoreWebModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options |
|||
.ConventionalControllers |
|||
.Create(typeof(BookStoreApplicationModule).Assembly); |
|||
}); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
此示例代码配置包含类`BookStoreApplicationModule`的程序集中的所有应用程序服务.下图显示了[Swagger UI](https://swagger.io/tools/swagger-ui/)上的API内容. |
|||
|
|||
 |
|||
|
|||
### 例子 |
|||
|
|||
一些示例方法名称和按约定生成的相应路由: |
|||
|
|||
| 服务方法名称 | HTTP Method | 路由 | |
|||
| ----------------------------------------------------- | ----------- | -------------------------- | |
|||
| GetAsync(Guid id) | GET | /api/app/book/{id} | |
|||
| GetListAsync() | GET | /api/app/book | |
|||
| CreateAsync(CreateBookDto input) | POST | /api/app/book | |
|||
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} | |
|||
| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} | |
|||
| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors | |
|||
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor | |
|||
|
|||
### HTTP Method |
|||
|
|||
ABP在确定服务方法的HTTP Method时使用命名约定: |
|||
|
|||
- **Get**: 如果方法名称以`GetList`,`GetAll`或`Get`开头. |
|||
- **Put**: 如果方法名称以`Put`或`Update`开头. |
|||
- **Delete**: 如果方法名称以`Delete`或`Remove`开头. |
|||
- **Post**: 如果方法名称以`Create`,`Add`,`Insert`或`Post`开头. |
|||
- **Patch**: 如果方法名称以`Patch`开头. |
|||
- 其他情况, **Post** 为 **默认方式**. |
|||
|
|||
如果需要为特定方法自定义HTTP Method, 则可以使用标准ASP.NET Core的属性([HttpPost], [HttpGet], [HttpPut]... 等等.). 这需要添加[Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core)的Nuget包. |
|||
|
|||
### 路由 |
|||
|
|||
路由根据一些惯例生成: |
|||
|
|||
* 它始终以 **/api**开头. |
|||
* 接着是**路由路径**. 默认值为"**/app**", 可以进行如下配置: |
|||
|
|||
````csharp |
|||
Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options.ConventionalControllers |
|||
.Create(typeof(BookStoreApplicationModule).Assembly, opts => |
|||
{ |
|||
opts.RootPath = "volosoft/book-store"; |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
然后获得一本书的路由将是'**/api/volosoft/book-store/book/{id}**'. 此示例使用两级根路径,但通常使用单个级别的深度. |
|||
|
|||
* 接着 **标准化控制器/服务名称**. 会删除`AppService`,`ApplicationService`和`Service`的后缀并将其转换为 **camelCase**. 如果你的应用程序服务类名称为`BookAppService`.那么它将变为`/book`. |
|||
* 如果要自定义命名, 则设置`UrlControllerNameNormalizer`选项. 它是一个委托允许你自定义每个控制器/服务的名称. |
|||
* 如果该方法具有 '**id**'参数, 则会在路由中添加'**/{id}**'. |
|||
* 如有必要,它会添加操作名称. 操作名称从服务上的方法名称获取并标准化; |
|||
* 删除'**Async**'后缀. 如果方法名称为'GetPhonesAsync',则变为`GetPhones`. |
|||
* 删除**HTTP method前缀**. 基于的HTTP method删除`GetList`,`GetAll`,`Get`,`Put`,`Update`,`Delete`,`Remove`,`Create`,`Add`,`Insert`,`Post`和`Patch`前缀, 因此`GetPhones`变为`Phones`, 因为`Get`前缀和GET请求重复. |
|||
* 将结果转换为**camelCase**. |
|||
* 如果生成的操作名称为**空**,则它不会添加到路径中.否则它会被添加到路由中(例如'/phones').对于`GetAllAsync`方法名称,它将为空,因为`GetPhonesAsync`方法名称将为`phone`. |
|||
* 可以通过设置`UrlActionNameNormalizer`选项来自定义.It's an action delegate that is called for every method. |
|||
* 如果有另一个带有'Id'后缀的参数,那么它也会作为最终路线段添加到路线中(例如'/phoneId'). |
|||
|
|||
## 服务选择 |
|||
|
|||
创建的HTTP API控制器并不是应用服务所独有的功能. |
|||
|
|||
### IRemoteService 接口 |
|||
|
|||
如果一个类实现了`IRemoteService`接口, 那么它会被自动选择为API控制器. 由于应用程序服务本身实现了`IRemoteService`接口, 因此它自然就成为API控制器. |
|||
|
|||
### RemoteService Attribute |
|||
|
|||
`RemoteService`可用于将实现`IRemoteService`接口的类标记为远程服务或禁用它. 例如: |
|||
|
|||
````csharp |
|||
[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)] |
|||
public class PersonAppService : ApplicationService |
|||
{ |
|||
|
|||
} |
|||
```` |
|||
|
|||
### TypePredicate 选项 |
|||
|
|||
你可以通过提供`TypePedicate`选项进一步过滤类以成为API控制器: |
|||
|
|||
````csharp |
|||
services.Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options.ConventionalControllers |
|||
.Create(typeof(BookStoreApplicationModule).Assembly, opts => |
|||
{ |
|||
opts.TypePredicate = type => { return true; }; |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
如果你不想将此类型公开为API控制器, 则可以在类型检查时返回`false`. |
|||
|
|||
## API Explorer |
|||
|
|||
API Explorer是可以由客户端获取API结构的服务. Swagger使用它为endpoint创建文档和test UI. |
|||
|
|||
默认情况下, HTTP API控制器会自动启用API Explorer, 可以使用`RemoteService`按类或方法的级别控制它. 例如: |
|||
|
|||
````csharp |
|||
[RemoteService(IsMetadataEnabled = false)] |
|||
public class PersonAppService : ApplicationService |
|||
{ |
|||
|
|||
} |
|||
```` |
|||
|
|||
禁用`IsMetadataEnabled`从而从API Explorer中隐藏此服务, 并且无法被发现. 但是它仍然可以被知道确切API路径/路由的客户端使用. |
|||
@ -0,0 +1,165 @@ |
|||
# 动态 C# API 客户端 |
|||
|
|||
ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 `HttpClient` 或者其他低级的HTTP功能调用远程服务并获取数据. |
|||
|
|||
## 服务接口 |
|||
|
|||
你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如: |
|||
|
|||
````csharp |
|||
public interface IBookAppService : IApplicationService |
|||
{ |
|||
Task<List<BookDto>> GetListAsync(); |
|||
} |
|||
```` |
|||
|
|||
为了能自动被发现,你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookAppService`完全满足这个条件. |
|||
|
|||
在你的服务中实现这个类,你可以使用[auto API controller system](Auto-API-Controllers.md)将你的服务暴漏为一个REST API 端点. |
|||
|
|||
## 客户端代理生成 |
|||
|
|||
首先,将[Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget包添加到你的客户端项目中: |
|||
|
|||
```` |
|||
Install-Package Volo.Abp.Http.Client |
|||
```` |
|||
|
|||
然后给你的模块添加`AbpHttpClientModule`依赖: |
|||
|
|||
````csharp |
|||
[DependsOn(typeof(AbpHttpClientModule))] //添加依赖 |
|||
public class MyClientAppModule : AbpModule |
|||
{ |
|||
} |
|||
```` |
|||
|
|||
现在,已经可以创建客户端代理了.例如: |
|||
|
|||
````csharp |
|||
[DependsOn( |
|||
typeof(AbpHttpClientModule), //用来创建客户端代理 |
|||
typeof(BookStoreApplicationModule) //包含应用服务接口 |
|||
)] |
|||
public class MyClientAppModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
//创建动态客户端代理 |
|||
context.Services.AddHttpClientProxies( |
|||
typeof(BookStoreApplicationModule).Assembly |
|||
); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
`AddHttpClientproxies`方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类. |
|||
|
|||
### Endpoint配置 |
|||
|
|||
`appsettings.json`文件中的`RemoteServices`节点被用来设置默认的服务地址.下面是最简单的配置: |
|||
|
|||
```` |
|||
{ |
|||
"RemoteServices": { |
|||
"Default": { |
|||
"BaseUrl": "http://localhost:53929/" |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
查看下面的"RemoteServiceOptions"章节获取更多详细配置. |
|||
|
|||
## 使用 |
|||
|
|||
可以很直接地使用.只需要在你的客户端程序中注入服务接口: |
|||
|
|||
````csharp |
|||
public class MyService : ITransientDependency |
|||
{ |
|||
private readonly IBookAppService _bookService; |
|||
|
|||
public MyService(IBookAppService bookService) |
|||
{ |
|||
_bookService = bookService; |
|||
} |
|||
|
|||
public async Task DoIt() |
|||
{ |
|||
var books = await _bookService.GetListAsync(); |
|||
foreach (var book in books) |
|||
{ |
|||
Console.WriteLine($"[BOOK {book.Id}] Name={book.Name}"); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
本例注入了上面定义的`IBookAppService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用. |
|||
|
|||
### IHttpClientProxy接口 |
|||
|
|||
你可以像上面那样注入`IBookAppService`来使用客户端代理,也可以注入`IHttpClientProxy<IBookAppService>`获取更多明确的用法.这种情况下你可以使用`IHttpClientProxy<T>`接口的`Service`属性. |
|||
|
|||
## 配置 |
|||
|
|||
### RemoteServiceOptions |
|||
|
|||
默认情况下`AbpRemoteServiceOptions`从`appsettings.json`获取.或者,你可以使用`Configure`方法来设置或重写它.如: |
|||
|
|||
````csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.Configure<AbpRemoteServiceOptions>(options => |
|||
{ |
|||
options.RemoteServices.Default = |
|||
new RemoteServiceConfiguration("http://localhost:53929/"); |
|||
}); |
|||
|
|||
//... |
|||
} |
|||
```` |
|||
|
|||
### 多个远程服务端点 |
|||
|
|||
上面的例子已经配置了"Default"远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点: |
|||
|
|||
````json |
|||
{ |
|||
"RemoteServices": { |
|||
"Default": { |
|||
"BaseUrl": "http://localhost:53929/" |
|||
}, |
|||
"BookStore": { |
|||
"BaseUrl": "http://localhost:48392/" |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
`AddHttpClientProxies`方法有一个可选的参数来定义远程服务的名字: |
|||
|
|||
````csharp |
|||
context.Services.AddHttpClientProxies( |
|||
typeof(BookStoreApplicationModule).Assembly, |
|||
remoteServiceName: "BookStore" |
|||
); |
|||
```` |
|||
|
|||
`remoteServiceName`参数会匹配通过`AbpRemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点. |
|||
|
|||
### 作为默认服务 |
|||
|
|||
当你为`IBookAppService`创建了一个服务代理,你可以直接注入`IBookAppService`来使用代理客户端(像上面章节中将的那样).你可以传递`asDefaultService:false`到`AddHttpClientProxies`方法来禁用此功能. |
|||
|
|||
````csharp |
|||
context.Services.AddHttpClientProxies( |
|||
typeof(BookStoreApplicationModule).Assembly, |
|||
asDefaultServices: false |
|||
); |
|||
```` |
|||
|
|||
如果你的程序中已经有一个服务的实现并且你不想用你的客户端代理重写或替换其他的实现,就需要使用`asDefaultServices:false` |
|||
|
|||
> 如果你禁用了`asDefaultService`,你只能使用`IHttpClientProxy<T>`接口去使用客户端代理.(参见上面的相关章节). |
|||
@ -0,0 +1,3 @@ |
|||
# abp.auth JavaScript API |
|||
|
|||
TODO |
|||
@ -0,0 +1,23 @@ |
|||
# JavaScript API |
|||
|
|||
ABP为ASP.NET Core MVC / Razor页面应用程序提供了一些执行客户端常见需求的JavaScrpt Api. |
|||
|
|||
## APIs |
|||
|
|||
* abp.ajax |
|||
* [abp.auth](Auth.md) |
|||
* abp.currentUser |
|||
* abp.dom |
|||
* abp.event |
|||
* abp.features |
|||
* abp.localization |
|||
* abp.log |
|||
* abp.ModalManager |
|||
* abp.notify |
|||
* abp.security |
|||
* abp.setting |
|||
* abp.ui |
|||
* abp.utils |
|||
* abp.ResourceLoader |
|||
* abp.WidgetManager |
|||
* Other APIs |
|||
@ -1,140 +1,3 @@ |
|||
# 自动API控制器 |
|||
文档已经移动到其他位置. |
|||
|
|||
创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做. |
|||
|
|||
ABP可以按照惯例 **自动** 将你的应用程序服务配置为API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义. |
|||
|
|||
## 配置 |
|||
|
|||
基本配置很简单. 只需配置`AbpAspNetCoreMvcOptions`并使用`ConventionalControllers.Create`方法,如下所示: |
|||
|
|||
````csharp |
|||
[DependsOn(BookStoreApplicationModule)] |
|||
public class BookStoreWebModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options |
|||
.ConventionalControllers |
|||
.Create(typeof(BookStoreApplicationModule).Assembly); |
|||
}); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
此示例代码配置包含类`BookStoreApplicationModule`的程序集中的所有应用程序服务.下图显示了[Swagger UI](https://swagger.io/tools/swagger-ui/)上的API内容. |
|||
|
|||
 |
|||
|
|||
### 例子 |
|||
|
|||
一些示例方法名称和按约定生成的相应路由: |
|||
|
|||
| 服务方法名称 | HTTP Method | 路由 | |
|||
| ----------------------------------------------------- | ----------- | -------------------------- | |
|||
| GetAsync(Guid id) | GET | /api/app/book/{id} | |
|||
| GetListAsync() | GET | /api/app/book | |
|||
| CreateAsync(CreateBookDto input) | POST | /api/app/book | |
|||
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} | |
|||
| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} | |
|||
| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors | |
|||
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor | |
|||
|
|||
### HTTP Method |
|||
|
|||
ABP在确定服务方法的HTTP Method时使用命名约定: |
|||
|
|||
- **Get**: 如果方法名称以`GetList`,`GetAll`或`Get`开头. |
|||
- **Put**: 如果方法名称以`Put`或`Update`开头. |
|||
- **Delete**: 如果方法名称以`Delete`或`Remove`开头. |
|||
- **Post**: 如果方法名称以`Create`,`Add`,`Insert`或`Post`开头. |
|||
- **Patch**: 如果方法名称以`Patch`开头. |
|||
- 其他情况, **Post** 为 **默认方式**. |
|||
|
|||
如果需要为特定方法自定义HTTP Method, 则可以使用标准ASP.NET Core的属性([HttpPost], [HttpGet], [HttpPut]... 等等.). 这需要添加[Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core)的Nuget包. |
|||
|
|||
### 路由 |
|||
|
|||
路由根据一些惯例生成: |
|||
|
|||
* 它始终以 **/api**开头. |
|||
* 接着是**路由路径**. 默认值为"**/app**", 可以进行如下配置: |
|||
|
|||
````csharp |
|||
Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options.ConventionalControllers |
|||
.Create(typeof(BookStoreApplicationModule).Assembly, opts => |
|||
{ |
|||
opts.RootPath = "volosoft/book-store"; |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
然后获得一本书的路由将是'**/api/volosoft/book-store/book/{id}**'. 此示例使用两级根路径,但通常使用单个级别的深度. |
|||
|
|||
* 接着 **标准化控制器/服务名称**. 会删除`AppService`,`ApplicationService`和`Service`的后缀并将其转换为 **camelCase**. 如果你的应用程序服务类名称为`BookAppService`.那么它将变为`/book`. |
|||
* 如果要自定义命名, 则设置`UrlControllerNameNormalizer`选项. 它是一个委托允许你自定义每个控制器/服务的名称. |
|||
* 如果该方法具有 '**id**'参数, 则会在路由中添加'**/{id}**'. |
|||
* 如有必要,它会添加操作名称. 操作名称从服务上的方法名称获取并标准化; |
|||
* 删除'**Async**'后缀. 如果方法名称为'GetPhonesAsync',则变为`GetPhones`. |
|||
* 删除**HTTP method前缀**. 基于的HTTP method删除`GetList`,`GetAll`,`Get`,`Put`,`Update`,`Delete`,`Remove`,`Create`,`Add`,`Insert`,`Post`和`Patch`前缀, 因此`GetPhones`变为`Phones`, 因为`Get`前缀和GET请求重复. |
|||
* 将结果转换为**camelCase**. |
|||
* 如果生成的操作名称为**空**,则它不会添加到路径中.否则它会被添加到路由中(例如'/phones').对于`GetAllAsync`方法名称,它将为空,因为`GetPhonesAsync`方法名称将为`phone`. |
|||
* 可以通过设置`UrlActionNameNormalizer`选项来自定义.It's an action delegate that is called for every method. |
|||
* 如果有另一个带有'Id'后缀的参数,那么它也会作为最终路线段添加到路线中(例如'/phoneId'). |
|||
|
|||
## 服务选择 |
|||
|
|||
创建的HTTP API控制器并不是应用服务所独有的功能. |
|||
|
|||
### IRemoteService 接口 |
|||
|
|||
如果一个类实现了`IRemoteService`接口, 那么它会被自动选择为API控制器. 由于应用程序服务本身实现了`IRemoteService`接口, 因此它自然就成为API控制器. |
|||
|
|||
### RemoteService Attribute |
|||
|
|||
`RemoteService`可用于将实现`IRemoteService`接口的类标记为远程服务或禁用它. 例如: |
|||
|
|||
````csharp |
|||
[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)] |
|||
public class PersonAppService : ApplicationService |
|||
{ |
|||
|
|||
} |
|||
```` |
|||
|
|||
### TypePredicate 选项 |
|||
|
|||
你可以通过提供`TypePedicate`选项进一步过滤类以成为API控制器: |
|||
|
|||
````csharp |
|||
services.Configure<AbpAspNetCoreMvcOptions>(options => |
|||
{ |
|||
options.ConventionalControllers |
|||
.Create(typeof(BookStoreApplicationModule).Assembly, opts => |
|||
{ |
|||
opts.TypePredicate = type => { return true; }; |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
如果你不想将此类型公开为API控制器, 则可以在类型检查时返回`false`. |
|||
|
|||
## API Explorer |
|||
|
|||
API Explorer是可以由客户端获取API结构的服务. Swagger使用它为endpoint创建文档和test UI. |
|||
|
|||
默认情况下, HTTP API控制器会自动启用API Explorer, 可以使用`RemoteService`按类或方法的级别控制它. 例如: |
|||
|
|||
````csharp |
|||
[RemoteService(IsMetadataEnabled = false)] |
|||
public class PersonAppService : ApplicationService |
|||
{ |
|||
|
|||
} |
|||
```` |
|||
|
|||
禁用`IsMetadataEnabled`从而从API Explorer中隐藏此服务, 并且无法被发现. 但是它仍然可以被知道确切API路径/路由的客户端使用. |
|||
[点击链接跳转到自动API控制器文档](../API/Auto-API-Controllers.md) |
|||
@ -1,354 +1,3 @@ |
|||
文档已经移动到其他位置. |
|||
|
|||
## ASP.NET Core MVC 捆绑 & 压缩 |
|||
|
|||
有许多方法可以捆绑&压缩客户端资源(JavaScript和CSS文件). 最常见的方式是: |
|||
|
|||
* 使用Visual Studio[捆绑&压缩](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier)扩展或者其它的[NuGet相关包](https://www.nuget.org/packages/BuildBundlerMinifier/). |
|||
|
|||
* 使用[Gulp](https://gulpjs.com/)/[Grunt](https://gruntjs.com/)及其插件. |
|||
|
|||
ABP内置了简单,动态,强大,模块化的方式. |
|||
|
|||
### Volo.Abp.AspNetCore.Mvc.UI.Bundling 包 |
|||
|
|||
> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它. |
|||
|
|||
将`Volo.Abp.AspNetCore.Mvc.UI.Bundling` nuget包安装到你的项目中: |
|||
|
|||
```` |
|||
install-package Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
```` |
|||
|
|||
然后将`AbpAspNetCoreMvcUiBundlingModule`依赖项添加到你的模块上: |
|||
|
|||
````C# |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace MyCompany.MyProject |
|||
{ |
|||
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))] |
|||
public class MyWebModule : AbpModule |
|||
{ |
|||
//... |
|||
} |
|||
} |
|||
```` |
|||
|
|||
### Razor Bundling Tag Helpers |
|||
|
|||
创建bundle的最简单方法是使用`abp-script-bundle`或`abp-style-bundle` tag helpers. 例如: |
|||
|
|||
````html |
|||
<abp-style-bundle name="MyGlobalBundle"> |
|||
<abp-style src="/libs/bootstrap/css/bootstrap.css" /> |
|||
<abp-style src="/libs/font-awesome/css/font-awesome.css" /> |
|||
<abp-style src="/libs/toastr/toastr.css" /> |
|||
<abp-style src="/styles/my-global-style.css" /> |
|||
</abp-style-bundle> |
|||
```` |
|||
|
|||
`abp-script-bundle`定义了一个带有**唯一名称**的样式包:`MyGlobalBundle`. 使用方法很容易理解. 让我们看看它是如何*工作的*: |
|||
|
|||
* 当首次请求时,ABP从提供的文件中 **(延迟)lazy** 创建. 后续将从 **缓存** 中返回内容. 这意味着如果你有条件地将文件添加到包中,它只执行一次, 并且条件的任何更改都不会影响下一个请求的包. |
|||
* 在`development`环境中ABP会将包文件**单独**添加到页面中, 其他环境(`staging`,`production`...)会自动捆绑和压缩. |
|||
* 捆绑文件可以是**物理**文件或[**虚拟/嵌入**](../Virtual-File-System.md)的文件. |
|||
* ABP自动将 **版本查询字符串(version query string)** 添加到捆绑文件的URL中,以防止浏览器缓存. 如:?_v=67872834243042(从文件的上次更改日期生成). 即使捆绑文件单独添加到页面(在`development`环境中), 版本控制仍然有效. |
|||
|
|||
#### 导入 Bundling Tag Helpers |
|||
|
|||
> 默认情况下已在启动模板导入. 大多数情况下,你不需要手动安装它. |
|||
|
|||
要使用`bundle tag helpers`, 你需要将其添加到`_ViewImports.cshtml`文件或页面中: |
|||
|
|||
```` |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
```` |
|||
|
|||
#### 未命名的 Bundles |
|||
|
|||
对于razor bundle tag helpers, `name`是**可选**. 如果没有定义一个名字,它将根据使用的捆绑文件名自动**计算生成**(they are **concatenated** and **hashed**) 例: |
|||
|
|||
````html |
|||
<abp-style-bundle> |
|||
<abp-style src="/libs/bootstrap/css/bootstrap.css" /> |
|||
<abp-style src="/libs/font-awesome/css/font-awesome.css" /> |
|||
<abp-style src="/libs/toastr/toastr.css" /> |
|||
@if (ViewBag.IncludeCustomStyles != false) |
|||
{ |
|||
<abp-style src="/styles/my-global-style.css" /> |
|||
} |
|||
</abp-style-bundle> |
|||
```` |
|||
|
|||
这将潜在地创建**两个不同的bundles**(一个包括`my-global-style.css`而另一个则不包括). |
|||
|
|||
**未命名的** bundles优点: |
|||
|
|||
* 可以**有条件地将项目**添加到捆绑包中. 但这可能会导致基于条件的捆绑的存在多种变化. |
|||
|
|||
**命名** bundles优点: |
|||
|
|||
* 其他模块可以通过其名称为捆绑包做出贡献(参见下面的部分). |
|||
|
|||
#### 单个文件 |
|||
|
|||
如果你只需要在页面中添加一个文件, 你可以使用`abp-script`或`abp-style`而不需要包含在`abp-script-bundle`或`abp-style-bundle`中. 例: |
|||
|
|||
````xml |
|||
<abp-script src="/scripts/my-script.js" /> |
|||
```` |
|||
|
|||
对于上面的示例,包名称将是 *scripts.my-scripts*("/"替换为"."). 所有捆绑功能也可以按预期应用于单个文件. |
|||
|
|||
### Bundling 选项 |
|||
|
|||
如果你需要在 **多个页面中使用相同的包** 或想要使用更多 **强大功能**, 你可以在[模块](../Module-Development-Basics.md)类中进行**配置**. |
|||
|
|||
#### 创建一个新的捆绑包 |
|||
|
|||
用法示例: |
|||
|
|||
````C# |
|||
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))] |
|||
public class MyWebModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.ScriptBundles |
|||
.Add("MyGlobalBundle", bundle => { |
|||
bundle.AddFiles( |
|||
"/libs/jquery/jquery.js", |
|||
"/libs/bootstrap/js/bootstrap.js", |
|||
"/libs/toastr/toastr.min.js", |
|||
"/scripts/my-global-scripts.js" |
|||
); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
> 你可以在脚本和样式包中使用相同的名称(*MyGlobalBundle*), 因为它们被添加到不同的集合(`ScriptBundles`和`StyleBundles`). |
|||
|
|||
在定义bundle之后, 可以使用上面定义的相同tag helpers将其包括在页面中. 例如: |
|||
|
|||
````html |
|||
<abp-script-bundle name="MyGlobalBundle" /> |
|||
```` |
|||
|
|||
这次tag helper定义中没有定义文件, 因为捆绑文件是由代码定义的. |
|||
|
|||
#### 配置现有的 Bundle |
|||
|
|||
ABP也支持[模块化](../Module-Development-Basics.md)捆绑. 模块可以修改由依赖模块创建的捆绑包. |
|||
例如: |
|||
|
|||
````C# |
|||
[DependsOn(typeof(MyWebModule))] |
|||
public class MyWebExtensionModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.ScriptBundles |
|||
.Configure("MyGlobalBundle", bundle => { |
|||
bundle.AddFiles( |
|||
"/scripts/my-extension-script.js" |
|||
); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
> 无法通过代码配置未命名的bundle tag helpers, 因为它们的名称在开发时是未知的. 建议始终使用bundle tag helper的名称. |
|||
|
|||
### Bundle 贡献者 |
|||
|
|||
将文件添加到现有bundle似乎很有用. 如果你需要**替换**bundle中的文件或者你想**有条件地**添加文件怎么办? 定义bundle贡献者可为此类情况提供额外的功能. |
|||
|
|||
一个bundle的贡献者使用自定义版本bootstrap.css替换示例: |
|||
|
|||
````C# |
|||
public class MyExtensionGlobalStyleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.ReplaceOne( |
|||
"/libs/bootstrap/css/bootstrap.css", |
|||
"/styles/extensions/bootstrap-customized.css" |
|||
); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
然后你可以按照下面的代码使用这个贡献者: |
|||
|
|||
````C# |
|||
services.Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.ScriptBundles |
|||
.Configure("MyGlobalBundle", bundle => { |
|||
bundle.AddContributors(typeof(MyExtensionGlobalStyleContributor)); |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
贡献者也可以在bundle tag helpers中使用. |
|||
例如: |
|||
|
|||
````xml |
|||
<abp-style-bundle> |
|||
<abp-style type="@typeof(BootstrapStyleContributor)" /> |
|||
<abp-style src="/libs/font-awesome/css/font-awesome.css" /> |
|||
<abp-style src="/libs/toastr/toastr.css" /> |
|||
</abp-style-bundle> |
|||
```` |
|||
|
|||
`abp-style`和`abp-script`标签可以使用`type`属性(而不是`src`属性), 如本示例所示. 添加bundle贡献者时, 其依赖关系也会自动添加到bundle中. |
|||
|
|||
#### 贡献者依赖关系 |
|||
|
|||
bundle贡献者可以与其他贡献者具有一个或多个依赖关系. |
|||
例如: |
|||
|
|||
````C# |
|||
[DependsOn(typeof(MyDependedBundleContributor))] //Define the dependency |
|||
public class MyExtensionStyleBundleContributor : BundleContributor |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
添加bundle贡献者时,其依赖关系将 **自动并递归** 添加. **依赖顺序** 通过阻止 **重复** 添加的依赖关系. 即使它们处于分离的bundle中,也会阻止重复. ABP在页面中组织所有bundle并消除重复. |
|||
|
|||
创建贡献者和定义依赖关系是一种跨不同模块组织bundle创建的方法. |
|||
|
|||
|
|||
#### 贡献者扩展 |
|||
|
|||
在某些高级应用场景中, 当用到一个bundle贡献者时,你可能想做一些额外的配置. 贡献者扩展可以和被扩展的贡献者无缝衔接. |
|||
|
|||
下面的示例为 prism.js 脚本库添加一些样式: |
|||
|
|||
````csharp |
|||
public class MyPrismjsStyleExtension : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/prismjs/plugins/toolbar/prism-toolbar.css"); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
然后你可以配置 `BundleContributorOptions` 去扩展已存在的 `PrismjsStyleBundleContributor`. |
|||
|
|||
````csharp |
|||
Configure<BundleContributorOptions>(options => |
|||
{ |
|||
options |
|||
.Extensions<PrismjsStyleBundleContributor>() |
|||
.Add<MyPrismjsStyleExtension>(); |
|||
}); |
|||
```` |
|||
|
|||
任何时候当 `PrismjsStyleBundleContributor` 被添加到bundle中时, `MyPrismjsStyleExtension` 也会被自动添加. |
|||
|
|||
#### 访问 IServiceProvider |
|||
|
|||
虽然很少需要它, 但是`BundleConfigurationContext`有一个`ServiceProvider`属性, 你可以在`ConfigureBundle`方法中解析服务依赖. |
|||
|
|||
#### 标准包装贡献者 |
|||
|
|||
将特定的NPM包资源(js,css文件)添加到包中对于该包非常简单. 例如, 你总是为bootstrap NPM包添加`bootstrap.css`文件. |
|||
|
|||
所有[标准NPM包](Client-Side-Package-Management.md)都有内置的贡献者. 例如,如果你的贡献者依赖于bootstrap,你可以声明它,而不是自己添加bootstrap.css. |
|||
|
|||
````C# |
|||
[DependsOn(typeof(BootstrapStyleContributor))] //Define the bootstrap style dependency |
|||
public class MyExtensionStyleBundleContributor : BundleContributor |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
使用标准包的内置贡献者: |
|||
|
|||
* 防止你输入**无效的资源路径**. |
|||
* 如果资源 **路径发生变化** (依赖贡献者将处理它),则防止更改你的贡献者. |
|||
* 防止多个模块添加**重复文件**. |
|||
* 以递归方式管理依赖项(如果需要,添加依赖项的依赖项). |
|||
|
|||
##### Volo.Abp.AspNetCore.Mvc.UI.Packages 包 |
|||
|
|||
> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它. |
|||
|
|||
标准包贡献者在`Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet包中定义. |
|||
将它安装到你的项目中: |
|||
|
|||
```` |
|||
install-package Volo.Abp.AspNetCore.Mvc.UI.Packages |
|||
```` |
|||
|
|||
然后将`AbpAspNetCoreMvcUiPackagesModule`模块依赖项添加到你的模块中; |
|||
|
|||
````C# |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace MyCompany.MyProject |
|||
{ |
|||
[DependsOn(typeof(AbpAspNetCoreMvcUiPackagesModule))] |
|||
public class MyWebModule : AbpModule |
|||
{ |
|||
//... |
|||
} |
|||
} |
|||
```` |
|||
|
|||
#### Bundle 继承 |
|||
|
|||
在某些特定情况下, 可能需要从其他bundle创建一个 **新** bundle **继承**, 从bundle继承(递归)会继承该bundle的所有文件/贡献者. 然后派生的bundle可以添加或修改文件/贡献者**而无需修改**原始bundle. |
|||
例如: |
|||
|
|||
````c# |
|||
services.Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.StyleBundles |
|||
.Add("MyTheme.MyGlobalBundle", bundle => { |
|||
bundle |
|||
.AddBaseBundles("MyGlobalBundle") //Can add multiple |
|||
.AddFiles( |
|||
"/styles/mytheme-global-styles.css" |
|||
); |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
### 主题 |
|||
|
|||
主题使用标准包贡献者将库资源添加到页面布局. 主题还可以定义一些标准/全局包, 因此任何模块都可以为这些标准/全局包做出贡献. 有关更多信息, 请参阅[主题文档](Theming.md). |
|||
|
|||
### 最佳实践 & 建议 |
|||
|
|||
建议为应用程序定义多个包, 每个包用于不同的目的. |
|||
|
|||
* **全局包**: 应用程序中的每个页面都包含全局样式/脚本包. 主题已经定义了全局样式和脚本包. 你的模块可以为他们做出贡献. |
|||
* **布局包**: 这是针对单个布局的特定包. 仅包含在所有页面之间共享的资源使用布局. 使用bundling tag helpers创建捆绑包是一种很好的做法. |
|||
* **模块包**: 用于单个模块页面之间的共享资源. |
|||
* **页面包**: 为每个页面创建的特定包. 使用bundling tag helpers创建捆绑包作为最佳实践. |
|||
|
|||
在性能,网络带宽使用和捆绑包的数量之间建立平衡. |
|||
|
|||
### 参见 |
|||
|
|||
* [客户端包管理](Client-Side-Package-Management.md) |
|||
* [主题](Theming.md) |
|||
[点击链接跳转到ASP.NET Core MVC 捆绑 & 压缩文档](../UI/AspNetCore/Bundling-Minification.md) |
|||
@ -1,115 +1,3 @@ |
|||
文档已经移动到其他位置. |
|||
|
|||
## ASP.NET Core MVC 客户端包管理 |
|||
|
|||
ABP框架可以与任何类型的客户端包管理系统一起使用. 甚至你可以决定不使用包管理系统并手动管理依赖项. |
|||
|
|||
但是, ABP框架最适用于**NPM/Yarn**. 默认情况下,内置模块配置为与NPM/Yarn一起使用. |
|||
|
|||
最后, 我们建议[**Yarn**](https://classic.yarnpkg.com/)而不是NPM,因为它更快,更稳定并且与NPM兼容. |
|||
|
|||
### @ABP NPM Packages |
|||
|
|||
ABP是一个模块化平台. 每个开发人员都可以创建模块, 模块应该在**兼容**和**稳定**状态下协同工作. |
|||
|
|||
一个挑战是依赖NPM包的**版本**. 如果两个不同的模块使用相同的JavaScript库但其不同(并且可能不兼容)的版本会怎样. |
|||
|
|||
为了解决版本问题, 我们创建了一套**标准包**, 这取决于一些常见的第三方库. 一些示例包是[@abp/jquery](https://www.npmjs.com/package/@abp/jquery), [@ abp/bootstrap](https://www.npmjs.com/package/@abp/bootstrap)和[@abp/font-awesome](https://www.npmjs.com/package/@abp/font-awesome). 你可以从[Github存储库](https://github.com/volosoft/abp/tree/master/npm/packs)中查看**列表**. |
|||
|
|||
**标准包**的好处是: |
|||
|
|||
* 它取决于包装的**标准版本**. 取决于此包是**安全**,因为所有模块都依赖于相同的版本. |
|||
* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹的gulp任务. 有关更多信息, 请参阅 *映射库资源* 部分. |
|||
|
|||
依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如: |
|||
|
|||
```` |
|||
{ |
|||
... |
|||
"dependencies": { |
|||
"@abp/bootstrap": "^1.0.0" |
|||
} |
|||
} |
|||
```` |
|||
|
|||
建议依赖于标准软件包, 而不是直接依赖于第三方软件包. |
|||
|
|||
#### 安装包 |
|||
|
|||
依赖于NPM包后, 你应该做的就是从命令行运行**yarn**命令来安装所有包及其依赖项: |
|||
|
|||
```` |
|||
yarn |
|||
```` |
|||
|
|||
虽然你可以使用`npm install`,但如前所述,建议使用[Yarn](https://classic.yarnpkg.com/). |
|||
|
|||
#### 贡献包 |
|||
|
|||
如果你需要不在标准软件包中的第三方NPM软件包,你可以在Github[repository](https://github.com/volosoft/abp)上创建Pull请求. 接受遵循这些规则的拉取请求: |
|||
|
|||
* 对于NPM上的`package-name`, 包名称应该命名为`@abp/package-name`(例如:`bootstrap`包的`@abp/bootstrap`). |
|||
* 它应该是**最新的稳定**版本的包. |
|||
* 它应该只依赖于**单个**第三方包. 它可以依赖于多个`@abp/*`包. |
|||
* 包应包含一个`abp.resourcemapping.js`文件格式,如*映射库资源*部分中所定义. 此文件应仅映射所依赖包的资源. |
|||
* 你还需要为你创建的包创建[bundle贡献者](Bundling-Minification.md). |
|||
|
|||
有关示例, 请参阅当前标准包. |
|||
|
|||
### 映射库资源 |
|||
|
|||
使用NPM包和NPM/Yarn工具是客户端库的事实标准. NPM/Yarn工具在Web项目的根文件夹中创建一个**node_modules**文件夹. |
|||
|
|||
下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问. |
|||
|
|||
ABP将基于[Gulp](https://gulpjs.com/)的任务定义为**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项. |
|||
|
|||
**启动模板**已经配置为开箱即用的所有这些. 本节将介绍配置选项. |
|||
|
|||
#### 资源映射定义文件 |
|||
|
|||
模块应该定义一个名为`abp.resourcemapping.js`的JavaScript文件,其格式如下例所示: |
|||
|
|||
````js |
|||
module.exports = { |
|||
aliases: { |
|||
"@node_modules": "./node_modules", |
|||
"@libs": "./wwwroot/libs" |
|||
}, |
|||
clean: [ |
|||
"@libs" |
|||
], |
|||
mappings: { |
|||
|
|||
} |
|||
} |
|||
```` |
|||
|
|||
* **aliases**部分定义了可在映射路径中使用的标准别名(占位符). **@node_modules**和 **@libs**是必需的(通过标准包), 你可以定义自己的别名以减少重复. |
|||
* **clean**部分是在复制文件之前要清理的文件夹列表. |
|||
* **mappings**部分是要复制的文件/文件夹的映射列表.此示例不会复制任何资源本身,但取决于标准包. |
|||
|
|||
示例映射配置如下所示: |
|||
|
|||
````js |
|||
mappings: { |
|||
"@node_modules/bootstrap/dist/css/bootstrap.css": "@libs/bootstrap/css/", |
|||
"@node_modules/bootstrap/dist/js/bootstrap.bundle.js": "@libs/bootstrap/js/" |
|||
} |
|||
```` |
|||
|
|||
#### 使用 Gulp |
|||
|
|||
正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行gulp命令: |
|||
|
|||
```` |
|||
gulp |
|||
```` |
|||
|
|||
当你运行`gulp`时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`yarn&gulp`. |
|||
|
|||
> 运行Gulp命令时, 使用package.json文件解析应用程序的依赖关系. Gulp任务自动发现并映射来自所有依赖项的所有资源(递归). |
|||
|
|||
#### 参见 |
|||
|
|||
* [捆绑 & 压缩](Bundling-Minification.md) |
|||
* [主题](Theming.md) |
|||
[点击链接跳转到ASP.NET Core MVC 客户端包管理文档](../UI/AspNetCore/Client-Side-Package-Management.md) |
|||
@ -1,165 +1,3 @@ |
|||
# 动态 C# API 客户端 |
|||
文档已经移动到其他位置. |
|||
|
|||
ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 `HttpClient` 或者其他低级的HTTP功能调用远程服务并获取数据. |
|||
|
|||
## 服务接口 |
|||
|
|||
你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如: |
|||
|
|||
````csharp |
|||
public interface IBookAppService : IApplicationService |
|||
{ |
|||
Task<List<BookDto>> GetListAsync(); |
|||
} |
|||
```` |
|||
|
|||
为了能自动被发现,你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookAppService`完全满足这个条件. |
|||
|
|||
在你的服务中实现这个类,你可以使用[auto API controller system](Auto-API-Controllers.md)将你的服务暴漏为一个REST API 端点. |
|||
|
|||
## 客户端代理生成 |
|||
|
|||
首先,将[Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget包添加到你的客户端项目中: |
|||
|
|||
```` |
|||
Install-Package Volo.Abp.Http.Client |
|||
```` |
|||
|
|||
然后给你的模块添加`AbpHttpClientModule`依赖: |
|||
|
|||
````csharp |
|||
[DependsOn(typeof(AbpHttpClientModule))] //添加依赖 |
|||
public class MyClientAppModule : AbpModule |
|||
{ |
|||
} |
|||
```` |
|||
|
|||
现在,已经可以创建客户端代理了.例如: |
|||
|
|||
````csharp |
|||
[DependsOn( |
|||
typeof(AbpHttpClientModule), //用来创建客户端代理 |
|||
typeof(BookStoreApplicationModule) //包含应用服务接口 |
|||
)] |
|||
public class MyClientAppModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
//创建动态客户端代理 |
|||
context.Services.AddHttpClientProxies( |
|||
typeof(BookStoreApplicationModule).Assembly |
|||
); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
`AddHttpClientproxies`方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类. |
|||
|
|||
### Endpoint配置 |
|||
|
|||
`appsettings.json`文件中的`RemoteServices`节点被用来设置默认的服务地址.下面是最简单的配置: |
|||
|
|||
```` |
|||
{ |
|||
"RemoteServices": { |
|||
"Default": { |
|||
"BaseUrl": "http://localhost:53929/" |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
查看下面的"RemoteServiceOptions"章节获取更多详细配置. |
|||
|
|||
## 使用 |
|||
|
|||
可以很直接地使用.只需要在你的客户端程序中注入服务接口: |
|||
|
|||
````csharp |
|||
public class MyService : ITransientDependency |
|||
{ |
|||
private readonly IBookAppService _bookService; |
|||
|
|||
public MyService(IBookAppService bookService) |
|||
{ |
|||
_bookService = bookService; |
|||
} |
|||
|
|||
public async Task DoIt() |
|||
{ |
|||
var books = await _bookService.GetListAsync(); |
|||
foreach (var book in books) |
|||
{ |
|||
Console.WriteLine($"[BOOK {book.Id}] Name={book.Name}"); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
本例注入了上面定义的`IBookAppService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用. |
|||
|
|||
### IHttpClientProxy接口 |
|||
|
|||
你可以像上面那样注入`IBookAppService`来使用客户端代理,也可以注入`IHttpClientProxy<IBookAppService>`获取更多明确的用法.这种情况下你可以使用`IHttpClientProxy<T>`接口的`Service`属性. |
|||
|
|||
## 配置 |
|||
|
|||
### RemoteServiceOptions |
|||
|
|||
默认情况下`AbpRemoteServiceOptions`从`appsettings.json`获取.或者,你可以使用`Configure`方法来设置或重写它.如: |
|||
|
|||
````csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.Configure<AbpRemoteServiceOptions>(options => |
|||
{ |
|||
options.RemoteServices.Default = |
|||
new RemoteServiceConfiguration("http://localhost:53929/"); |
|||
}); |
|||
|
|||
//... |
|||
} |
|||
```` |
|||
|
|||
### 多个远程服务端点 |
|||
|
|||
上面的例子已经配置了"Default"远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点: |
|||
|
|||
````json |
|||
{ |
|||
"RemoteServices": { |
|||
"Default": { |
|||
"BaseUrl": "http://localhost:53929/" |
|||
}, |
|||
"BookStore": { |
|||
"BaseUrl": "http://localhost:48392/" |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
`AddHttpClientProxies`方法有一个可选的参数来定义远程服务的名字: |
|||
|
|||
````csharp |
|||
context.Services.AddHttpClientProxies( |
|||
typeof(BookStoreApplicationModule).Assembly, |
|||
remoteServiceName: "BookStore" |
|||
); |
|||
```` |
|||
|
|||
`remoteServiceName`参数会匹配通过`AbpRemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点. |
|||
|
|||
### 作为默认服务 |
|||
|
|||
当你为`IBookAppService`创建了一个服务代理,你可以直接注入`IBookAppService`来使用代理客户端(像上面章节中将的那样).你可以传递`asDefaultService:false`到`AddHttpClientProxies`方法来禁用此功能. |
|||
|
|||
````csharp |
|||
context.Services.AddHttpClientProxies( |
|||
typeof(BookStoreApplicationModule).Assembly, |
|||
asDefaultServices: false |
|||
); |
|||
```` |
|||
|
|||
如果你的程序中已经有一个服务的实现并且你不想用你的客户端代理重写或替换其他的实现,就需要使用`asDefaultServices:false` |
|||
|
|||
> 如果你禁用了`asDefaultService`,你只能使用`IHttpClientProxy<T>`接口去使用客户端代理.(参见上面的相关章节). |
|||
[点击链接跳转到动态 C# API 客户端文档](../API/Dynamic-CSharp-API-Clients.md) |
|||
@ -1,3 +1,3 @@ |
|||
# abp.auth JavaScript API |
|||
文档已经移动到其他位置. |
|||
|
|||
TODO |
|||
[点击链接跳转到JavaScript Auth文档](../../API/JavaScript-API/Auth.md) |
|||
|
|||
@ -1,24 +1,3 @@ |
|||
# JavaScript API |
|||
|
|||
ABP为ASP.NET Core MVC / Razor页面应用程序提供了一些执行客户端常见需求的JavaScrpt Api. |
|||
|
|||
## APIs |
|||
|
|||
* abp.ajax |
|||
* [abp.auth](Auth.md) |
|||
* abp.currentUser |
|||
* abp.dom |
|||
* abp.event |
|||
* abp.features |
|||
* abp.localization |
|||
* abp.log |
|||
* abp.ModalManager |
|||
* abp.notify |
|||
* abp.security |
|||
* abp.setting |
|||
* abp.ui |
|||
* abp.utils |
|||
* abp.ResourceLoader |
|||
* abp.WidgetManager |
|||
* Other APIs |
|||
文档已经移动到其他位置. |
|||
|
|||
[点击链接跳转到JavaScript API文档](../../API/JavaScript-API/Index.md) |
|||
|
|||
@ -1,3 +1,3 @@ |
|||
## Dynamic Forms |
|||
文档已经移动到其他位置. |
|||
|
|||
目前还没有文档. 你现在可以看到[组件演示](http://bootstrap-taghelpers.abp.io/Components/DynamicForms). |
|||
[点击链接跳转到Dynamic Forms文档](../../UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md) |
|||
@ -1,3 +1,3 @@ |
|||
## ABP Tag Helpers |
|||
文档已经移动到其他位置. |
|||
|
|||
"ABP tag helpers" 文档还在创建中. 你现在可以参阅[组件演示](http://bootstrap-taghelpers.abp.io/). |
|||
[点击链接跳转到ABP Tag Helpers文档](../../UI/AspNetCore/Tag-Helpers/Index.md) |
|||
|
|||
@ -1,3 +1,4 @@ |
|||
# Theming |
|||
|
|||
TODO |
|||
文档已经移动到其他位置. |
|||
|
|||
[点击链接跳转到Theming文档](../UI/AspNetCore/Theming.md) |
|||
@ -1,274 +1,4 @@ |
|||
# 小部件 |
|||
|
|||
ABP为创建**可重用的部件**提供了模型和基础设施. 部件系统是[ASP.NET Core ViewComponents](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components)的扩展. 在你有以下需求时,小部件会非常有用; |
|||
文档已经移动到其他位置. |
|||
|
|||
* 在可复用的 **[模块](../Module-Development-Basics.md)** 中定义部件. |
|||
* 在部件中引用 **scripts & styles** 脚本. |
|||
* 使用部件创建 **[仪表盘](Dashboards.md)**. |
|||
* 支持 **[授权](../Authorization.md)** 与 **[捆绑`bundling`](Bundling-Minification.md)** 的部件 |
|||
|
|||
## 基本部件定义 |
|||
|
|||
### 创建一个视图组件 |
|||
|
|||
第一部,创建一个新的ASP.NET Core View Component: |
|||
|
|||
 |
|||
|
|||
**MySimpleWidgetViewComponent.cs**: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
继承 `AbpViewComponent` 不是必需的. 你也可以继承ASP.NET Core的 `ViewComponent`. `AbpViewComponent` 只是定义了一些基本的实用属性. |
|||
|
|||
**Default.cshtml**: |
|||
|
|||
```xml |
|||
<div class="my-simple-widget"> |
|||
<h2>My Simple Widget</h2> |
|||
<p>This is a simple widget!</p> |
|||
</div> |
|||
``` |
|||
|
|||
### 定义部件 |
|||
|
|||
添加 `Widget` attribute 到 `MySimpleWidgetViewComponent` 类,将此视图组件标记为部件: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
## 渲染部件 |
|||
|
|||
渲染部件的用法是ASP.NET Core的标准用法. 在razor view/page中使用 `Component.InvokeAsync` 方法, 就像渲染一个View Component一样. 例如: |
|||
|
|||
````xml |
|||
@await Component.InvokeAsync("MySimpleWidget") |
|||
@await Component.InvokeAsync(typeof(MySimpleWidgetViewComponent)) |
|||
```` |
|||
|
|||
第一行代码使用名称渲染了部件,第二行代码使用type渲染了View Comonent. |
|||
|
|||
## 部件名称 |
|||
|
|||
默认下名称是根据View Conponent组件的名称计算的, 比如你的视图组件名是 `MySimpleWidgetViewComponent`, 那么部件的名称就是 `MySimpleWidget` (删除`ViewComponent`后缀). 这与ASP.NET Core的默认视图组件名称的方式一样. |
|||
|
|||
想要自定义组件名称,只需要使用ASP.NET Core的 `ViewComponent` attribute: |
|||
|
|||
```csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget] |
|||
[ViewComponent(Name = "MyCustomNamedWidget")] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View("~/Pages/Components/MySimpleWidget/Default.cshtml"); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
ABP会通过自定义的名称去处理部件. |
|||
|
|||
> 如果视图组件名与视图组件的文件夹名称不匹配,那么需要像本例中那样去手动编写视图路径. |
|||
|
|||
### 显示名称 |
|||
|
|||
你还可以定义对于使用者友好的本地化显示名称. 需要时在UI中使用显示名称. 显示名称是可选的,在 `Widget` attribute 的`DisplayName`属性中定义: |
|||
|
|||
````csharp |
|||
using DashboardDemo.Localization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget( |
|||
DisplayName = "MySimpleWidgetDisplayName", //Localization key |
|||
DisplayNameResource = typeof(DashboardDemoResource) //localization resource |
|||
)] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
参阅 [本地化文档](../Localization.md) 学习关于本地化资源的更多内容. |
|||
|
|||
## 引用 Style & Script |
|||
|
|||
当部件含有样式和scirpt文件时,会存在一些挑战; |
|||
|
|||
* 使用部件的页面应该将 **script & styles** 文件引用到页面中. |
|||
* 页面还需要解析部件的 `依赖库/文件`. |
|||
|
|||
将资源与部件正确的关联在一起时,ABP会解决这些问题. 使用正确的方法,就不用担心部件的依赖关系. |
|||
|
|||
### 定义一个简单的文件路径 |
|||
|
|||
下面的示例中部件添加了样式和scirpt文件: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget( |
|||
StyleFiles = new[] { "/Pages/Components/MySimpleWidget/Default.css" }, |
|||
ScriptFiles = new[] { "/Pages/Components/MySimpleWidget/Default.js" } |
|||
)] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
ABP会考虑到这些依赖关系, 在view/page中使用正确的方法添加部件 . 样式和script可以是物理文件也可以是虚拟文件. 它于[虚拟文件系统](../Virtual-File-System.md)完全集成]. |
|||
|
|||
### 定义 Bundle |
|||
|
|||
页面中使用的组件的所有资源都做为捆绑包添加(如果没有其他配置,会在生产中合并和压缩). 除了简单的添加文件,你还可以充分的利用捆绑功能. |
|||
|
|||
下面的示例与上面的代码相同,但是在添加文件时文件路径替换成了 `BundleContributor`: |
|||
|
|||
````csharp |
|||
using System.Collections.Generic; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget( |
|||
StyleTypes = new []{ typeof(MySimpleWidgetStyleBundleContributor) }, |
|||
ScriptTypes = new[]{ typeof(MySimpleWidgetScriptBundleContributor) } |
|||
)] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
|
|||
public class MySimpleWidgetStyleBundleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files |
|||
.AddIfNotContains("/Pages/Components/MySimpleWidget/Default.css"); |
|||
} |
|||
} |
|||
|
|||
public class MySimpleWidgetScriptBundleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files |
|||
.AddIfNotContains("/Pages/Components/MySimpleWidget/Default.js"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
```` |
|||
|
|||
捆绑系统非常强大,如果你的部件使用了JavaScript库来呈现图表, 你可以将它声明为依赖项, 如果之前未添加JavaScript库. 则会自动添加到页面中. 使用这种方式让页面使用部件时不用关心依赖项. |
|||
|
|||
参阅 [捆包&压缩 文档](Bundling-Minification.md) 了解更多内容. |
|||
|
|||
## 授权 |
|||
|
|||
某些组件可能只对通过身份验证或授权的用户可用,这时可以使用 `Widget` attribute 的以下属性: |
|||
|
|||
* `RequiresAuthentication` (`bool`): 设置为true,只有通过身份验证的用户(登录用户)可用. |
|||
* `RequiredPolicies` (`List<string>`): 授权用户的策略名称列表. 有关策略的详细信息请参阅[授权文档](../Authorization.md). |
|||
|
|||
示例: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget(RequiredPolicies = new[] { "MyPolicyName" })] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
## 部件选项 |
|||
|
|||
`AbpWidgetOptions` 是 `Widget` attribute 替代, 你可以使用它去配置部件: |
|||
|
|||
```csharp |
|||
Configure<AbpWidgetOptions>(options => |
|||
{ |
|||
options.Widgets.Add<MySimpleWidgetViewComponent>(); |
|||
}); |
|||
``` |
|||
|
|||
将上面的代码写到[模块](../Module-Development-Basics.md)的 `ConfigureServices` 方法中. `AbpWidgetOptions` 可以完成 `Widget` attribute 的所有功能. 比如为组件添加样式: |
|||
|
|||
````csharp |
|||
Configure<AbpWidgetOptions>(options => |
|||
{ |
|||
options.Widgets |
|||
.Add<MySimpleWidgetViewComponent>() |
|||
.WithStyles("/Pages/Components/MySimpleWidget/Default.css"); |
|||
}); |
|||
```` |
|||
|
|||
> 提示: `AbpWidgetOptions` 还可以更改现有的部件配置. 如果要修改应用程序使用的模块内的组件配置,这会很有用. 使用 `options.Widgets.Find` 获取现有的 `WidgetDefinition`. |
|||
[点击链接跳转到小部件文档](../UI/AspNetCore/Widgets.md) |
|||
@ -0,0 +1,3 @@ |
|||
## Creating a Settings Tab |
|||
|
|||
TODO... |
|||
@ -0,0 +1,3 @@ |
|||
# Component Replacement |
|||
|
|||
TODO... |
|||
@ -0,0 +1,3 @@ |
|||
# Angular用户界面自定义指南 |
|||
|
|||
* [替换组件](Component-Replacement.md) |
|||
@ -0,0 +1,3 @@ |
|||
# Localization |
|||
|
|||
TODO... |
|||
@ -0,0 +1,3 @@ |
|||
# Permission Management |
|||
|
|||
TODO... |
|||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,354 @@ |
|||
|
|||
## ASP.NET Core MVC 捆绑 & 压缩 |
|||
|
|||
有许多方法可以捆绑&压缩客户端资源(JavaScript和CSS文件). 最常见的方式是: |
|||
|
|||
* 使用Visual Studio[捆绑&压缩](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier)扩展或者其它的[NuGet相关包](https://www.nuget.org/packages/BuildBundlerMinifier/). |
|||
|
|||
* 使用[Gulp](https://gulpjs.com/)/[Grunt](https://gruntjs.com/)及其插件. |
|||
|
|||
ABP内置了简单,动态,强大,模块化的方式. |
|||
|
|||
### Volo.Abp.AspNetCore.Mvc.UI.Bundling 包 |
|||
|
|||
> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它. |
|||
|
|||
将`Volo.Abp.AspNetCore.Mvc.UI.Bundling` nuget包安装到你的项目中: |
|||
|
|||
```` |
|||
install-package Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
```` |
|||
|
|||
然后将`AbpAspNetCoreMvcUiBundlingModule`依赖项添加到你的模块上: |
|||
|
|||
````C# |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace MyCompany.MyProject |
|||
{ |
|||
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))] |
|||
public class MyWebModule : AbpModule |
|||
{ |
|||
//... |
|||
} |
|||
} |
|||
```` |
|||
|
|||
### Razor Bundling Tag Helpers |
|||
|
|||
创建bundle的最简单方法是使用`abp-script-bundle`或`abp-style-bundle` tag helpers. 例如: |
|||
|
|||
````html |
|||
<abp-style-bundle name="MyGlobalBundle"> |
|||
<abp-style src="/libs/bootstrap/css/bootstrap.css" /> |
|||
<abp-style src="/libs/font-awesome/css/font-awesome.css" /> |
|||
<abp-style src="/libs/toastr/toastr.css" /> |
|||
<abp-style src="/styles/my-global-style.css" /> |
|||
</abp-style-bundle> |
|||
```` |
|||
|
|||
`abp-script-bundle`定义了一个带有**唯一名称**的样式包:`MyGlobalBundle`. 使用方法很容易理解. 让我们看看它是如何*工作的*: |
|||
|
|||
* 当首次请求时,ABP从提供的文件中 **(延迟)lazy** 创建. 后续将从 **缓存** 中返回内容. 这意味着如果你有条件地将文件添加到包中,它只执行一次, 并且条件的任何更改都不会影响下一个请求的包. |
|||
* 在`development`环境中ABP会将包文件**单独**添加到页面中, 其他环境(`staging`,`production`...)会自动捆绑和压缩. |
|||
* 捆绑文件可以是**物理**文件或[**虚拟/嵌入**](../Virtual-File-System.md)的文件. |
|||
* ABP自动将 **版本查询字符串(version query string)** 添加到捆绑文件的URL中,以防止浏览器缓存. 如:?_v=67872834243042(从文件的上次更改日期生成). 即使捆绑文件单独添加到页面(在`development`环境中), 版本控制仍然有效. |
|||
|
|||
#### 导入 Bundling Tag Helpers |
|||
|
|||
> 默认情况下已在启动模板导入. 大多数情况下,你不需要手动安装它. |
|||
|
|||
要使用`bundle tag helpers`, 你需要将其添加到`_ViewImports.cshtml`文件或页面中: |
|||
|
|||
```` |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
```` |
|||
|
|||
#### 未命名的 Bundles |
|||
|
|||
对于razor bundle tag helpers, `name`是**可选**. 如果没有定义一个名字,它将根据使用的捆绑文件名自动**计算生成**(they are **concatenated** and **hashed**) 例: |
|||
|
|||
````html |
|||
<abp-style-bundle> |
|||
<abp-style src="/libs/bootstrap/css/bootstrap.css" /> |
|||
<abp-style src="/libs/font-awesome/css/font-awesome.css" /> |
|||
<abp-style src="/libs/toastr/toastr.css" /> |
|||
@if (ViewBag.IncludeCustomStyles != false) |
|||
{ |
|||
<abp-style src="/styles/my-global-style.css" /> |
|||
} |
|||
</abp-style-bundle> |
|||
```` |
|||
|
|||
这将潜在地创建**两个不同的bundles**(一个包括`my-global-style.css`而另一个则不包括). |
|||
|
|||
**未命名的** bundles优点: |
|||
|
|||
* 可以**有条件地将项目**添加到捆绑包中. 但这可能会导致基于条件的捆绑的存在多种变化. |
|||
|
|||
**命名** bundles优点: |
|||
|
|||
* 其他模块可以通过其名称为捆绑包做出贡献(参见下面的部分). |
|||
|
|||
#### 单个文件 |
|||
|
|||
如果你只需要在页面中添加一个文件, 你可以使用`abp-script`或`abp-style`而不需要包含在`abp-script-bundle`或`abp-style-bundle`中. 例: |
|||
|
|||
````xml |
|||
<abp-script src="/scripts/my-script.js" /> |
|||
```` |
|||
|
|||
对于上面的示例,包名称将是 *scripts.my-scripts*("/"替换为"."). 所有捆绑功能也可以按预期应用于单个文件. |
|||
|
|||
### Bundling 选项 |
|||
|
|||
如果你需要在 **多个页面中使用相同的包** 或想要使用更多 **强大功能**, 你可以在[模块](../Module-Development-Basics.md)类中进行**配置**. |
|||
|
|||
#### 创建一个新的捆绑包 |
|||
|
|||
用法示例: |
|||
|
|||
````C# |
|||
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))] |
|||
public class MyWebModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.ScriptBundles |
|||
.Add("MyGlobalBundle", bundle => { |
|||
bundle.AddFiles( |
|||
"/libs/jquery/jquery.js", |
|||
"/libs/bootstrap/js/bootstrap.js", |
|||
"/libs/toastr/toastr.min.js", |
|||
"/scripts/my-global-scripts.js" |
|||
); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
> 你可以在脚本和样式包中使用相同的名称(*MyGlobalBundle*), 因为它们被添加到不同的集合(`ScriptBundles`和`StyleBundles`). |
|||
|
|||
在定义bundle之后, 可以使用上面定义的相同tag helpers将其包括在页面中. 例如: |
|||
|
|||
````html |
|||
<abp-script-bundle name="MyGlobalBundle" /> |
|||
```` |
|||
|
|||
这次tag helper定义中没有定义文件, 因为捆绑文件是由代码定义的. |
|||
|
|||
#### 配置现有的 Bundle |
|||
|
|||
ABP也支持[模块化](../Module-Development-Basics.md)捆绑. 模块可以修改由依赖模块创建的捆绑包. |
|||
例如: |
|||
|
|||
````C# |
|||
[DependsOn(typeof(MyWebModule))] |
|||
public class MyWebExtensionModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.ScriptBundles |
|||
.Configure("MyGlobalBundle", bundle => { |
|||
bundle.AddFiles( |
|||
"/scripts/my-extension-script.js" |
|||
); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
> 无法通过代码配置未命名的bundle tag helpers, 因为它们的名称在开发时是未知的. 建议始终使用bundle tag helper的名称. |
|||
|
|||
### Bundle 贡献者 |
|||
|
|||
将文件添加到现有bundle似乎很有用. 如果你需要**替换**bundle中的文件或者你想**有条件地**添加文件怎么办? 定义bundle贡献者可为此类情况提供额外的功能. |
|||
|
|||
一个bundle的贡献者使用自定义版本bootstrap.css替换示例: |
|||
|
|||
````C# |
|||
public class MyExtensionGlobalStyleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.ReplaceOne( |
|||
"/libs/bootstrap/css/bootstrap.css", |
|||
"/styles/extensions/bootstrap-customized.css" |
|||
); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
然后你可以按照下面的代码使用这个贡献者: |
|||
|
|||
````C# |
|||
services.Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.ScriptBundles |
|||
.Configure("MyGlobalBundle", bundle => { |
|||
bundle.AddContributors(typeof(MyExtensionGlobalStyleContributor)); |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
贡献者也可以在bundle tag helpers中使用. |
|||
例如: |
|||
|
|||
````xml |
|||
<abp-style-bundle> |
|||
<abp-style type="@typeof(BootstrapStyleContributor)" /> |
|||
<abp-style src="/libs/font-awesome/css/font-awesome.css" /> |
|||
<abp-style src="/libs/toastr/toastr.css" /> |
|||
</abp-style-bundle> |
|||
```` |
|||
|
|||
`abp-style`和`abp-script`标签可以使用`type`属性(而不是`src`属性), 如本示例所示. 添加bundle贡献者时, 其依赖关系也会自动添加到bundle中. |
|||
|
|||
#### 贡献者依赖关系 |
|||
|
|||
bundle贡献者可以与其他贡献者具有一个或多个依赖关系. |
|||
例如: |
|||
|
|||
````C# |
|||
[DependsOn(typeof(MyDependedBundleContributor))] //Define the dependency |
|||
public class MyExtensionStyleBundleContributor : BundleContributor |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
添加bundle贡献者时,其依赖关系将 **自动并递归** 添加. **依赖顺序** 通过阻止 **重复** 添加的依赖关系. 即使它们处于分离的bundle中,也会阻止重复. ABP在页面中组织所有bundle并消除重复. |
|||
|
|||
创建贡献者和定义依赖关系是一种跨不同模块组织bundle创建的方法. |
|||
|
|||
|
|||
#### 贡献者扩展 |
|||
|
|||
在某些高级应用场景中, 当用到一个bundle贡献者时,你可能想做一些额外的配置. 贡献者扩展可以和被扩展的贡献者无缝衔接. |
|||
|
|||
下面的示例为 prism.js 脚本库添加一些样式: |
|||
|
|||
````csharp |
|||
public class MyPrismjsStyleExtension : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/prismjs/plugins/toolbar/prism-toolbar.css"); |
|||
} |
|||
} |
|||
```` |
|||
|
|||
然后你可以配置 `BundleContributorOptions` 去扩展已存在的 `PrismjsStyleBundleContributor`. |
|||
|
|||
````csharp |
|||
Configure<BundleContributorOptions>(options => |
|||
{ |
|||
options |
|||
.Extensions<PrismjsStyleBundleContributor>() |
|||
.Add<MyPrismjsStyleExtension>(); |
|||
}); |
|||
```` |
|||
|
|||
任何时候当 `PrismjsStyleBundleContributor` 被添加到bundle中时, `MyPrismjsStyleExtension` 也会被自动添加. |
|||
|
|||
#### 访问 IServiceProvider |
|||
|
|||
虽然很少需要它, 但是`BundleConfigurationContext`有一个`ServiceProvider`属性, 你可以在`ConfigureBundle`方法中解析服务依赖. |
|||
|
|||
#### 标准包装贡献者 |
|||
|
|||
将特定的NPM包资源(js,css文件)添加到包中对于该包非常简单. 例如, 你总是为bootstrap NPM包添加`bootstrap.css`文件. |
|||
|
|||
所有[标准NPM包](Client-Side-Package-Management.md)都有内置的贡献者. 例如,如果你的贡献者依赖于bootstrap,你可以声明它,而不是自己添加bootstrap.css. |
|||
|
|||
````C# |
|||
[DependsOn(typeof(BootstrapStyleContributor))] //Define the bootstrap style dependency |
|||
public class MyExtensionStyleBundleContributor : BundleContributor |
|||
{ |
|||
//... |
|||
} |
|||
```` |
|||
|
|||
使用标准包的内置贡献者: |
|||
|
|||
* 防止你输入**无效的资源路径**. |
|||
* 如果资源 **路径发生变化** (依赖贡献者将处理它),则防止更改你的贡献者. |
|||
* 防止多个模块添加**重复文件**. |
|||
* 以递归方式管理依赖项(如果需要,添加依赖项的依赖项). |
|||
|
|||
##### Volo.Abp.AspNetCore.Mvc.UI.Packages 包 |
|||
|
|||
> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它. |
|||
|
|||
标准包贡献者在`Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet包中定义. |
|||
将它安装到你的项目中: |
|||
|
|||
```` |
|||
install-package Volo.Abp.AspNetCore.Mvc.UI.Packages |
|||
```` |
|||
|
|||
然后将`AbpAspNetCoreMvcUiPackagesModule`模块依赖项添加到你的模块中; |
|||
|
|||
````C# |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace MyCompany.MyProject |
|||
{ |
|||
[DependsOn(typeof(AbpAspNetCoreMvcUiPackagesModule))] |
|||
public class MyWebModule : AbpModule |
|||
{ |
|||
//... |
|||
} |
|||
} |
|||
```` |
|||
|
|||
#### Bundle 继承 |
|||
|
|||
在某些特定情况下, 可能需要从其他bundle创建一个 **新** bundle **继承**, 从bundle继承(递归)会继承该bundle的所有文件/贡献者. 然后派生的bundle可以添加或修改文件/贡献者**而无需修改**原始bundle. |
|||
例如: |
|||
|
|||
````c# |
|||
services.Configure<BundlingOptions>(options => |
|||
{ |
|||
options |
|||
.StyleBundles |
|||
.Add("MyTheme.MyGlobalBundle", bundle => { |
|||
bundle |
|||
.AddBaseBundles("MyGlobalBundle") //Can add multiple |
|||
.AddFiles( |
|||
"/styles/mytheme-global-styles.css" |
|||
); |
|||
}); |
|||
}); |
|||
```` |
|||
|
|||
### 主题 |
|||
|
|||
主题使用标准包贡献者将库资源添加到页面布局. 主题还可以定义一些标准/全局包, 因此任何模块都可以为这些标准/全局包做出贡献. 有关更多信息, 请参阅[主题文档](Theming.md). |
|||
|
|||
### 最佳实践 & 建议 |
|||
|
|||
建议为应用程序定义多个包, 每个包用于不同的目的. |
|||
|
|||
* **全局包**: 应用程序中的每个页面都包含全局样式/脚本包. 主题已经定义了全局样式和脚本包. 你的模块可以为他们做出贡献. |
|||
* **布局包**: 这是针对单个布局的特定包. 仅包含在所有页面之间共享的资源使用布局. 使用bundling tag helpers创建捆绑包是一种很好的做法. |
|||
* **模块包**: 用于单个模块页面之间的共享资源. |
|||
* **页面包**: 为每个页面创建的特定包. 使用bundling tag helpers创建捆绑包作为最佳实践. |
|||
|
|||
在性能,网络带宽使用和捆绑包的数量之间建立平衡. |
|||
|
|||
### 参见 |
|||
|
|||
* [客户端包管理](Client-Side-Package-Management.md) |
|||
* [主题](Theming.md) |
|||
@ -0,0 +1,115 @@ |
|||
|
|||
## ASP.NET Core MVC 客户端包管理 |
|||
|
|||
ABP框架可以与任何类型的客户端包管理系统一起使用. 甚至你可以决定不使用包管理系统并手动管理依赖项. |
|||
|
|||
但是, ABP框架最适用于**NPM/Yarn**. 默认情况下,内置模块配置为与NPM/Yarn一起使用. |
|||
|
|||
最后, 我们建议[**Yarn**](https://classic.yarnpkg.com/)而不是NPM,因为它更快,更稳定并且与NPM兼容. |
|||
|
|||
### @ABP NPM Packages |
|||
|
|||
ABP是一个模块化平台. 每个开发人员都可以创建模块, 模块应该在**兼容**和**稳定**状态下协同工作. |
|||
|
|||
一个挑战是依赖NPM包的**版本**. 如果两个不同的模块使用相同的JavaScript库但其不同(并且可能不兼容)的版本会怎样. |
|||
|
|||
为了解决版本问题, 我们创建了一套**标准包**, 这取决于一些常见的第三方库. 一些示例包是[@abp/jquery](https://www.npmjs.com/package/@abp/jquery), [@ abp/bootstrap](https://www.npmjs.com/package/@abp/bootstrap)和[@abp/font-awesome](https://www.npmjs.com/package/@abp/font-awesome). 你可以从[Github存储库](https://github.com/volosoft/abp/tree/master/npm/packs)中查看**列表**. |
|||
|
|||
**标准包**的好处是: |
|||
|
|||
* 它取决于包装的**标准版本**. 取决于此包是**安全**,因为所有模块都依赖于相同的版本. |
|||
* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹的gulp任务. 有关更多信息, 请参阅 *映射库资源* 部分. |
|||
|
|||
依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如: |
|||
|
|||
```` |
|||
{ |
|||
... |
|||
"dependencies": { |
|||
"@abp/bootstrap": "^1.0.0" |
|||
} |
|||
} |
|||
```` |
|||
|
|||
建议依赖于标准软件包, 而不是直接依赖于第三方软件包. |
|||
|
|||
#### 安装包 |
|||
|
|||
依赖于NPM包后, 你应该做的就是从命令行运行**yarn**命令来安装所有包及其依赖项: |
|||
|
|||
```` |
|||
yarn |
|||
```` |
|||
|
|||
虽然你可以使用`npm install`,但如前所述,建议使用[Yarn](https://classic.yarnpkg.com/). |
|||
|
|||
#### 贡献包 |
|||
|
|||
如果你需要不在标准软件包中的第三方NPM软件包,你可以在Github[repository](https://github.com/volosoft/abp)上创建Pull请求. 接受遵循这些规则的拉取请求: |
|||
|
|||
* 对于NPM上的`package-name`, 包名称应该命名为`@abp/package-name`(例如:`bootstrap`包的`@abp/bootstrap`). |
|||
* 它应该是**最新的稳定**版本的包. |
|||
* 它应该只依赖于**单个**第三方包. 它可以依赖于多个`@abp/*`包. |
|||
* 包应包含一个`abp.resourcemapping.js`文件格式,如*映射库资源*部分中所定义. 此文件应仅映射所依赖包的资源. |
|||
* 你还需要为你创建的包创建[bundle贡献者](Bundling-Minification.md). |
|||
|
|||
有关示例, 请参阅当前标准包. |
|||
|
|||
### 映射库资源 |
|||
|
|||
使用NPM包和NPM/Yarn工具是客户端库的事实标准. NPM/Yarn工具在Web项目的根文件夹中创建一个**node_modules**文件夹. |
|||
|
|||
下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问. |
|||
|
|||
ABP将基于[Gulp](https://gulpjs.com/)的任务定义为**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项. |
|||
|
|||
**启动模板**已经配置为开箱即用的所有这些. 本节将介绍配置选项. |
|||
|
|||
#### 资源映射定义文件 |
|||
|
|||
模块应该定义一个名为`abp.resourcemapping.js`的JavaScript文件,其格式如下例所示: |
|||
|
|||
````js |
|||
module.exports = { |
|||
aliases: { |
|||
"@node_modules": "./node_modules", |
|||
"@libs": "./wwwroot/libs" |
|||
}, |
|||
clean: [ |
|||
"@libs" |
|||
], |
|||
mappings: { |
|||
|
|||
} |
|||
} |
|||
```` |
|||
|
|||
* **aliases**部分定义了可在映射路径中使用的标准别名(占位符). **@node_modules**和 **@libs**是必需的(通过标准包), 你可以定义自己的别名以减少重复. |
|||
* **clean**部分是在复制文件之前要清理的文件夹列表. |
|||
* **mappings**部分是要复制的文件/文件夹的映射列表.此示例不会复制任何资源本身,但取决于标准包. |
|||
|
|||
示例映射配置如下所示: |
|||
|
|||
````js |
|||
mappings: { |
|||
"@node_modules/bootstrap/dist/css/bootstrap.css": "@libs/bootstrap/css/", |
|||
"@node_modules/bootstrap/dist/js/bootstrap.bundle.js": "@libs/bootstrap/js/" |
|||
} |
|||
```` |
|||
|
|||
#### 使用 Gulp |
|||
|
|||
正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行gulp命令: |
|||
|
|||
```` |
|||
gulp |
|||
```` |
|||
|
|||
当你运行`gulp`时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`yarn&gulp`. |
|||
|
|||
> 运行Gulp命令时, 使用package.json文件解析应用程序的依赖关系. Gulp任务自动发现并映射来自所有依赖项的所有资源(递归). |
|||
|
|||
#### 参见 |
|||
|
|||
* [捆绑 & 压缩](Bundling-Minification.md) |
|||
* [主题](Theming.md) |
|||
@ -0,0 +1,94 @@ |
|||
# 按钮 |
|||
|
|||
ABP框架定义了Tag Helper用于简单的创建bootstrap按钮. |
|||
|
|||
`<abp-button>` |
|||
|
|||
## 属性 |
|||
|
|||
`<abp-button>` 有7个不同的属性. |
|||
|
|||
* [`button-type`](#button-type) |
|||
* [`size`](#size) |
|||
* [`busy-text`](#busy-text) |
|||
* [`text`](#text) |
|||
* [`icon`](#icon) |
|||
* [`disabled`](#disabled) |
|||
* [`icon-type`](#icon-type) |
|||
|
|||
### `button-type` |
|||
|
|||
`button-type` 是一个可选参数. 它的默认值是 `Default`. |
|||
|
|||
`<abp-button button-type="Primary">Button</abp-button>` |
|||
|
|||
你可以为按钮选择以下按钮类型: |
|||
|
|||
* `Default` |
|||
* `Primary` |
|||
* `Secondary` |
|||
* `Success` |
|||
* `Danger` |
|||
* `Warning` |
|||
* `Info` |
|||
* `Light` |
|||
* `Dark` |
|||
* `Outline_Primary` |
|||
* `Outline_Secondary` |
|||
* `Outline_Success` |
|||
* `Outline_Danger` |
|||
* `Outline_Warning` |
|||
* `Outline_Info` |
|||
* `Outline_Light` |
|||
* `Outline_Dark` |
|||
* `Link` |
|||
|
|||
### `size` |
|||
|
|||
`size` 是一个可选参数. 它的默认值是 `Default`. |
|||
|
|||
`<abp-button size="Default">Button</abp-button>` |
|||
|
|||
你可以为按钮选择以下size类型: |
|||
|
|||
* `Default` |
|||
* `Small` |
|||
* `Medium` |
|||
* `Large` |
|||
* `Block` |
|||
* `Block_Small` |
|||
* `Block_Medium` |
|||
* `Block_Large` |
|||
|
|||
### `busy-text` |
|||
|
|||
`busy-text` 是一个字符串类型参数. 当按钮繁忙时设置该文本. |
|||
|
|||
### `text` |
|||
|
|||
`text` 是一个字符串类型参数,显示在按钮上. |
|||
|
|||
### `icon` |
|||
|
|||
`icon` 是一个字符串类型参数. 它的值取决于[`icon-type`](#`icon-type`). 默认情况下,我们对图标使用[Font Awesome](https://fontawesome.com/). 要使用它,你需要将 `icon` 参数设置为图标名称. |
|||
|
|||
##### 示例 |
|||
|
|||
[fa-address-card](https://fontawesome.com/icons/address-card):  |
|||
|
|||
`<abp-button icon="address-card" text="Address" />` |
|||
|
|||
> 不要忘记: 你不需要写前缀,如果你没有更改 `icon-type` ,它会为[Font Awesome](https://fontawesome.com/)图标自动添加 `fa` 前缀. |
|||
|
|||
### `disabled` |
|||
|
|||
`disabled` 是一个布尔类型参数. 如果你设值为 `true`, 按钮会被禁用. |
|||
|
|||
### `icon-type` |
|||
|
|||
`icon-type` 是一个可选参数。它的默认值是 `FontAwesome`. 你可以创建自己的图标类型提供程序并更改它. |
|||
|
|||
你可以为按钮选择以下图标类型: |
|||
|
|||
* `FontAwesome` |
|||
* `Other` |
|||
@ -0,0 +1,3 @@ |
|||
## Dynamic Forms |
|||
|
|||
目前还没有文档. 你现在可以看到[组件演示](http://bootstrap-taghelpers.abp.io/Components/DynamicForms). |
|||
@ -0,0 +1,3 @@ |
|||
## ABP Tag Helpers |
|||
|
|||
"ABP tag helpers" 文档还在创建中. 你现在可以参阅[组件演示](http://bootstrap-taghelpers.abp.io/). |
|||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,3 @@ |
|||
# Theming |
|||
|
|||
TODO |
|||
@ -0,0 +1,274 @@ |
|||
# 小部件 |
|||
|
|||
ABP为创建**可重用的部件**提供了模型和基础设施. 部件系统是[ASP.NET Core ViewComponents](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components)的扩展. 在你有以下需求时,小部件会非常有用; |
|||
|
|||
* 在可复用的 **[模块](../Module-Development-Basics.md)** 中定义部件. |
|||
* 在部件中引用 **scripts & styles** 脚本. |
|||
* 使用部件创建 **[仪表盘](Dashboards.md)**. |
|||
* 支持 **[授权](../Authorization.md)** 与 **[捆绑`bundling`](Bundling-Minification.md)** 的部件 |
|||
|
|||
## 基本部件定义 |
|||
|
|||
### 创建一个视图组件 |
|||
|
|||
第一部,创建一个新的ASP.NET Core View Component: |
|||
|
|||
 |
|||
|
|||
**MySimpleWidgetViewComponent.cs**: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
继承 `AbpViewComponent` 不是必需的. 你也可以继承ASP.NET Core的 `ViewComponent`. `AbpViewComponent` 只是定义了一些基本的实用属性. |
|||
|
|||
**Default.cshtml**: |
|||
|
|||
```xml |
|||
<div class="my-simple-widget"> |
|||
<h2>My Simple Widget</h2> |
|||
<p>This is a simple widget!</p> |
|||
</div> |
|||
``` |
|||
|
|||
### 定义部件 |
|||
|
|||
添加 `Widget` attribute 到 `MySimpleWidgetViewComponent` 类,将此视图组件标记为部件: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
## 渲染部件 |
|||
|
|||
渲染部件的用法是ASP.NET Core的标准用法. 在razor view/page中使用 `Component.InvokeAsync` 方法, 就像渲染一个View Component一样. 例如: |
|||
|
|||
````xml |
|||
@await Component.InvokeAsync("MySimpleWidget") |
|||
@await Component.InvokeAsync(typeof(MySimpleWidgetViewComponent)) |
|||
```` |
|||
|
|||
第一行代码使用名称渲染了部件,第二行代码使用type渲染了View Comonent. |
|||
|
|||
## 部件名称 |
|||
|
|||
默认下名称是根据View Conponent组件的名称计算的, 比如你的视图组件名是 `MySimpleWidgetViewComponent`, 那么部件的名称就是 `MySimpleWidget` (删除`ViewComponent`后缀). 这与ASP.NET Core的默认视图组件名称的方式一样. |
|||
|
|||
想要自定义组件名称,只需要使用ASP.NET Core的 `ViewComponent` attribute: |
|||
|
|||
```csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget] |
|||
[ViewComponent(Name = "MyCustomNamedWidget")] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View("~/Pages/Components/MySimpleWidget/Default.cshtml"); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
ABP会通过自定义的名称去处理部件. |
|||
|
|||
> 如果视图组件名与视图组件的文件夹名称不匹配,那么需要像本例中那样去手动编写视图路径. |
|||
|
|||
### 显示名称 |
|||
|
|||
你还可以定义对于使用者友好的本地化显示名称. 需要时在UI中使用显示名称. 显示名称是可选的,在 `Widget` attribute 的`DisplayName`属性中定义: |
|||
|
|||
````csharp |
|||
using DashboardDemo.Localization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget( |
|||
DisplayName = "MySimpleWidgetDisplayName", //Localization key |
|||
DisplayNameResource = typeof(DashboardDemoResource) //localization resource |
|||
)] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
参阅 [本地化文档](../Localization.md) 学习关于本地化资源的更多内容. |
|||
|
|||
## 引用 Style & Script |
|||
|
|||
当部件含有样式和scirpt文件时,会存在一些挑战; |
|||
|
|||
* 使用部件的页面应该将 **script & styles** 文件引用到页面中. |
|||
* 页面还需要解析部件的 `依赖库/文件`. |
|||
|
|||
将资源与部件正确的关联在一起时,ABP会解决这些问题. 使用正确的方法,就不用担心部件的依赖关系. |
|||
|
|||
### 定义一个简单的文件路径 |
|||
|
|||
下面的示例中部件添加了样式和scirpt文件: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget( |
|||
StyleFiles = new[] { "/Pages/Components/MySimpleWidget/Default.css" }, |
|||
ScriptFiles = new[] { "/Pages/Components/MySimpleWidget/Default.js" } |
|||
)] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
ABP会考虑到这些依赖关系, 在view/page中使用正确的方法添加部件 . 样式和script可以是物理文件也可以是虚拟文件. 它于[虚拟文件系统](../Virtual-File-System.md)完全集成]. |
|||
|
|||
### 定义 Bundle |
|||
|
|||
页面中使用的组件的所有资源都做为捆绑包添加(如果没有其他配置,会在生产中合并和压缩). 除了简单的添加文件,你还可以充分的利用捆绑功能. |
|||
|
|||
下面的示例与上面的代码相同,但是在添加文件时文件路径替换成了 `BundleContributor`: |
|||
|
|||
````csharp |
|||
using System.Collections.Generic; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget( |
|||
StyleTypes = new []{ typeof(MySimpleWidgetStyleBundleContributor) }, |
|||
ScriptTypes = new[]{ typeof(MySimpleWidgetScriptBundleContributor) } |
|||
)] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
|
|||
public class MySimpleWidgetStyleBundleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files |
|||
.AddIfNotContains("/Pages/Components/MySimpleWidget/Default.css"); |
|||
} |
|||
} |
|||
|
|||
public class MySimpleWidgetScriptBundleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files |
|||
.AddIfNotContains("/Pages/Components/MySimpleWidget/Default.js"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
```` |
|||
|
|||
捆绑系统非常强大,如果你的部件使用了JavaScript库来呈现图表, 你可以将它声明为依赖项, 如果之前未添加JavaScript库. 则会自动添加到页面中. 使用这种方式让页面使用部件时不用关心依赖项. |
|||
|
|||
参阅 [捆包&压缩 文档](Bundling-Minification.md) 了解更多内容. |
|||
|
|||
## 授权 |
|||
|
|||
某些组件可能只对通过身份验证或授权的用户可用,这时可以使用 `Widget` attribute 的以下属性: |
|||
|
|||
* `RequiresAuthentication` (`bool`): 设置为true,只有通过身份验证的用户(登录用户)可用. |
|||
* `RequiredPolicies` (`List<string>`): 授权用户的策略名称列表. 有关策略的详细信息请参阅[授权文档](../Authorization.md). |
|||
|
|||
示例: |
|||
|
|||
````csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace DashboardDemo.Web.Pages.Components.MySimpleWidget |
|||
{ |
|||
[Widget(RequiredPolicies = new[] { "MyPolicyName" })] |
|||
public class MySimpleWidgetViewComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
## 部件选项 |
|||
|
|||
`AbpWidgetOptions` 是 `Widget` attribute 替代, 你可以使用它去配置部件: |
|||
|
|||
```csharp |
|||
Configure<AbpWidgetOptions>(options => |
|||
{ |
|||
options.Widgets.Add<MySimpleWidgetViewComponent>(); |
|||
}); |
|||
``` |
|||
|
|||
将上面的代码写到[模块](../Module-Development-Basics.md)的 `ConfigureServices` 方法中. `AbpWidgetOptions` 可以完成 `Widget` attribute 的所有功能. 比如为组件添加样式: |
|||
|
|||
````csharp |
|||
Configure<AbpWidgetOptions>(options => |
|||
{ |
|||
options.Widgets |
|||
.Add<MySimpleWidgetViewComponent>() |
|||
.WithStyles("/Pages/Components/MySimpleWidget/Default.css"); |
|||
}); |
|||
```` |
|||
|
|||
> 提示: `AbpWidgetOptions` 还可以更改现有的部件配置. 如果要修改应用程序使用的模块内的组件配置,这会很有用. 使用 `options.Widgets.Find` 获取现有的 `WidgetDefinition`. |
|||
Loading…
Reference in new issue