动态 C# API 客户端

ABP可以自动创建C# API 客户端代理来调用远程HTTP服务(REST APIS).通过这种方式,你不需要通过 HttpClient 或者其他低级的HTTP功能调用远程服务并获取数据.

服务接口

你的service或controller需要实现一个在服务端和客户端共享的接口.因此,首先需要在一个共享的类库项目中定义一个服务接口.例如:

  1. public interface IBookAppService : IApplicationService
  2. {
  3. Task<List<BookDto>> GetListAsync();
  4. }

为了能自动被发现,你的接口需要实现IRemoteService接口.由于IApplicationService继承自IRemoteService接口.所以IBookAppService完全满足这个条件.

在你的服务中实现这个类,你可以使用auto API controller system将你的服务暴漏为一个REST API 端点.

客户端代理生成

首先,将Volo.Abp.Http.Client nuget包添加到你的客户端项目中:

  1. Install-Package Volo.Abp.Http.Client

然后给你的模块添加AbpHttpClientModule依赖:

  1. [DependsOn(typeof(AbpHttpClientModule))] //添加依赖
  2. public class MyClientAppModule : AbpModule
  3. {
  4. }

现在,已经可以创建客户端代理了.例如:

  1. [DependsOn(
  2. typeof(AbpHttpClientModule), //用来创建客户端代理
  3. typeof(BookStoreApplicationContractsModule) //包含应用服务接口
  4. )]
  5. public class MyClientAppModule : AbpModule
  6. {
  7. public override void ConfigureServices(ServiceConfigurationContext context)
  8. {
  9. //创建动态客户端代理
  10. context.Services.AddHttpClientProxies(
  11. typeof(BookStoreApplicationContractsModule).Assembly
  12. );
  13. }
  14. }

AddHttpClientproxies方法获得一个程序集,找到这个程序集中所有的服务接口,创建并注册代理类.

Endpoint配置

appsettings.json文件中的RemoteServices节点被用来设置默认的服务地址.下面是最简单的配置:

  1. {
  2. "RemoteServices": {
  3. "Default": {
  4. "BaseUrl": "http://localhost:53929/"
  5. }
  6. }
  7. }

查看下面的”AbpRemoteServiceOptions”章节获取更多详细配置.

使用

可以很直接地使用.只需要在你的客户端程序中注入服务接口:

  1. public class MyService : ITransientDependency
  2. {
  3. private readonly IBookAppService _bookService;
  4. public MyService(IBookAppService bookService)
  5. {
  6. _bookService = bookService;
  7. }
  8. public async Task DoIt()
  9. {
  10. var books = await _bookService.GetListAsync();
  11. foreach (var book in books)
  12. {
  13. Console.WriteLine($"[BOOK {book.Id}] Name={book.Name}");
  14. }
  15. }
  16. }

本例注入了上面定义的IBookAppService服务接口.当客户端调用服务方法的时候动态客户端代理就会创建一个HTTP调用.

IHttpClientProxy接口

你可以像上面那样注入IBookAppService来使用客户端代理,也可以注入IHttpClientProxy<IBookAppService>获取更多明确的用法.这种情况下你可以使用IHttpClientProxy<T>接口的Service属性.

配置

AbpRemoteServiceOptions

默认情况下AbpRemoteServiceOptionsappsettings.json获取.或者,你可以使用Configure方法来设置或重写它.如:

  1. public override void ConfigureServices(ServiceConfigurationContext context)
  2. {
  3. context.Services.Configure<AbpRemoteServiceOptions>(options =>
  4. {
  5. options.RemoteServices.Default =
  6. new RemoteServiceConfiguration("http://localhost:53929/");
  7. });
  8. //...
  9. }

多个远程服务端点

上面的例子已经配置了”Default”远程服务端点.你可能需要为不同的服务创建不同的端点.(就像在微服务方法中一样,每个微服务具有不同的端点).在这种情况下,你可以在你的配置文件中添加其他的端点:

  1. {
  2. "RemoteServices": {
  3. "Default": {
  4. "BaseUrl": "http://localhost:53929/"
  5. },
  6. "BookStore": {
  7. "BaseUrl": "http://localhost:48392/"
  8. }
  9. }
  10. }

AddHttpClientProxies方法有一个可选的参数来定义远程服务的名字:

  1. context.Services.AddHttpClientProxies(
  2. typeof(BookStoreApplicationContractsModule).Assembly,
  3. remoteServiceConfigurationName: "BookStore"
  4. );

remoteServiceConfigurationName参数会匹配通过AbpRemoteServiceOptions配置的服务端点.如果BookStore端点没有定义就会使用默认的Default端点.

作为默认服务

当你为IBookAppService创建了一个服务代理,你可以直接注入IBookAppService来使用代理客户端(像上面章节中将的那样).你可以传递asDefaultService:falseAddHttpClientProxies方法来禁用此功能.

  1. context.Services.AddHttpClientProxies(
  2. typeof(BookStoreApplicationContractsModule).Assembly,
  3. asDefaultServices: false
  4. );

如果你的程序中已经有一个服务的实现并且你不想用你的客户端代理重写或替换其他的实现,就需要使用asDefaultServices:false

如果你禁用了asDefaultService,你只能使用IHttpClientProxy<T>接口去使用客户端代理.(参见上面的相关章节).