• ABP.vNext系列之Dynamic C# API Client chef


    ABP.vNext 可以创建 C# API 客户端动态代理来调用远程 HTTP 服务 (REST API)。使用这种方式你无需处理 HttpClient 和其他细节即可调用远程服务并获取结果。

    ​ 在ABP.vNext中,Service/Controller 应该实现一个在服务器和客户端之间共享的接口。因此,首先在共享库项目中定义服务接口,如果使用启动模板创建了解决方案,通常在 Application.Contracts 项目中,如下定义:

    public interface IBookAppService : IApplicationService
    {
        Task<List<BookDto>> GetListAsync();
    }
    

    生成客户端代理

    ​ 首先,要生成Client Proxy,你需要先通过Install-Package Volo.Abp.Http.Client 命令引入Volo.Abp.Http.Client 包。

    ​ 其次需要为Module添加AbpHttpClientModule 依赖:

    [DependsOn(typeof(AbpHttpClientModule))] //add the dependency
    public class MyClientAppModule : AbpModule
    {
    }
    

    ​ 接着,使用AddHttpClientProxies 生成动态代理

    [DependsOn(
        typeof(AbpHttpClientModule), //used to create client proxies
        typeof(BookStoreApplicationContractsModule) //contains the application service interfaces
        )]
    public class MyClientAppModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //Create dynamic client proxies
            context.Services.AddHttpClientProxies(
                typeof(BookStoreApplicationContractsModule).Assembly
            );
        }
    }
    

    Endpoint 配置

    ​ 添加完Client Proxy后,程序如何知道所要请求的Url呢,ABP.vNext项目中,需要对Endpoint进行配置,在appsettings.json 文件中添加如下配置:

    {
      "RemoteServices": {
        "Default": {
          "BaseUrl": "http://localhost:53929/"
        } 
      } 
    }
    

    ​ 以上方式是最简单的配置方式,使用AbpRemoteServiceOptions 可以进行一些复杂的配置。AbpRemoteServiceOptions 默认从 appsettings.json 自动设置。当然,你可以在Module的 ConfigureServices 方法中对其进行设置。

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.Configure<AbpRemoteServiceOptions>(options =>
        {
            options.RemoteServices.Default =
                new RemoteServiceConfiguration("http://localhost:53929/");
        });
        
        //...
    }
    

    多个Endpoint配置

    ​ 如果项目需要调用多个不同的服务,可以在appsettings.json 中进行如下配置:

    {
      "RemoteServices": {
        "Default": {
          "BaseUrl": "http://localhost:53929/"
        },
        "BookStore": {
          "BaseUrl": "http://localhost:48392/"
        } 
      } 
    }
    

    AddHttpClientProxies 方法可以获取远程服务名称的附加参数。

    context.Services.AddHttpClientProxies(
        typeof(BookStoreApplicationContractsModule).Assembly,
        remoteServiceConfigurationName: "BookStore"
    );
    

    remoteServiceConfigurationName 参数匹配 AbpRemoteServiceOptions 配置的服务端点。如果未定义 BookStore 端点,则将回退到默认端点。

    如何使用Client Proxy

    ​ 最直接的使用方式,直接使用构造函数注入。在你的Client项目中,不应该直接引用ApplicationService的具体实现,而是只引用Contracts项目即可,下面的 IBookAppService 将发起Http请求调用。

    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 以使用客户端代理,但如果你的项目中有某个服务实现了该接口,注入时你想使用本地的实现,这时候可以将AddHttpClientProxies 中的属性AddHttpClientProxies 设置为 false 来禁用。

    ​ 但可能在某个时候又想调用远程的API时,可以通过注入 IHttpClientProxy 获得更明确的用法。在这种情况下,将使用 IHttpClientProxy 接口的 Service 属性。

    context.Services.AddHttpClientProxies(
        typeof(BookStoreApplicationContractsModule).Assembly,
        asDefaultServices: false
    );
    

    失败重试

    ​ 如果要为Client Proxy的远程 HTTP 调用添加失败重试逻辑,可以在Module类的 PreConfigureServices 方法中配置 AbpHttpClientBuilderOptions,如下配置使用 Polly 库在失败时重试 3 次。

    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        PreConfigure<AbpHttpClientBuilderOptions>(options =>
        {
            options.ProxyClientBuildActions.Add((remoteServiceName, clientBuilder) =>
            {
                clientBuilder.AddTransientHttpErrorPolicy(policyBuilder =>
                    policyBuilder.WaitAndRetryAsync(
                        3,
                        i => TimeSpan.FromSeconds(Math.Pow(2, i))
                    )
                );
            });
        });
    }
    
  • 相关阅读:
    C# 使用HttpWebRequest Post提交数据,携带Cookie和相关参数示例
    关于vue的页面跳转后,如何每次进入页面时都能获取后台数据
    关于vue的页面跳转后,如何每次进入页面时都能获取后台数据
    C#根据汉字获取编码和根据编码获取汉字
    C#根据汉字获取编码和根据编码获取汉字
    多线程系列教材 (一)- Java 创建一个线程的三种方式
    Lambda系列教材 (三)- java 集合的聚合操作
    Lambda系列教材 (二)- 方法引用
    Lambda系列教材 (一)- Java Lambda 表达式教程
    泛型系列教材 (四)- Java 中的子类泛型 转型 成父类泛型
  • 原文地址:https://www.cnblogs.com/jesen1315/p/16198343.html
Copyright © 2020-2023  润新知