|
| 1 | +# 自动API控制器 |
| 2 | + |
| 3 | +创建[应用程序服务](Application-Services.md)后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做. |
| 4 | + |
| 5 | +ABP可以按照惯例 **自动** 将你的应用程序服务配置为API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义. |
| 6 | + |
| 7 | +## 配置 |
| 8 | + |
| 9 | +基本配置很简单. 只需配置`AbpAspNetCoreMvcOptions`并使用`ConventionalControllers.Create`方法,如下所示: |
| 10 | + |
| 11 | +````csharp |
| 12 | +[DependsOn(BookStoreApplicationModule)] |
| 13 | +public class BookStoreWebModule : AbpModule |
| 14 | +{ |
| 15 | + public override void ConfigureServices(ServiceConfigurationContext context) |
| 16 | + { |
| 17 | + Configure<AbpAspNetCoreMvcOptions>(options => |
| 18 | + { |
| 19 | + options |
| 20 | + .ConventionalControllers |
| 21 | + .Create(typeof(BookStoreApplicationModule).Assembly); |
| 22 | + }); |
| 23 | + } |
| 24 | +} |
| 25 | +```` |
| 26 | + |
| 27 | +此示例代码配置包含类`BookStoreApplicationModule`的程序集中的所有应用程序服务.下图显示了[Swagger UI](https://swagger.io/tools/swagger-ui/)上的API内容. |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | +### 例子 |
| 32 | + |
| 33 | +一些示例方法名称和按约定生成的相应路由: |
| 34 | + |
| 35 | +| 服务方法名称 | HTTP Method | 路由 | |
| 36 | +| ----------------------------------------------------- | ----------- | -------------------------- | |
| 37 | +| GetAsync(Guid id) | GET | /api/app/book/{id} | |
| 38 | +| GetListAsync() | GET | /api/app/book | |
| 39 | +| CreateAsync(CreateBookDto input) | POST | /api/app/book | |
| 40 | +| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} | |
| 41 | +| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} | |
| 42 | +| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors | |
| 43 | +| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor | |
| 44 | + |
| 45 | +### HTTP Method |
| 46 | + |
| 47 | +ABP在确定服务方法的HTTP Method时使用命名约定: |
| 48 | + |
| 49 | +- **Get**: 如果方法名称以`GetList`,`GetAll`或`Get`开头. |
| 50 | +- **Put**: 如果方法名称以`Put`或`Update`开头. |
| 51 | +- **Delete**: 如果方法名称以`Delete`或`Remove`开头. |
| 52 | +- **Post**: 如果方法名称以`Create`,`Add`,`Insert`或`Post`开头. |
| 53 | +- **Patch**: 如果方法名称以`Patch`开头. |
| 54 | +- 其他情况, **Post** 为 **默认方式**. |
| 55 | + |
| 56 | +如果需要为特定方法自定义HTTP Method, 则可以使用标准ASP.NET Core的属性([HttpPost], [HttpGet], [HttpPut]... 等等.). 这需要添加[Microsoft.AspNetCore.Mvc.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core)的Nuget包. |
| 57 | + |
| 58 | +### 路由 |
| 59 | + |
| 60 | +路由根据一些惯例生成: |
| 61 | + |
| 62 | +* 它始终以 **/api**开头. |
| 63 | +* 接着是**路由路径**. 默认值为"**/app**", 可以进行如下配置: |
| 64 | + |
| 65 | +````csharp |
| 66 | +Configure<AbpAspNetCoreMvcOptions>(options => |
| 67 | +{ |
| 68 | + options.ConventionalControllers |
| 69 | + .Create(typeof(BookStoreApplicationModule).Assembly, opts => |
| 70 | + { |
| 71 | + opts.RootPath = "volosoft/book-store"; |
| 72 | + }); |
| 73 | +}); |
| 74 | +```` |
| 75 | + |
| 76 | +然后获得一本书的路由将是'**/api/volosoft/book-store/book/{id}**'. 此示例使用两级根路径,但通常使用单个级别的深度. |
| 77 | + |
| 78 | +* 接着 **标准化控制器/服务名称**. 会删除`AppService`,`ApplicationService`和`Service`的后缀并将其转换为 **camelCase**. 如果你的应用程序服务类名称为`BookAppService`.那么它将变为`/book`. |
| 79 | + * 如果要自定义命名, 则设置`UrlControllerNameNormalizer`选项. 它是一个委托允许你自定义每个控制器/服务的名称. |
| 80 | +* 如果该方法具有 '**id**'参数, 则会在路由中添加'**/{id}**'. |
| 81 | +* 如有必要,它会添加操作名称. 操作名称从服务上的方法名称获取并标准化; |
| 82 | + * 删除'**Async**'后缀. 如果方法名称为'GetPhonesAsync',则变为`GetPhones`. |
| 83 | + * 删除**HTTP method前缀**. 基于的HTTP method删除`GetList`,`GetAll`,`Get`,`Put`,`Update`,`Delete`,`Remove`,`Create`,`Add`,`Insert`,`Post`和`Patch`前缀, 因此`GetPhones`变为`Phones`, 因为`Get`前缀和GET请求重复. |
| 84 | + * 将结果转换为**camelCase**. |
| 85 | + * 如果生成的操作名称为**空**,则它不会添加到路径中.否则它会被添加到路由中(例如'/phones').对于`GetAllAsync`方法名称,它将为空,因为`GetPhonesAsync`方法名称将为`phone`. |
| 86 | + * 可以通过设置`UrlActionNameNormalizer`选项来自定义.It's an action delegate that is called for every method. |
| 87 | +* 如果有另一个带有'Id'后缀的参数,那么它也会作为最终路线段添加到路线中(例如'/phoneId'). |
| 88 | + |
| 89 | +## 服务选择 |
| 90 | + |
| 91 | +创建的HTTP API控制器并不是应用服务所独有的功能. |
| 92 | + |
| 93 | +### IRemoteService 接口 |
| 94 | + |
| 95 | +如果一个类实现了`IRemoteService`接口, 那么它会被自动选择为API控制器. 由于应用程序服务本身实现了`IRemoteService`接口, 因此它自然就成为API控制器. |
| 96 | + |
| 97 | +### RemoteService Attribute |
| 98 | + |
| 99 | +`RemoteService`可用于将实现`IRemoteService`接口的类标记为远程服务或禁用它. 例如: |
| 100 | + |
| 101 | +````csharp |
| 102 | +[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)] |
| 103 | +public class PersonAppService : ApplicationService |
| 104 | +{ |
| 105 | + |
| 106 | +} |
| 107 | +```` |
| 108 | + |
| 109 | +### TypePredicate 选项 |
| 110 | + |
| 111 | +你可以通过提供`TypePedicate`选项进一步过滤类以成为API控制器: |
| 112 | + |
| 113 | +````csharp |
| 114 | +services.Configure<AbpAspNetCoreMvcOptions>(options => |
| 115 | +{ |
| 116 | + options.ConventionalControllers |
| 117 | + .Create(typeof(BookStoreApplicationModule).Assembly, opts => |
| 118 | + { |
| 119 | + opts.TypePredicate = type => { return true; }; |
| 120 | + }); |
| 121 | +}); |
| 122 | +```` |
| 123 | + |
| 124 | +如果你不想将此类型公开为API控制器, 则可以在类型检查时返回`false`. |
| 125 | + |
| 126 | +## API Explorer |
| 127 | + |
| 128 | +API Explorer是可以由客户端获取API结构的服务. Swagger使用它为endpoint创建文档和test UI. |
| 129 | + |
| 130 | +默认情况下, HTTP API控制器会自动启用API Explorer, 可以使用`RemoteService`按类或方法的级别控制它. 例如: |
| 131 | + |
| 132 | +````csharp |
| 133 | +[RemoteService(IsMetadataEnabled = false)] |
| 134 | +public class PersonAppService : ApplicationService |
| 135 | +{ |
| 136 | + |
| 137 | +} |
| 138 | +```` |
| 139 | + |
| 140 | +禁用`IsMetadataEnabled`从而从API Explorer中隐藏此服务, 并且无法被发现. 但是它仍然可以被知道确切API路径/路由的客户端使用. |
0 commit comments