自动 API 控制器
一旦您创建了一个 应用服务 ,通常您会希望创建一个 API 控制器,将此服务作为 HTTP (REST) API 端点公开。典型的 API 控制器除了将方法调用重定向到应用服务并使用诸如 [HttpGet]、[HttpPost]、[Route] 等属性配置 REST API 之外,几乎不执行其他操作。
ABP 可以自动地按照约定将您的应用服务配置为 API 控制器。大多数情况下,您不需要关心其详细配置,但完全可以对其进行完全自定义。
配置
基本配置很简单。只需配置 AbpAspNetCoreMvcOptions 并使用 ConventionalControllers.Create 方法,如下所示:
[DependsOn(BookStoreApplicationModule)]
public class BookStoreWebModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
{
options
.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly);
});
}
}
此示例代码配置了包含 BookStoreApplicationModule 类的程序集中的所有应用服务。下图显示了在 Swagger UI 上生成的 API。
示例
一些示例方法名称以及按约定计算出的相应路由:
| 服务方法名称 | HTTP 方法 | 路由 |
|---|---|---|
| GetAsync(Guid id) | GET | /api/app/book/ |
| GetListAsync() | GET | /api/app/book |
| CreateAsync(CreateBookDto input) | POST | /api/app/book |
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/ |
| DeleteAsync(Guid id) | DELETE | /api/app/book/ |
| GetEditorsAsync(Guid id) | GET | /api/app/book//editors |
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book//editor |
HTTP 方法
ABP 在确定服务方法(操作)的 HTTP 方法时使用命名约定:
- Get: 如果方法名称以 'GetList'、'GetAll' 或 'Get' 开头,则使用。
- Put: 如果方法名称以 'Put' 或 'Update' 开头,则使用。
- Delete: 如果方法名称以 'Delete' 或 'Remove' 开头,则使用。
- Post: 如果方法名称以 'Create'、'Add'、'Insert' 或 'Post' 开头,则使用。
- Patch: 如果方法名称以 'Patch' 开头,则使用。
- 否则,默认使用 Post。
如果您需要为特定方法自定义 HTTP 方法,则可以使用标准的 ASP.NET Core 属性之一([HttpPost]、[HttpGet]、[HttpPut]... 等)。这需要将 Microsoft.AspNetCore.Mvc.Core nuget 包添加到包含该服务的项目中。
路由
路由基于一些约定计算得出:
- 它总是以 '/api' 开头。
- 然后是路由路径。默认值为 '/app',可以像下面这样配置:
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.RootPath = "volosoft/book-store";
});
});
那么获取书籍的路由将是 '/api/volosoft/book-store/book/'。此示例使用了两个层级的根路径,但您通常使用单层深度。
- 然后是规范化的控制器/服务名称。规范化会移除 'AppService'、'ApplicationService' 和 'Service' 后缀,并将其转换为短横线命名法 (kebab-case)。如果您的应用服务类名是 'ReadingBookAppService',那么它将变为 '/reading-book'。
- 如果您想自定义命名,请设置
UrlControllerNameNormalizer选项。它是一个 func 委托,允许您为每个控制器/服务确定名称。
- 如果您想自定义命名,请设置
- 如果方法有一个 'id' 参数,则将 '/' 添加到路由中。
- 然后,如果需要,它会添加操作名称。操作名称从服务上的方法名获取,并通过以下方式规范化:
- 移除 'Async' 后缀。如果方法名是 'GetPhonesAsync',则变为 'GetPhones'。
- 移除 HTTP 方法前缀。根据选定的 HTTP 方法,移除 'GetList'、'GetAll'、'Get'、'Put'、'Update'、'Delete'、'Remove'、'Create'、'Add'、'Insert'、'Post' 和 'Patch' 前缀。因此,'GetPhones' 对于 GET 请求来说,'Get' 前缀是重复的,所以变为 'Phones'。
- 将结果转换为短横线命名法 (kebab-case)。
- 如果生成的操作名称为空,则不添加到路由中。如果不为空,则添加到路由中(如 '/phones')。对于 'GetAllAsync' 方法名,它将为空;对于 'GetPhonesAsync' 方法名,它将为 'phones'。
- 可以通过设置
UrlActionNameNormalizer选项来自定义规范化。它是一个为每个方法调用的操作委托。
- 如果存在另一个带有 'Id' 后缀的参数,则它也会作为最终路由段添加到路由中(如 '/phoneId')。
自定义路由计算
IConventionalRouteBuilder 用于构建路由。默认由 ConventionalRouteBuilder 实现,并按上述方式工作。您可以替换/覆盖此服务以自定义路由计算策略。
版本 3.x 风格的路由计算
在版本 4.0 之前,路由计算是不同的。它使用的是驼峰命名法约定,而 ABP 版本 4.0+ 使用短横线命名法。如果您使用旧的路由计算策略,请遵循以下方法之一:
- 在
options.ConventionalControllers.Create(...)方法的选项中,将UseV3UrlStyle设置为true。示例:
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.UseV3UrlStyle = true;
});
此方法仅影响 BookStoreApplicationModule 的控制器。
- 将
AbpConventionalControllerOptions的UseV3UrlStyle设置为true,以全局设置它。示例:
Configure<AbpConventionalControllerOptions>(options =>
{
options.UseV3UrlStyle = true;
});
全局设置会影响模块化应用程序中的所有模块。
服务选择
创建约定式 HTTP API 控制器实际上并非应用服务独有的功能。
IRemoteService 接口
如果一个类实现了 IRemoteService 接口,那么它会被自动选为约定式 API 控制器。由于应用服务本质上实现了该接口,因此它们被视为天然的 API 控制器。
RemoteService 属性
RemoteService 属性可用于将类标记为远程服务,或者为固有实现了 IRemoteService 接口的特定类禁用远程服务。示例:
[RemoteService(IsEnabled = false)] //或直接写 [RemoteService(false)]
public class PersonAppService : ApplicationService
{
}
TypePredicate 选项
您可以通过提供 TypePredicate 选项进一步筛选要成为 API 控制器的类:
services.Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.TypePredicate = type => { return true; };
});
});
您不必为每个类型都返回 true,可以检查它,如果不想将此类型公开为 API 控制器,则返回 false。
API 探测
API 探测是一项服务,使客户端能够探查 API 结构。Swagger 使用它来创建端点的文档和测试 UI。
默认情况下,约定式 HTTP API 控制器会自动启用 API 探测。使用 RemoteService 属性在类或方法级别控制它。示例:
[RemoteService(IsMetadataEnabled = false)]
public class PersonAppService : ApplicationService
{
}
禁用了 IsMetadataEnabled,这将从 API 探测中隐藏此服务,使其不可被发现。但是,了解确切 API 路径/路由的客户端仍然可以使用它。
替换或移除控制器
除了 覆盖控制器 外,您还可以使用一个完全独立的控制器来替换框架或模块中的控制器。
它们具有相同的 路由 ,但可以具有不同的输入和输出参数。
替换内置的 AbpApplicationConfigurationController
ReplaceControllersAttribute 指示要替换的控制器类型。
[ReplaceControllers(typeof(AbpApplicationConfigurationController))]
[Area("abp")]
[RemoteService(Name = "abp")]
public class ReplaceBuiltInController : AbpController
{
[HttpGet("api/abp/application-configuration")]
public virtual Task<MyApplicationConfigurationDto> GetAsync(MyApplicationConfigurationRequestOptions options)
{
return Task.FromResult(new MyApplicationConfigurationDto());
}
}
public class MyApplicationConfigurationRequestOptions : ApplicationConfigurationRequestOptions
{
}
public class MyApplicationConfigurationDto : ApplicationConfigurationDto
{
}
移除控制器
配置 AbpAspNetCoreMvcOptions 的 ControllersToRemove 以移除控制器。
services.Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ControllersToRemove.Add(typeof(AbpLanguagesController));
});
抠丁客



