RPC 远程调用
目前并不推荐大家使用 grpc 作为远程调用的框架首选。因为,很多的中间件目前还不支持 grpc 协议。可能会造成和中间件集成问题。
目前,微软官方推荐大家使用 IHttpClientFactory 来发送 http 请求。并在官方文档提到了开源组件 Refit。
Refit 是在 IHttpClientFactory 的基础上进行了包装。把远程的 Http 调用抽象成 c# 中的接口,并通过依赖注入到运行环境进行调用。
备注
使用细节,请参见 Refit 在 github 的使用说明。
另外, IHttpClientFactory 官方集成了 Polly 。可以对调用失败的请求执行重试、熔断等操作。详细也请参考 Polly 自身的文档。
集成及使用
添加项目引用
dotnet add package Refit.HttpClientFactory dotnet add package Refit.Newtonsoft.Json dotnet add package Microsoft.Extensions.Http.Polly
定义调用的下游系统接口
这里我们以调用飞书发送消息为例。
public interface IFeiShuApi { /// <summary> /// 获取token /// </summary> [Post("/open-apis/auth/v3/tenant_access_token/internal")] Task<ApiResponse<LoginModel>> GetToken([Body(buffered: true)] TokenInput input); /// <summary> /// 发送消息 /// </summary> [Post("/open-apis/im/v1/messages")] Task<ApiResponse<BasicResponse<SendMessageResponse>>> SendMessage(string receive_id_type, [Body(buffered: true)] FeiShuSendMessageInput input, [Authorize("Bearer")] string token); }
Startup.cs中添加依赖注入public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddRefitClient<IFeiShuApi>(new RefitSettings()) .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://open.feishu.cn")) // .AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600))) // 增加 Polly 的失败策略。 ; } }
在 Services 中调用远程 api
public class FeiShuMessageService : IFeiShuMessageService { // 注入 IFeiShuApi private readonly IFeiShuApi _feiShuApi; public FeiShuMessageService(IFeiShuApi feiShuApi) { _feiShuApi = feiShuApi; } public async Task SendMessage(FeiShuSendingMsgBody msgBody, FeiShuSendMessageInput input) { var tokenRes = await _feiShuApi.GetToken(new TokenInput()); var res = await _feiShuApi.SendMessage("user_id", input, tokenRes.Content.tenant_access_token); if(res.IsSuccessStatusCode) { _logger.LogInformation(); } else { _logger.LogError(res.Error, res.Error.Content); } } }
错误处理
方法定义的返回值是:
Task<IApiResponse>,Task<IApiResponse<T>>,Task<ApiResponse<T>>则调用请求会被组件捕获。程序仅需要判断 response 响应状态var response = await _myRefitClient.GetSomeStuff(); if(response.IsSuccessStatusCode) { //do your thing } else { _logger.LogError(response.Error, response.Error.Content); }
方法定义的返回值是:
Task<T>则调用异常需要自己处理try { var result = await awesomeApi.GetFooAsync("bar"); } catch (ApiException exception) { //exception handling }