DaprClient 使用

使用 DaprClient 的基本提示和建议

生命周期管理

一个 DaprClient 以TCP套接字的形式持有访问网络资源的权限,用于与Dapr sidecar进行通信。 DaprClient 实现了 IDisposable,以支持对资源的迫切清理。

为了获得最佳性能,请创建 DaprClient 的单一长期实例,并在整个应用程序中提供对该共享实例的访问。 DaprClient实例是线程安全的,旨在共享。

避免为每个操作创建 DaprClient 并在操作完成后释放它。

配置 DaprClient

一个 DaprClient 可以在调用 .Build() 创建客户端之前,通过调用 DaprClientBuilder 类的方法来进行配置。 每个 DaprClient 对象的设置都是独立的,并且在调用 .Build() 后无法更改。

var daprClient = new DaprClientBuilder()
    .UseJsonSerializerSettings( ... ) // Configure JSON serializer
    .Build();

DaprClientBuilder 包含以下各项的设置:

  • Dapr sidecar 的 HTTP 端点
  • Dapr sidecar 的 gRPC 端点
  • 用于配置 JSON 序列化的 JsonSerializerOptions 对象
  • 用于配置 gRPC 的 GrpcChannelOptions 对象
  • 用于验证请求到 sidecar 的 API 令牌

SDK 将读取以下环境变量来配置默认值:

  • DAPR_HTTP_ENDPOINT: 用于查找 Dapr sidecar 的 HTTP 端点,示例:https://dapr-api.mycompany.com
  • DAPR_GRPC_ENDPOINT: 用于查找Dapr sidecar的gRPC端点,示例:https://dapr-grpc-api.mycompany.com
  • DAPR_HTTP_PORT:如果未设置DAPR_HTTP_ENDPOINT,则用于查找Dapr sidecar的本地HTTP端点
  • DAPR_GRPC_PORT: 如果未设置DAPR_GRPC_ENDPOINT,则用于查找Dapr sidecar的gRPC本地端点
  • DAPR_API_TOKEN: 用于设置 API 令牌

配置 gRPC 通道选项

Dapr使用CancellationToken进行取消,这依赖于gRPC通道选项的配置。 如果您需要自行配置这些选项,请确保启用ThrowOperationCanceledOnCancellation setting

var daprClient = new DaprClientBuilder()
    .UseGrpcChannelOptions(new GrpcChannelOptions { ... ThrowOperationCanceledOnCancellation = true })
    .Build();

使用 DaprClient 取消

在 DaprClient 上执行异步操作的 API 接受一个可选的 CancellationToken 参数。 这遵循了可取消操作的标准 .NET 习惯用法。 请注意,当取消发生时,并不能保证远程端点停止处理请求,只能保证客户端已经停止等待完成。

当操作被取消时,它将抛出一个 OperationCancelledException

了解 DaprClient JSON 序列化

许多方法在 DaprClient 上使用 System.Text.Json 序列化器执行JSON序列化。 接受应用程序数据类型作为参数的方法将对其进行 JSON 序列化,除非文档另有明确说明。

如果您有高级需求,阅读System.Text.Json文档是值得的。 Dapr .NET SDK 没有提供独特的序列化行为或自定义 - 它依赖于底层的序列化器将数据转换为应用程序的 .NET 类型。

DaprClient 配置为使用从 JsonSerializerDefaults.Web 配置的序列化器选项对象。 这意味着 DaprClient 将使用 camelCase 来命名属性,允许读取引号 ("10.99"),并将不区分大小写地绑定属性。 这些设置与ASP.NET Core和System.Text.Json.Http API所使用的设置相同,并被设计为遵循可互操作的Web惯例。

截至.NET 5.0,System.Text.Json 并没有很好地支持所有内置的 F# 语言功能。 如果你使用的是 F#,你可能会想要使用一个添加了 F# 功能支持的转换器包,如 FSharp.SystemTextJson

JSON 序列化的简单指南

如果您使用映射到 JSON 类型系统的特性集,您使用 JSON 序列化和 DaprClient 的体验将会很顺利。 这些都是一般准则,在可以应用的地方会简化你的代码。

  • 避免继承和多态性
  • 不要试图用循环引用来序列化数据。
  • 不要将复杂或昂贵的逻辑放在构造函数或属性访问器中
  • 使用 .NET 类型,干净利落地映射到 JSON 类型(数字类型,字符串,DateTime
  • 为顶层消息、事件或状态值创建自己的类,以便您可以在未来添加属性
  • 使用get/set属性设计类型,或者使用支持的模式来创建具有JSON的不可变类型

多态性和序列化

DaprClient 使用的 System.Text.Json 序列化器在执行序列化时使用声明的值类型。

本节将在示例中使用 DaprClient.SaveStateAsync<TValue>(...) ,但该建议适用于 SDK 暴露的任何 Dapr 构建块。

public class Widget
{
    public string Color { get; set; }
}
...

// Storing a Widget value as JSON in the state store
widget widget = new Widget() { Color = "Green", };
await client.SaveStateAsync("mystatestore", "mykey", widget);

在上面的例子中,类型参数 TValue 的类型参数是从 widget 变量的类型推断出来的。 这一点很重要,因为 System.Text.Json 序列化器将根据 declared type 的值来执行序列化。 结果是,JSON值 { "color": "Green" } 将被存储。

考虑一下当你试图使用 Widget 的派生类型时会发生什么:

public class Widget
{
    public string Color { get; set; }
}

public class SuperWidget : Widget
{
    public bool HasSelfCleaningFeature { get; set; }
}
...

// Storing a SuperWidget value as JSON in the state store
Widget widget = new SuperWidget() { Color = "Green", HasSelfCleaningFeature = true, };
await client.SaveStateAsync("mystatestore", "mykey", widget);

在这个示例中,我们使用了一个SuperWidget,但变量的声明类型是Widget。 由于 JSON 序列化器的行为是由声明的类型决定的,所以它只看到一个简单的 Widget,并将保存值 { "color": "Green" },而不是 { "color": "Green", "hasSelfCleaningFeature": true }

如果你想让 SuperWidget 的属性被序列化,那么最好的选择是用 object 覆盖类型参数。 这将导致序列器包含所有数据,因为它对类型一无所知。

Widget widget = new SuperWidget() { Color = "Green", HasSelfCleaningFeature = true, };
await client.SaveStateAsync<object>("mystatestore", "mykey", widget);

错误处理

当遇到失败时,DaprClient 上的方法会抛出 DaprException 或其子类。

try
{
    var widget = new Widget() { Color = "Green", };
    await client.SaveStateAsync("mystatestore", "mykey", widget);
}
catch (DaprException ex)
{
    // handle the exception, log, retry, etc.
}

最常见的故障案例将与以下情况有关:

  • Dapr 组件配置不正确
  • 暂时性故障,如网络问题
  • 无效数据,如未能反序列化 JSON

在任何这些情况下,您可以通过.InnerException属性检查更多的异常细节。