mirror of https://github.com/abpframework/abp
commit
60fbaf6e45
@ -0,0 +1,138 @@
|
||||
# 自动API控制器
|
||||
|
||||
创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做.
|
||||
|
||||
ABP可以按照惯例 **自动** 将你的应用程序服务配置为MVC 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,153 @@
|
||||
# 动态 C# API 客户端
|
||||
|
||||
ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 `HttpClient` 或者其他低级的HTTP功能调用远程服务并获取数据.
|
||||
|
||||
## 服务接口
|
||||
|
||||
你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如:
|
||||
|
||||
````csharp
|
||||
public interface IBookService : IApplicationService
|
||||
{
|
||||
Task<List<BookDto>> GetListAsync();
|
||||
}
|
||||
````
|
||||
|
||||
你的接口需要实现`IRemoteService`接口.由于`IApplicationService`继承自`IRemoteService`接口.所以`IBookService`完全满足这个条件.
|
||||
|
||||
在你的服务中实现这个类,你可以使用[Auto API Controller](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.Configure<RemoteServiceOptions>(options =>
|
||||
{
|
||||
options.RemoteServices.Default =
|
||||
new RemoteServiceConfiguration("http://localhost:53929/");
|
||||
});
|
||||
|
||||
//创建动态客户端代理
|
||||
context.Services.AddHttpClientProxies(
|
||||
typeof(BookStoreApplicationModule).Assembly
|
||||
);
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
`RemoteServiceOptions`被用来为远程服务配置端点(本例设置了默认的端点,当然你也可以拥有不同的服务端点供不同的客户端使用.参考本文"多个远程服务端点"小节).
|
||||
|
||||
`AddHttpClientproxies`方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类.
|
||||
|
||||
## 使用
|
||||
|
||||
可以很直接地使用.只需要在你的客户端程序中注入服务接口:
|
||||
|
||||
````csharp
|
||||
public class MyService : ITransientDependency
|
||||
{
|
||||
private readonly IBookService _bookService;
|
||||
|
||||
public MyService(IBookService 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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
本例注入了上面定义的`IBookService`服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用.
|
||||
|
||||
## 详细配置
|
||||
|
||||
### RemoteServiceOptions
|
||||
|
||||
你可以像上面展示的那样配置`RemoteServiceOptions`.也可以从`appsettings.json`文件中读取.在你的`appsettings.json`文件中添加`RemoteServices`节点:
|
||||
|
||||
````json
|
||||
{
|
||||
"RemoteServices": {
|
||||
"Default": {
|
||||
"BaseUrl": "http://localhost:53929/"
|
||||
}
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
然后你可以像下面这样将`IConfigurationRoot`实例直接传递到`Configure<RemoteServiceOptions>()`方法中:
|
||||
|
||||
````csharp
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.Build();
|
||||
|
||||
context.Services.Configure<RemoteServiceOptions>(configuration);
|
||||
````
|
||||
|
||||
这种方式对于不修改代码来改变配置是非常有用的.
|
||||
|
||||
#### 多个远程服务端点
|
||||
|
||||
上面的例子已经配置了"Default"远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点:
|
||||
|
||||
````json
|
||||
{
|
||||
"RemoteServices": {
|
||||
"Default": {
|
||||
"BaseUrl": "http://localhost:53929/"
|
||||
},
|
||||
"BookStore": {
|
||||
"BaseUrl": "http://localhost:48392/"
|
||||
}
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
下一节学习如何使用这个新的端点.
|
||||
|
||||
### AddHttpClientProxies方法
|
||||
|
||||
`AddHttpClientProxies`方法有一个可选的参数来定义远程服务的名字:
|
||||
|
||||
````csharp
|
||||
context.Services.AddHttpClientProxies(
|
||||
typeof(BookStoreApplicationModule).Assembly,
|
||||
remoteServiceName: "BookStore"
|
||||
);
|
||||
````
|
||||
|
||||
`remoteServiceName`参数会匹配通过`RemoteServiceOptions`配置的服务端点.如果`BookStore`端点没有定义就会使用默认的`Default`端点.
|
||||
@ -0,0 +1,26 @@
|
||||
# 应用程序模块
|
||||
|
||||
ABP是一个 **模块化的应用程序框架** 由十多个 **nuget packages** 组成. 它提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块包含实体,服务,数据库集成,API,UI组件等.
|
||||
|
||||
**有两种类型的模块.** 它们没有任何结构上的差异,只是按照功能和目地分类:
|
||||
|
||||
* [**框架模块**](https://github.com/abpframework/abp/tree/master/framework/src): 这些是 **框架的核心模块**,像缓存,邮件,主题,安全性,序列化,验证,Ef Core集成,MongoDB集成...等等. 它们没有应用程序/业务功能,但通过提供通用基础架构,集成和抽象会使你的日常开发更加容易.
|
||||
* [**应用程序模块**](https://github.com/abpframework/abp/tree/master/modules): 这些模块是实现特定的应用程序/业务功能,像 博客, 文档管理, 身份管理, 租户管理... 等等. 它是通常有自己的实体,服务,API和UI组件.
|
||||
|
||||
## 开源的应用程序模块
|
||||
|
||||
有一些由ABP社区开发和维护的 **开源免费** 的应用程序模块:
|
||||
|
||||
* **Account**: 用于用户登陆/注册应用程序.
|
||||
* **Audit Logging**: 用于将审计日志持久化到数据库.
|
||||
* **Background Jobs**: 用于在使用默认后台作业管理器时保存后台作业.
|
||||
* **Blogging**: 用于创建精美的博客. ABP的[博客](https://abp.io/blog/abp/) 就使用了此模块.
|
||||
* [**Docs**](Docs.md): 用于创建技术文档页面. ABP的[文档](https://abp.io/documents/) 就使用了此模块.
|
||||
* **Identity**: 用于管理角色,用户和他们的权限.
|
||||
* **Identity Server**: 集成了IdentityServer4.
|
||||
* **Permission Management**: 用于保存权限.
|
||||
* **Setting Management**: 用于保存设置.
|
||||
* **Tenant Management**: 用于管理[多租户](../Multi-Tenancy.md)应用程序的租户.
|
||||
* **Users**: 用于抽象用户, 因此其他模块可以依赖此模块而不是Identity模块.
|
||||
|
||||
模块化文档正在编写中. 请参阅[这个仓库](https://github.com/abpframework/abp/tree/master/modules)获取所有模块的源代码.
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in new issue