目录:
面向.NET开发人员的Dapr——前言
面向.NET开发人员的Dapr——分布式世界
面向.NET开发人员的Dapr——俯瞰Dapr
面向.NET开发人员的Dapr——入门
面向.NET开发人员的Dapr——参考应用程序
The Dapr state management building block
Dapr 状态管理构建基块
Distributed applications are composed of independent services. While each service should be stateless, some services must track state to complete business operations. Consider a shopping basket service for an e-Commerce site. If the service can't track state, the customer could loose the shopping basket content by leaving the website, resulting in a lost sale and an unhappy customer experience. For these scenarios, state needs to be persisted to a distributed state store. The Dapr state management building block simplifies state tracking and offers advanced features across various data stores.
分布式应用程序由独立的服务组成。虽然每个服务都应该是无状态的,但某些服务必须跟踪状态才能完成业务操作。请考虑电子商务网站的购物篮服务。如果服务无法跟踪状态,则客户可能因离开网站而丢失购物篮内容,导致失销和客户不满。对于这些情况,需要将状态保存到分布式状态存储中。 Dapr 状态管理构建块简化了状态跟踪,并提供了跨各种数据存储的高级功能。
To try out the state management building block, have a look at the counter application sample in chapter 3.
若要试用状态管理构建块,请参阅 第3章中的计数器应用程序示例。
What it solves
解决方法
Tracking state in a distributed application can be challenging. For example:
The application may require different types of data stores.
Different consistency levels may be required for accessing and updating data.
Multiple users may update data at the same time, requiring conflict resolution.
Services must retry any short-lived transient errors that occur while interacting with the data store.
在分布式应用程序中跟踪状态具有挑战性。例如:
应用可能需要不同类型的数据存储。
访问和更新数据时可能需要不同的一致性级别。
多个用户可能同时更新数据,需要冲突解决。
在与数据存储交互时,服务必须重试发生的任何短暂的 暂时性错误 。
The Dapr state management building block addresses these challenges. It streamlines tracking state without dependencies or a learning curve on third-party storage SDKs.
Dapr 状态管理构建块解决了这些难题。它简化了跟踪状态,而无需依赖或学习第三方存储 Sdk 。
Important
重要
Dapr state management offers a key/value API. The feature doesn't support relational or graph data storage.
Dapr 状态管理提供 键/值 API。此功能不支持关系数据存储或图数据存储。
How it works
工作原理
The application interacts with a Dapr sidecar to store and retrieve key/value data. Under the hood, the sidecar API consumes a configurable state store component to persist data. Developers can choose from a growing collection of supported state stores that include Azure Cosmos DB, SQL Server, and Cassandra.
应用程序与 Dapr 边车(sidecar)交互,以存储和检索键/值数据。在后台,边车 API 使用可配置的状态存储组件来持久保存数据。开发人员可以从不断增长的 支持状态存储 集合中进行选择,其中包括 Azure Cosmos DB、SQL Server 和 Cassandra。
The API can be called with either HTTP or gRPC. Use the following URL to call the HTTP API:
可以通过 HTTP 或 gRPC 调用 API。使用以下 URL 调用 HTTP API:
http://localhost:<dapr-port>/v1.0/state/<store-name>/
<dapr-port>
:Dapr 侦听的 HTTP 端口。<store-name>
:要使用的状态存储组件的名称。
Figure 5-1 shows how a Dapr-enabled shopping basket service stores a key/value pair using the Dapr state store component named statestore
.
图5-1 显示了 借助Dapr 的购物篮服务如何使用名为statestore
的 Dapr 状态存储组件来存储键/值对 。
Figure 5-1. Storing a key/value pair in a Dapr state store.
图 5-1。在 Dapr 状态存储中存储键/值对。
Note the steps in the previous figure:
The basket service calls the state management API on the Dapr sidecar. The body of the request encloses a JSON array that can contain multiple key/value pairs.
The Dapr sidecar determines the state store based on the component configuration file. In this case, it's a Redis cache state store.
The sidecar persists the data to the Redis cache.
请注意上图中的步骤:
购物篮服务在 Dapr 边车上调用状态管理 API。请求正文包含一个可包含多个键/值对的 JSON 数组。
Dapr 边车基于组件配置文件确定状态存储。在这种情况下,它是一个 Redis 缓存状态存储。
边车将数据保存到 Redis 缓存。
Retrieving the stored data is a similar API call. In the example below, a curl command retrieves the data by calling the Dapr sidecar API:
检索存储的数据使用类似的 API 调用。在下面的示例中, curl命令通过调用 DAPR 边车 API 来检索数据:
curl http://localhost:3500/v1.0/state/statestore/basket1
The command returns the stored state in the response body:
此命令将在响应正文中返回已存储状态:
{
"items": [
{
"itemId": "DaprHoodie",
"quantity": 1
}
],
"customerId": 1
}
The following ps explain how to use the more advanced features of the state management building block.
以下各节介绍如何使用状态管理构建基块的更高级的功能。
Consistency
一致性
The CAP theorem is a set of principles that apply to distributed systems that store state. Figure 5-2 shows the three properties of the CAP theorem.
CAP 定理是一组适用于分布式系统存储状态的原则。图5-2 显示了 CAP 定理的三个特性。
Figure 5-2. The CAP theorem.
图 5-2。CAP 定理。
The theorem states that distributed data systems offer a trade-off between consistency, availability, and partition tolerance. And, that any datastore can only guarantee two of the three properties:
Consistency (C). Every node in the cluster responds with the most recent data, even if the system must block the request until all replicas update. If you query a "consistent system" for an item that is currently updating, you won't get a response until all replicas successfully update. However, you'll always receive the most current data.
Availability (A). Every node returns an immediate response, even if that response isn't the most recent data. If you query an "available system" for an item that is updating, you'll get the best possible answer the service can provide at that moment.
Partition Tolerance (P). Guarantees the system continues to operate even if a replicated data node fails or loses connectivity with other replicated data nodes.
定理指出,分布式数据系统提供一致性、可用性和分区容差之间的权衡。而且,任何数据存储只能 保证三个特性中的两个:
一致性 (C) 。群集中的每个节点都将使用最新的数据做出响应,在所有副本更新之前,系统都必须阻塞请求。如果在 "一致性系统"中查询正在更新的项,则在所有副本都成功更新之前,将不会收到响应。但是,您将始终接收最新的数据。
可用性 (A) 。每个节点都立即返回响应,即使返回的不是最新数据。如果您在 "可用系统" 中查询正在更新的项,则您将获得该服务在此时可以提供的值。
分区容差 (P) 。保证系统可持续运行,即使某个副本数据节点发生故障或失去与其他副本数据节点的连接。
Distributed applications must handle the P property. As services communicate among each other with network calls, network disruptions (P) will occur. With that in mind, distributed applications must either be AP or CP.
分布式应用程序必须满足 P 特性。随着服务彼此间的网络调用通信,会发生网络中断 (P) 。考虑到这一点,分布式应用程序必须在 AP 或 CP中二选一。
AP applications choose availability over consistency. Dapr supports this choice with its eventual consistency strategy. Consider an underlying data store, such as Azure CosmosDB, which stores redundant data on multiple replicas. With eventual consistency, the state store writes the update to one replica and completes the write request with the client. After this time, the store will asynchronously update its replicas. Read requests can return data from any of the replicas, including those replicas that haven't yet received the latest update.
AP 应用程序选择 "可用性高于一致性"。Dapr 通过其 最终一致性 策略支持此选择。请考虑使用底层数据存储(例如 Azure CosmosDB)将冗余数据存储在多个副本上。对于最终一致性,状态存储会将更新写入一个副本并完成与客户端的写入请求。此后,存储将以异步方式更新其它副本。读取请求可以返回任何副本的数据,包括尚未收到最新更新的副本。
CP applications choose consistency over availability. Dapr supports this choice with its strong consistency strategy. In this scenario, the state store will synchronously update all (or, in some cases, a quorum of) required replicas before completing the write request. Read operations will return the most up-to-date data consistently across replicas.
CP 应用程序选择“一致性高于可用性”。Dapr 通过其 强一致性 策略支持此选择。在此方案中,状态存储将在完成写请求之前,同步更新 所有 (或在某些情况下,为规定数量) 必需副本。读取操作将返回跨副本一致的最新数据。
The consistency level for a state operation is specified by attaching a consistency hint to the operation. The following curl command writes a Hello=World
key/value pair to a state store using a strong consistency hint:
通过将 一致性提示 附加到操作来指定状态操作的一致性级别。以下 curl 命令使用强一致性提示向状态存储写入一个键/值对 Hello=World
:
curl -X POST http://localhost:3500/v1.0/state/<store-name> \
-H "Content-Type: application/json" \
-d '[
{
"key": "Hello",
"value": "World",
"options": {
"consistency": "strong"
}
}
]'
Important
重要
It is up to the Dapr state store component to fulfill the consistency hint attached to the operation. Not all data stores support both consistency levels. If no consistency hint is set, the default behavior is eventual.
这取决于Dapr 状态存储组件是否满足附加在操作上的一致性提示。并非所有数据存储都支持这两种一致性级别。如果未设置任何一致性提示,则默认行为为最终一致性。
Concurrency
并发
In a multi-user application, there's a chance that multiple users will update the same data concurrently (at the same time). Dapr supports optimistic concurrency control (OCC) to manage conflicts. OCC is based on an assumption that update conflicts are uncommon because users work on different parts of the data. It's more efficient to assume an update will succeed and retry if it doesn't. The alternative, implementing pessimistic locking, can affect performance with long-running locking causing data contention.
在多用户应用程序中,有可能多个用户同时更新相同的数据。Dapr 支持乐观并发控制 (OCC) 来管理冲突。OCC 基于一个假设,因为用户处理数据的不同部分,所以更新冲突很少见。假设更新将成功,如果不成功,则重试,这样更高效。另一个选择是,实现悲观锁,长时间运行的锁定会导致数据争用,影响性能。
Dapr supports optimistic concurrency control (OCC) using ETags. An ETag is a value associated with a specific version of a stored key/value pair. Each time a key/value pair updates, the ETag value updates as well. When a client retrieves a key/value pair, the response includes the current ETag value. When a client updates or deletes a key/value pair, it must send that ETag value back in the request body. If another client has updated the data in the meantime, the ETags won't match and the request will fail. At this point, the client must retrieve the updated data, make the change again, and resubmit the update. This strategy is called first-write-wins.
Dapr 使用 Etag支持乐观并发控制。ETag 是与存储的键/值对的特定版本相关联的值。键/值对的每次更新时,ETag 值也会更新。当客户端检索键/值对时,返回的响应包括当前 ETag 值。当客户端更新或删除键/值对时,它必须在请求正文中发送该 ETag 值。如果在这期间其他客户端更新了数据,则 Etag 不会匹配,请求将失败。此时,客户端必须检索更新的数据,重新修改,然后重新提交更新。此策略称为 先写入胜出。
Dapr also supports a last-write-wins strategy. With this approach, the client doesn't attach an ETag to the write request. The state store component will always allow the update, even if the underlying value has changed during the session. Last-write-wins is useful for high-throughput write scenarios with low data contention. As well, overwriting an occasional user update can be tolerated.
Dapr 还支持后写入胜出策略。使用此方法时,客户端不会将 ETag 附加到写入请求。状态存储组件将始终允许更新,即使基础值在会话期间已更改也是如此。后写入胜出对于数据争用较少的高吞吐量写入方案非常有用。同样,偶尔覆盖用户更新是可以容忍的。
Transactions
事务
Dapr can write multi-item changes to a data store as a single operation implemented as a transaction. This functionality is only available for data stores that support ACID transactions. At the time of this writing, these stores include Redis, MongoDB, PostgreSQL, SQL Server, and Azure CosmosDB.
Dapr 可以将 多项更改 作为单项操作单个事务写入数据存储区。此功能仅适用于支持 ACID 事务的数据存储。撰写本文时,这些存储包括 Redis、MongoDB、PostgreSQL、SQL Server 和 Azure CosmosDB。
In the example below, a multi-item operation is sent to the state store in a single transaction. All operations must succeed for the transaction to commit. If one or more of the operations fail, the entire transaction rolls back.
在下面的示例中,多项操作将作为单个事务发送到状态存储。所有操作必须全部成功才能提交事务。如果一个或多个操作失败,则将回滚整个事务。
curl -X POST http://localhost:3500/v1.0/state/<store-name>/transaction \
-H "Content-Type: application/json" \
-d '{
"operations": [
{
"operation": "upsert",
"request": { "key": "Key1", "value": "Value1"
}
},
{
"operation": "delete",
"request": { "key": "Key2" }
}
]
}'
For data stores that don't support transactions, multiple keys can still be sent as a single request. The following example shows a bulk write operation:
对于不支持事务的数据存储,还可以将多个键作为单个请求发送。下面的示例演示了一个批量写入操作:
curl -X POST http://localhost:3500/v1.0/state/<store-name> \
-H "Content-Type: application/json" \
-d '[
{ "key": "Key1", "value": "Value1" },
{ "key": "Key2", "value": "Value2" }
]'
For bulk operations, Dapr will submit each key/value pair update as a separate request to the data store.
对于批量操作,Dapr 会将每个键/值对更新作为单独的请求提交到数据存储区。
Use the Dapr .NET SDK
使用 Dapr .NET SDK
The Dapr .NET SDK provides language-specific support for .NET Core platform. Developers can use the DaprClient
class introduced in chapter 3 to read and write data. The following example shows how to use the DaprClient.GetStateAsync<TValue>
method to read data from a state store. The method expects the store name, statestore
, and key, AMS
, as parameters:
Dapr .NET SDK 为 .NET Core 平台提供特定于语言的支持。开发人员可以使用第3章 中引入的类 DaprClient
来读取和写入数据。下面的示例演示如何使用 DaprClient.GetStateAsync<TValue>
方法从状态存储中读取数据。此方法要求使用存储名称(statestore
)和键( AMS
)作为参数:
var weatherForecast = await daprClient.GetStateAsync<WeatherForecast>("statestore", "AMS");
If the state store contains no data for key AMS
, the result will be default(WeatherForecast)
.
如果状态存储不包含键为AMS的任何数据 ,则结果将是 default(WeatherForecast)
。
To write data to the data store, use the DaprClient.SaveStateAsync<TValue>
method:
若要将数据写入数据存储,请使用 DaprClient.SaveStateAsync<TValue>
方法:
daprClient.SaveStateAsync("statestore", "AMS", weatherForecast);
The example uses the last-write-wins strategy as an ETag value isn't passed to the state store component. To use optimistic concurrency control (OCC) with a first-write-wins strategy, first retrieve the current ETag using the DaprClient.GetStateAndETagAsync
method. Then write the updated value and pass along the retrieved ETag using the DaprClient.TrySaveStateAsync
method.
该示例使用 后写入胜出 策略,因为 ETag 值不传递到状态存储组件。若要使用乐观并发控制 (使用 先写入胜出 策略) ,请首先使用方法DaprClient.GetStateAndETagAsync检索当前 ETag 。然后,使用方法DaprClient.TrySaveStateAsync 写入更新后的值并传递先前检索到的 ETag 。
var (weatherForecast, etag) = await daprClient.GetStateAndETagAsync<WeatherForecast>("statestore", city);
// ... make some changes to the retrieved weather forecast
var result = await daprClient.TrySaveStateAsync("statestore", city, weatherForecast, etag);
The DaprClient.TrySaveStateAsync
method fails when the data (and associated ETag) has been changed in the state store after the data was retrieved. The method returns a boolean value to indicate whether the call succeeded. A strategy to handle the failure is to simply reload the updated data from the state store, make the change again, and resubmit the update.
如果在检索数据后状态存储中更改了数据 (和关联的 ETag) ,则DaprClient.TrySaveStateAsync方法将失败。方法返回一个布尔值,指示调用是否成功。处理故障的策略是只需从状态存储重新加载已更新的数据,重新进行更改,然后重新提交更新。
If you always want a write to succeed regardless of other changes to the data, use the last-write-wins strategy.
如果你始终希望写入成功,而不考虑数据的其他更改,请使用 后写入胜出 策略。
The SDK provides other methods to retrieve data in bulk, delete data, and execute transactions. For more information, see the Dapr .NET SDK repository.
SDK 提供了用于批量检索数据、删除数据和执行事务的其他方法。有关详细信息,请参阅 Dapr .NET SDK 存储库。
ASP.NET Core integration
ASP.NET Core 集成
Dapr also supports ASP.NET Core, a cross-platform framework for building modern cloud-based web applications. The Dapr SDK integrates state management capabilities directly into the ASP.NET Core model binding capabilities. Configuration is simple. Add the IMVCBuilder.AddDapr
by appending the .AddDapr
extension method in your Startup.cs
class as shown in the next example:
Dapr 还支持 ASP.NET Core,这是一个跨平台框架,用于构建基于云的现代 web 应用程序。Dapr SDK 直接将状态管理功能集成到 ASP.NET Core 模型绑定。配置非常简单。 通过 在Startup类中追加扩展方法.AddDapr来添加,如下面的示例中所示:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddDapr();
}
Once configured, Dapr can inject a key/value pair directly into a controller action using the ASP.NET Core FromState
attribute. Referencing the DaprClient
object is no longer necessary. The next example shows a Web API that returns the weather forecast for a given city:
配置后,Dapr 可以使用 ASP.NET Core FromState 特性
将键/值对直接注入控制器操作。 不再需要引用对象DaprClient。下一个示例显示了一个 Web API,该 API 返回给定城市的天气预报:
[HttpGet("{city}")]
public ActionResult<WeatherForecast> Get([FromState("statestore", "city")] StateEntry<WeatherForecast> forecast)
{
if (forecast.Value == null)
{
return NotFound();
}
return forecast.Value;
}
In the example, the controller loads the weather forecast using the FromState
attribute. The first attribute parameter is the state store, statestore
. The second attribute parameter, city
, is the name of the route template variable to get the state key. If you omit the second parameter, the name of the bound method parameter (forecast
) is used to look up the route template variable.
在此示例中,控制器使用FromState特性加载天气预报 。第一个特性参数是状态存储(statestore)
。第二个特性参数 (city
)是用于获取状态键的 路由模板 变量的名称。如果省略第二个参数,则使用绑定方法参数的名称 (forecast
) 查找路由模板变量。
The StateEntry
class contains properties for all the information that is retrieved for a single key/value pair: StoreName
, Key
, Value
, and ETag
. The ETag is useful for implementing optimistic concurrency control (OCC) strategy. The class also provides methods to delete or update retrieved key/value data without requiring a DaprClient
instance. In the next example, the TrySaveAsync
method is used to update the retrieved weather forecast using OCC.
StateEntry
类包含被检索的单个键/值对所有信息的属性: StoreName
、 Key
、 Value
和 ETag
。ETag 有助于实现 (OCC) 策略的开放式并发控制。该类还提供了删除或更新检索到的键/值数据的方法,无需再使用 DaprClient
对象。在下一个示例中, TrySaveAsync
方法用于使用 OCC 更新检索到的天气预报。
[HttpPut("{city}")]
public async Task Put(WeatherForecast updatedForecast, [FromState("statestore", "city")] StateEntry<WeatherForecast> currentForecast)
{
// update cached current forecast with updated forecast passed into service endpoint
currentForecast.Value = updatedForecast;
// update state store
var success = await currentForecast.TrySaveAsync();
// ... check result
}
State store components
状态存储组件
At the time of this writing, Dapr provides support for the following transactional state stores:
在撰写本文时,Dapr 为以下事务状态存储提供支持:
Azure CosmosDB
Azure SQL Server
MongoDB
PostgreSQL
Redis
Dapr also includes support for state stores that support CRUD operations, but not transactional capabilities:
Dapr 还包括对支持 CRUD 操作的状态存储的支持,但不支持事务功能:
Aerospike
Azure Blob Storage
Azure Table Storage
Cassandra
Cloudstate
Couchbase
etcd
Google Cloud Firestore
Hashicorp Consul
Hazelcast
Memcached
Zookeeper
Configuration
配置
When initialized for local, self-hosted development, Dapr registers Redis as the default state store. Here's an example of the default state store configuration. Note the default name, statestore
:
在为本地自承载开发初始化时,Dapr 将 Redis 注册为默认的状态存储。下面是默认状态存储配置的示例。请注意默认名称 statestore
:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: actorStateStore
value: "true"
Note
备注
Many state stores can be registered to a single application each with a different name.
许多状态存储可以注册到单个应用程序,每个应用程序都有不同的名称。
The Redis state store requires redisHost
and redisPassword
metadata to connect to the Redis instance. In the example above, the Redis password (which is an empty string by default) is stored as a plain string. The best practice is to avoid clear-text strings and always use secret references. To learn more about secret management, see chapter 10.
Redis 状态存储需要 redisHost
和 redisPassword
元数据来连接到 Redis 实例。在上面的示例中,Redis 密码 (默认值为空字符串) 以纯字符串形式存储。最佳做法是避免使用明文并始终使用加密引用。若要了解有关机密管理的详细信息,请参阅第 10 章。
The other metadata field, actorStateStore
, indicates whether the state store can be consumed by the actors building block.
其他元数据字段指示参与者构建块
actorStateStore 是否可以使用状态存储区。
Key prefix strategies
key前缀策略
State store components enable different strategies to store key/value pairs in the underlying store. Recall the earlier example of a shopping basket service storing items a customer wishes to purchase:
状态存储组件允许以不同的策略在底层存储中存储键/值对。回忆早期的购物车服务示例,其中存放了客户希望购买的商品:
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[{
"key": "basket1",
"value": {
"customerId": 1,
"items": [
{ "itemId": "DaprHoodie", "quantity": 1 }
]
}
}]'
Using the Redis Console tool, look inside the Redis cache to see how the Redis state store component persisted the data:
使用 Redis 控制台工具,进入 Redis 缓存里查看 Redis 状态存储组件如何保存数据:
127.0.0.1:6379> KEYS *
1) "basketservice||basket1"
127.0.0.1:6379> HGETALL basketservice||basket1
1) "data"
2) "{\"items\":[{\"itemId\":\"DaprHoodie\",\"quantity\":1}],\"customerId\":1}"
3) "version"
4) "1"
The output shows the full Redis key for the data as basketservice||basket1
. By default, Dapr uses the application id
of the Dapr instance (basketservice
) as a prefix for the key. This naming convention enables multiple Dapr instances to share the same data store without key name collisions. For the developer, it's critical always to specify the same application id
when running the application with Dapr. If omitted, Dapr will generate a unique application ID. If the application id
changes, the application can no longer access the state stored with the previous key prefix.
输出显示数据的完整 Redis 键 basketservice||basket1
。默认情况下,Dapr 使用Dapr 实例的 application id
(basketservice)
作为key的前缀 。此命名惯例允许多个 Dapr 实例共享相同的数据存储,而不会发生键名称冲突。对于开发人员来说, 在运行使用 Dapr 的应用程序时,指定相同的application id
是至关重要的。如果省略,则 Dapr 将生成唯一的application ID。如果更改了 application id
,应用程序将无法再访问使用上一个key前缀存储的状态。
That said, it's possible to configure a constant value for the key prefix in the keyPrefix
metadata field in the state store component file. Consider the following example:
即便如此,可以在状态存储组件配置文件中的keyprefix元数据字段中为key配置前缀。请看下面的示例:
spec:
metadata:
- name: keyPrefix
- value: MyPrefix
A constant key prefix enables the state store to be accessed across multiple Dapr applications. What's more, setting the keyPrefix
to none
omits the prefix completely.
使用常量key前缀可以跨多个 Dapr 应用程序访问状态存储。更多操作,将 keyPrefix
设置为 none
完全省略前缀。
Reference application: eShopOnDapr
参考应用程序:eShopOnDapr
This book includes a reference application entitled eShopOnDapr
. It's modeled from an earlier Microsoft microservices reference application, eShopOnContainers
.
本书包括一个名为 eShopOnDapr
的参考应用程序。它从早期的 Microsoft 微服务参考应用程序 eShopOnContainers
进行建模。
The original eShopOnContainers architecture used an IBasketRepository
interface to read and write data for the basket service. The RedisBasketRepository
class provided the implementation using Redis as the underlying data store:
原始 eShopOnContainers 架构使用 IBasketRepository
接口来读取和写入购物车服务的数据。 RedisBasketRepository
类提供了使用 Redis 作为底层数据存储的实现:
public class RedisBasketRepository : IBasketRepository
{
private readonly ConnectionMultiplexer _redis;
private readonly IDatabase _database;
public RedisBasketRepository(ConnectionMultiplexer redis)
{
_redis = redis;
_database = redis.GetDatabase();
}
public async Task<CustomerBasket> GetBasketAsync(string customerId)
{
var data = await _database.StringGetAsync(customerId);
if (data.IsNullOrEmpty)
{
return null;
}
return JsonConvert.DeserializeObject<CustomerBasket>(data);
}
// ...
}
This code uses the third-party StackExchange.Redis
NuGet package. The following steps are required to load the shopping basket for a given customer:
此代码使用第三方 StackExchange.Redis
NuGet 包。若要为给定客户加载购物篮,需执行以下步骤:
Inject a
ConnectionMultiplexer
into the constructor. TheConnectionMultiplexer
is registered with the dependency injection framework in theStartup.cs
file: 将ConnectionMultiplexer
注入到构造函数中。 在Startup.cs
文件中使用依赖注入框架注入ConnectionMultiplexer
:services.AddSingleton<ConnectionMultiplexer>(sp => { var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value; var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true); configuration.ResolveDns = true; return ConnectionMultiplexer.Connect(configuration); });
Use the
ConnectionMultiplexer
to create anIDatabase
instance in each consuming class. 使用ConnectionMultiplexer 在
每个使用类中创建IDatabase
实例。Use the
IDatabase
instance to execute a Redis StringGet call using the givencustomerId
as the key. 使用给定的customerId
作为键,使用IDatabase
实例执行 Redis StringGet 调用 ,并传参customerId
。Check if data is loaded from Redis; if not, return
null
. 检查数据是否已从 Redis 加载;如果不是,则返回null
。Deserialize the data from Redis to a
CustomerBasket
object and return the result. 将 Redis 中的数据反序列化为CustomerBasket
对象并返回。
In the updated eShopOnDapr reference application, a new DaprBasketRepository
class replaces the RedisBasketRepository
class:
在更新后的 eShopOnDapr 参考应用程序中,使用新 DaprBasketRepository
类替换 RedisBasketRepository
类:
public class DaprBasketRepository : IBasketRepository
{
private const string StoreName = "eshop-basket-statestore";
private readonly DaprClient _daprClient;
public DaprBasketRepository(DaprClient daprClient)
{
_daprClient = daprClient ?? throw new ArgumentNullException(nameof(daprClient));;
}
public async Task<CustomerBasket> GetBasketAsync(string customerId)
{
return await _daprClient.GetStateAsync<CustomerBasket>(StoreName, customerId);
}
// ...
}
The updated code uses the Dapr .NET SDK to read and write data using the state management building block. The new steps to load the basket for a customer are dramatically simplified:
Inject a
DaprClient
into the constructor. TheDaprClient
is registered with the dependency injection framework in theStartup.cs
file.Use the
DaprClient.GetStateAsync
method to load the customer's shopping basket items from the configured state store and return the result.
更新的代码使用 Dapr .NET SDK,通过状态管理构建块读取和写入数据。为客户加载购物篮的新步骤大大简化:
将
DaprClient
注入到构造函数中。DaprClient
注册到文件中的依赖关系注入框架Startup.cs
。使用
DaprClient.GetStateAsync
方法从已配置的状态存储中加载客户的购物篮项,并返回结果。
The updated implementation still uses Redis as the underlying data store. But, Dapr abstracts the StackExchange.Redis
references and complexity from the application. A Dapr configuration file is all that's needed:
更新后的实现仍然使用 Redis 作为底层数据存储。但是,Dapr 从应用程序中抽离了 StackExchange.Redis
引用和复杂性。Dapr 配置文件是必需的:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: eshop-basket-statestore
namespace: eshop
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: redis:6379
- name: redisPassword
secretKeyRef:
name: redisPassword
auth:
secretStore: eshop-secretstore
The Dapr implementation also simplifies changing the underlying data store. For example, switching to Azure Table Storage requires only changing the contents of the configuration file. No code changes are necessary.
Dapr 实现还简化了底层数据存储的更改。例如,若要切换到 Azure 表存储,只需更改配置文件的内容。不需要更改代码。
Summary
摘要
The Dapr state management building block offers an API for storing key/value data across various data stores. The API provides support for:
Bulk operations
Strong and eventual consistency
Optimistic concurrency control
Multi-item transactions
Dapr 状态管理构建块提供了一个 API,用于在各种数据存储中存储键/值数据。API 为以下内容提供支持:
批量操作
强一致性和最终一致性
乐观并发控制
多项事务
The .NET SDK provides language-specific support for .NET Core and ASP.NET Core. Model binding integration simplifies accessing and updating state from ASP.NET Core controller action methods.
.NET SDK 为 .NET Core 和 ASP.NET Core 提供特定于语言的支持。模型绑定集成简化了访问和更新状态(通过在ASP.NET Core 控制器操作方法中使用FromState特性)。
In the eShopOnDapr reference application, the benefits to moving to Dapr state management are clear:
The new implementation uses fewer lines of code.
It abstracts away the complexity of the third-party
StackExchange.Redis
API.Replacing the underlying Redis cache with a different type of data store now only requires changes to the state store configuration file.
在 eShopOnDapr 参考应用程序中,转向 Dapr 状态管理的好处是显而易见的:
新实现使用更少的代码行。
它消除了第三方 API
StackExchange.Redis
的复杂性 。只需要更改状态存储配置文件就可以替换底层数据存储类型。