Dapr 客户端 搭配 WebApiClientCore 玩耍服务调用
使用Dapr 客户端 处理服务调用,需要遵循的他的模式,通常代码是这个样子的:
var client = DaprClient.CreateInvokeHttpClient(appId: "routing");
var response = await client.GetAsJsonAsync($"/accounts/{17}", cancellationToken);
var account = await response.Content.ReadFromJsonAsync<Account>(cancellationToken: cancellationToken);
我更希望是这样子调用:
public interface IBank
{
[HttpGet(“/accounts/{accountId}”)]
Task<Account> GetUser(string accountId, CancellationToken cancellationToken = default);
[HttpPost(“/deposit”)]
Task<Account> Deposit([JsonContent] Transaction transaction, CancellationToken cancellationToken = default);
[HttpPost(“/withdraw”)]
[RawReturn(Enable =true, EnsureSuccessStatusCode = false)]
Task<HttpResponseMessage> Withdraw([JsonContent] Transaction transaction, CancellationToken cancellationToken = default);
}
var account = await bankClient.GetUser("17", cancellationToken);
我们可以用 Refit,RestEase 或者是 WebApiClientCore 来达到这样的效果, 那么在Dapr 里面使用这些库如何做到呢, 在Dapr的客户端库里面有一个Handler 的官方实现:InvocationHandler。 搭配这个InvocationHandler 就可以和这几个库,在本文中,我们重点介绍Dapr Client 如何搭配 WebApiClientCore。
public interface IBank
{
[HttpGet(“/accounts/{accountId}”)]
Task<Account> GetUser(string accountId, CancellationToken cancellationToken = default);
[HttpPost(“/deposit”)]
Task<Account> Deposit([JsonContent] Transaction transaction, CancellationToken cancellationToken = default);
[HttpPost(“/withdraw”)]
[RawReturn(Enable =true, EnsureSuccessStatusCode = false)]
Task<HttpResponseMessage> Withdraw([JsonContent] Transaction transaction, CancellationToken cancellationToken = default);
}
public class WebapiClientExample : Example
{
public override string DisplayName => “WebapiClient”;
private IBank bankClient;
public WebapiClientExample(IBank bank)
{
bankClient = bank;
}
public override async Task RunAsync(CancellationToken cancellationToken)
{
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
// Scenario 1: Check if the account already exists.
Account? account = null;
try
{
account = await bankClient.GetUser(“17”, cancellationToken);
}
catch (ApiException ex)
{
// Account does not exist.
}
Console.WriteLine($”Scenario 1: account ’17’ {(account is null ? “does not exist” : “already exists”)}”);
// Scenario 2: Deposit some money
var transaction = new Transaction()
{
Amount = 100m,
Id = “17”,
};
// read updated balance
account = await bankClient.Deposit(transaction, cancellationToken);
Console.WriteLine($”Scenario 2: account ’17’ has ‘{account?.Balance}’ money”);
// Scenario 3: Handle a validation error without exceptions
transaction = new Transaction()
{
Amount = 1_000_000m,
Id = “17”,
};
HttpResponseMessage response = null;
response = await bankClient.Withdraw(transaction, cancellationToken);
if (response.StatusCode != HttpStatusCode.BadRequest)
{
// We don’t actually expect this example to succeed – we expect a 400
Console.WriteLine(“Something went wrong :(“);
return;
}
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(cancellationToken: cancellationToken);
Console.WriteLine($”Scenario 3: got the following errors:”);
foreach (var kvp in problem!.Errors)
{
Console.WriteLine($”{kvp.Key}: {string.Join(“, “, kvp.Value)}”);
}
}
}
var services = new ServiceCollection();
services.AddTransient<Example, WebapiClientExample>();
services.AddLogging();
services
.AddScoped<InvocationHandler>()
.AddHttpApi<WebapiClientExample.IBank>(o => o.HttpHost = new Uri(“http://bank”))
.AddHttpMessageHandler<InvocationHandler>();
var serviceprovider = services.BuildServiceProvider();
代码的核心部分就在于上面红色的部分,我们把InvocationHandler 加入到AddHttpApi ,就可以和 dapr 一起玩耍了。